diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index c53f607..a799a2a 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -515,6 +515,13 @@ + + + + + + @@ -806,6 +813,7 @@ + diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 4c421aa..9f849ae 100644 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -5,6 +5,7 @@ + diff --git a/data/.flutter-plugins b/data/.flutter-plugins index bc41b14..76e5888 100644 --- a/data/.flutter-plugins +++ b/data/.flutter-plugins @@ -3,3 +3,4 @@ google_sign_in=/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in-6.2 google_sign_in_android=/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.21/ google_sign_in_ios=/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/ google_sign_in_web=/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+2/ +photo_manager=/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.0.0-dev.5/ diff --git a/data/.flutter-plugins-dependencies b/data/.flutter-plugins-dependencies index 1de2c2d..64bf33c 100644 --- a/data/.flutter-plugins-dependencies +++ b/data/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"android":[{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.21/","native_build":true,"dependencies":[]}],"macos":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+2/","dependencies":[]}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]}],"date_created":"2024-01-23 10:35:50.290203","version":"3.16.7"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.0.0-dev.5/","native_build":true,"dependencies":[]}],"android":[{"name":"google_sign_in_android","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_android-6.1.21/","native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.0.0-dev.5/","native_build":true,"dependencies":[]}],"macos":[{"name":"google_sign_in_ios","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_ios-5.7.3/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"photo_manager","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/photo_manager-3.0.0-dev.5/","native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"google_sign_in_web","path":"/Users/pratikcanopas/.pub-cache/hosted/pub.dev/google_sign_in_web-0.12.3+2/","dependencies":[]}]},"dependencyGraph":[{"name":"google_sign_in","dependencies":["google_sign_in_android","google_sign_in_ios","google_sign_in_web"]},{"name":"google_sign_in_android","dependencies":[]},{"name":"google_sign_in_ios","dependencies":[]},{"name":"google_sign_in_web","dependencies":[]},{"name":"photo_manager","dependencies":[]}],"date_created":"2024-01-24 18:58:15.075183","version":"3.16.7"} \ No newline at end of file diff --git a/data/lib/models/media/media.dart b/data/lib/models/media/media.dart index 1d2ae4e..e20e4bc 100644 --- a/data/lib/models/media/media.dart +++ b/data/lib/models/media/media.dart @@ -1,19 +1,31 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'media.freezed.dart'; + part 'media.g.dart'; +enum AppMediaType { image, video } + +enum AppMediaOrientation { landscape, portrait } + @freezed -class Media with _$Media { - const factory Media({ +class AppMedia with _$AppMedia { + const factory AppMedia({ required String id, - required String name, - required String image, - required double size, + String? name, + required String path, + double? displayHeight, + double? displayWidth, + required AppMediaType type, String? mimeType, required DateTime createdTime, DateTime? modifiedTime, - }) = _Media; + AppMediaOrientation? orientation, + required double? latitude, + required double? longitude, + @Default(false) bool isLocal, + }) = _AppMedia; - factory Media.fromJson(Map json) => _$MediaFromJson(json); + factory AppMedia.fromJson(Map json) => + _$AppMediaFromJson(json); } diff --git a/data/lib/models/media/media.freezed.dart b/data/lib/models/media/media.freezed.dart index b91321b..d143f82 100644 --- a/data/lib/models/media/media.freezed.dart +++ b/data/lib/models/media/media.freezed.dart @@ -14,44 +14,57 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); -Media _$MediaFromJson(Map json) { - return _Media.fromJson(json); +AppMedia _$AppMediaFromJson(Map json) { + return _AppMedia.fromJson(json); } /// @nodoc -mixin _$Media { +mixin _$AppMedia { String get id => throw _privateConstructorUsedError; - String get name => throw _privateConstructorUsedError; - String get image => throw _privateConstructorUsedError; - double get size => throw _privateConstructorUsedError; + String? get name => throw _privateConstructorUsedError; + String get path => throw _privateConstructorUsedError; + double? get displayHeight => throw _privateConstructorUsedError; + double? get displayWidth => throw _privateConstructorUsedError; + AppMediaType get type => throw _privateConstructorUsedError; String? get mimeType => throw _privateConstructorUsedError; DateTime get createdTime => throw _privateConstructorUsedError; DateTime? get modifiedTime => throw _privateConstructorUsedError; + AppMediaOrientation? get orientation => throw _privateConstructorUsedError; + double? get latitude => throw _privateConstructorUsedError; + double? get longitude => throw _privateConstructorUsedError; + bool get isLocal => throw _privateConstructorUsedError; Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) - $MediaCopyWith get copyWith => throw _privateConstructorUsedError; + $AppMediaCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class $MediaCopyWith<$Res> { - factory $MediaCopyWith(Media value, $Res Function(Media) then) = - _$MediaCopyWithImpl<$Res, Media>; +abstract class $AppMediaCopyWith<$Res> { + factory $AppMediaCopyWith(AppMedia value, $Res Function(AppMedia) then) = + _$AppMediaCopyWithImpl<$Res, AppMedia>; @useResult $Res call( {String id, - String name, - String image, - double size, + String? name, + String path, + double? displayHeight, + double? displayWidth, + AppMediaType type, String? mimeType, DateTime createdTime, - DateTime? modifiedTime}); + DateTime? modifiedTime, + AppMediaOrientation? orientation, + double? latitude, + double? longitude, + bool isLocal}); } /// @nodoc -class _$MediaCopyWithImpl<$Res, $Val extends Media> - implements $MediaCopyWith<$Res> { - _$MediaCopyWithImpl(this._value, this._then); +class _$AppMediaCopyWithImpl<$Res, $Val extends AppMedia> + implements $AppMediaCopyWith<$Res> { + _$AppMediaCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; @@ -62,30 +75,44 @@ class _$MediaCopyWithImpl<$Res, $Val extends Media> @override $Res call({ Object? id = null, - Object? name = null, - Object? image = null, - Object? size = null, + Object? name = freezed, + Object? path = null, + Object? displayHeight = freezed, + Object? displayWidth = freezed, + Object? type = null, Object? mimeType = freezed, Object? createdTime = null, Object? modifiedTime = freezed, + Object? orientation = freezed, + Object? latitude = freezed, + Object? longitude = freezed, + Object? isLocal = null, }) { return _then(_value.copyWith( id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as String, - name: null == name + name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable + as String?, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - size: null == size - ? _value.size - : size // ignore: cast_nullable_to_non_nullable - as double, + displayHeight: freezed == displayHeight + ? _value.displayHeight + : displayHeight // ignore: cast_nullable_to_non_nullable + as double?, + displayWidth: freezed == displayWidth + ? _value.displayWidth + : displayWidth // ignore: cast_nullable_to_non_nullable + as double?, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as AppMediaType, mimeType: freezed == mimeType ? _value.mimeType : mimeType // ignore: cast_nullable_to_non_nullable @@ -98,63 +125,100 @@ class _$MediaCopyWithImpl<$Res, $Val extends Media> ? _value.modifiedTime : modifiedTime // ignore: cast_nullable_to_non_nullable as DateTime?, + orientation: freezed == orientation + ? _value.orientation + : orientation // ignore: cast_nullable_to_non_nullable + as AppMediaOrientation?, + latitude: freezed == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double?, + longitude: freezed == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double?, + isLocal: null == isLocal + ? _value.isLocal + : isLocal // ignore: cast_nullable_to_non_nullable + as bool, ) as $Val); } } /// @nodoc -abstract class _$$MediaImplCopyWith<$Res> implements $MediaCopyWith<$Res> { - factory _$$MediaImplCopyWith( - _$MediaImpl value, $Res Function(_$MediaImpl) then) = - __$$MediaImplCopyWithImpl<$Res>; +abstract class _$$AppMediaImplCopyWith<$Res> + implements $AppMediaCopyWith<$Res> { + factory _$$AppMediaImplCopyWith( + _$AppMediaImpl value, $Res Function(_$AppMediaImpl) then) = + __$$AppMediaImplCopyWithImpl<$Res>; @override @useResult $Res call( {String id, - String name, - String image, - double size, + String? name, + String path, + double? displayHeight, + double? displayWidth, + AppMediaType type, String? mimeType, DateTime createdTime, - DateTime? modifiedTime}); + DateTime? modifiedTime, + AppMediaOrientation? orientation, + double? latitude, + double? longitude, + bool isLocal}); } /// @nodoc -class __$$MediaImplCopyWithImpl<$Res> - extends _$MediaCopyWithImpl<$Res, _$MediaImpl> - implements _$$MediaImplCopyWith<$Res> { - __$$MediaImplCopyWithImpl( - _$MediaImpl _value, $Res Function(_$MediaImpl) _then) +class __$$AppMediaImplCopyWithImpl<$Res> + extends _$AppMediaCopyWithImpl<$Res, _$AppMediaImpl> + implements _$$AppMediaImplCopyWith<$Res> { + __$$AppMediaImplCopyWithImpl( + _$AppMediaImpl _value, $Res Function(_$AppMediaImpl) _then) : super(_value, _then); @pragma('vm:prefer-inline') @override $Res call({ Object? id = null, - Object? name = null, - Object? image = null, - Object? size = null, + Object? name = freezed, + Object? path = null, + Object? displayHeight = freezed, + Object? displayWidth = freezed, + Object? type = null, Object? mimeType = freezed, Object? createdTime = null, Object? modifiedTime = freezed, + Object? orientation = freezed, + Object? latitude = freezed, + Object? longitude = freezed, + Object? isLocal = null, }) { - return _then(_$MediaImpl( + return _then(_$AppMediaImpl( id: null == id ? _value.id : id // ignore: cast_nullable_to_non_nullable as String, - name: null == name + name: freezed == name ? _value.name : name // ignore: cast_nullable_to_non_nullable + as String?, + path: null == path + ? _value.path + : path // ignore: cast_nullable_to_non_nullable as String, - image: null == image - ? _value.image - : image // ignore: cast_nullable_to_non_nullable - as String, - size: null == size - ? _value.size - : size // ignore: cast_nullable_to_non_nullable - as double, + displayHeight: freezed == displayHeight + ? _value.displayHeight + : displayHeight // ignore: cast_nullable_to_non_nullable + as double?, + displayWidth: freezed == displayWidth + ? _value.displayWidth + : displayWidth // ignore: cast_nullable_to_non_nullable + as double?, + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as AppMediaType, mimeType: freezed == mimeType ? _value.mimeType : mimeType // ignore: cast_nullable_to_non_nullable @@ -167,101 +231,171 @@ class __$$MediaImplCopyWithImpl<$Res> ? _value.modifiedTime : modifiedTime // ignore: cast_nullable_to_non_nullable as DateTime?, + orientation: freezed == orientation + ? _value.orientation + : orientation // ignore: cast_nullable_to_non_nullable + as AppMediaOrientation?, + latitude: freezed == latitude + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double?, + longitude: freezed == longitude + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double?, + isLocal: null == isLocal + ? _value.isLocal + : isLocal // ignore: cast_nullable_to_non_nullable + as bool, )); } } /// @nodoc @JsonSerializable() -class _$MediaImpl implements _Media { - const _$MediaImpl( +class _$AppMediaImpl implements _AppMedia { + const _$AppMediaImpl( {required this.id, - required this.name, - required this.image, - required this.size, + this.name, + required this.path, + this.displayHeight, + this.displayWidth, + required this.type, this.mimeType, required this.createdTime, - this.modifiedTime}); + this.modifiedTime, + this.orientation, + required this.latitude, + required this.longitude, + this.isLocal = false}); - factory _$MediaImpl.fromJson(Map json) => - _$$MediaImplFromJson(json); + factory _$AppMediaImpl.fromJson(Map json) => + _$$AppMediaImplFromJson(json); @override final String id; @override - final String name; + final String? name; @override - final String image; + final String path; @override - final double size; + final double? displayHeight; + @override + final double? displayWidth; + @override + final AppMediaType type; @override final String? mimeType; @override final DateTime createdTime; @override final DateTime? modifiedTime; + @override + final AppMediaOrientation? orientation; + @override + final double? latitude; + @override + final double? longitude; + @override + @JsonKey() + final bool isLocal; @override String toString() { - return 'Media(id: $id, name: $name, image: $image, size: $size, mimeType: $mimeType, createdTime: $createdTime, modifiedTime: $modifiedTime)'; + return 'AppMedia(id: $id, name: $name, path: $path, displayHeight: $displayHeight, displayWidth: $displayWidth, type: $type, mimeType: $mimeType, createdTime: $createdTime, modifiedTime: $modifiedTime, orientation: $orientation, latitude: $latitude, longitude: $longitude, isLocal: $isLocal)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$MediaImpl && + other is _$AppMediaImpl && (identical(other.id, id) || other.id == id) && (identical(other.name, name) || other.name == name) && - (identical(other.image, image) || other.image == image) && - (identical(other.size, size) || other.size == size) && + (identical(other.path, path) || other.path == path) && + (identical(other.displayHeight, displayHeight) || + other.displayHeight == displayHeight) && + (identical(other.displayWidth, displayWidth) || + other.displayWidth == displayWidth) && + (identical(other.type, type) || other.type == type) && (identical(other.mimeType, mimeType) || other.mimeType == mimeType) && (identical(other.createdTime, createdTime) || other.createdTime == createdTime) && (identical(other.modifiedTime, modifiedTime) || - other.modifiedTime == modifiedTime)); + other.modifiedTime == modifiedTime) && + (identical(other.orientation, orientation) || + other.orientation == orientation) && + (identical(other.latitude, latitude) || + other.latitude == latitude) && + (identical(other.longitude, longitude) || + other.longitude == longitude) && + (identical(other.isLocal, isLocal) || other.isLocal == isLocal)); } @JsonKey(ignore: true) @override int get hashCode => Object.hash( - runtimeType, id, name, image, size, mimeType, createdTime, modifiedTime); + runtimeType, + id, + name, + path, + displayHeight, + displayWidth, + type, + mimeType, + createdTime, + modifiedTime, + orientation, + latitude, + longitude, + isLocal); @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') - _$$MediaImplCopyWith<_$MediaImpl> get copyWith => - __$$MediaImplCopyWithImpl<_$MediaImpl>(this, _$identity); + _$$AppMediaImplCopyWith<_$AppMediaImpl> get copyWith => + __$$AppMediaImplCopyWithImpl<_$AppMediaImpl>(this, _$identity); @override Map toJson() { - return _$$MediaImplToJson( + return _$$AppMediaImplToJson( this, ); } } -abstract class _Media implements Media { - const factory _Media( +abstract class _AppMedia implements AppMedia { + const factory _AppMedia( {required final String id, - required final String name, - required final String image, - required final double size, + final String? name, + required final String path, + final double? displayHeight, + final double? displayWidth, + required final AppMediaType type, final String? mimeType, required final DateTime createdTime, - final DateTime? modifiedTime}) = _$MediaImpl; + final DateTime? modifiedTime, + final AppMediaOrientation? orientation, + required final double? latitude, + required final double? longitude, + final bool isLocal}) = _$AppMediaImpl; - factory _Media.fromJson(Map json) = _$MediaImpl.fromJson; + factory _AppMedia.fromJson(Map json) = + _$AppMediaImpl.fromJson; @override String get id; @override - String get name; + String? get name; + @override + String get path; + @override + double? get displayHeight; @override - String get image; + double? get displayWidth; @override - double get size; + AppMediaType get type; @override String? get mimeType; @override @@ -269,7 +403,15 @@ abstract class _Media implements Media { @override DateTime? get modifiedTime; @override + AppMediaOrientation? get orientation; + @override + double? get latitude; + @override + double? get longitude; + @override + bool get isLocal; + @override @JsonKey(ignore: true) - _$$MediaImplCopyWith<_$MediaImpl> get copyWith => + _$$AppMediaImplCopyWith<_$AppMediaImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/data/lib/models/media/media.g.dart b/data/lib/models/media/media.g.dart index a83033e..8d07a5b 100644 --- a/data/lib/models/media/media.g.dart +++ b/data/lib/models/media/media.g.dart @@ -6,25 +6,49 @@ part of 'media.dart'; // JsonSerializableGenerator // ************************************************************************** -_$MediaImpl _$$MediaImplFromJson(Map json) => _$MediaImpl( +_$AppMediaImpl _$$AppMediaImplFromJson(Map json) => + _$AppMediaImpl( id: json['id'] as String, - name: json['name'] as String, - image: json['image'] as String, - size: (json['size'] as num).toDouble(), + name: json['name'] as String?, + path: json['path'] as String, + displayHeight: (json['displayHeight'] as num?)?.toDouble(), + displayWidth: (json['displayWidth'] as num?)?.toDouble(), + type: $enumDecode(_$AppMediaTypeEnumMap, json['type']), mimeType: json['mimeType'] as String?, createdTime: DateTime.parse(json['createdTime'] as String), modifiedTime: json['modifiedTime'] == null ? null : DateTime.parse(json['modifiedTime'] as String), + orientation: $enumDecodeNullable( + _$AppMediaOrientationEnumMap, json['orientation']), + latitude: (json['latitude'] as num?)?.toDouble(), + longitude: (json['longitude'] as num?)?.toDouble(), + isLocal: json['isLocal'] as bool? ?? false, ); -Map _$$MediaImplToJson(_$MediaImpl instance) => +Map _$$AppMediaImplToJson(_$AppMediaImpl instance) => { 'id': instance.id, 'name': instance.name, - 'image': instance.image, - 'size': instance.size, + 'path': instance.path, + 'displayHeight': instance.displayHeight, + 'displayWidth': instance.displayWidth, + 'type': _$AppMediaTypeEnumMap[instance.type]!, 'mimeType': instance.mimeType, 'createdTime': instance.createdTime.toIso8601String(), 'modifiedTime': instance.modifiedTime?.toIso8601String(), + 'orientation': _$AppMediaOrientationEnumMap[instance.orientation], + 'latitude': instance.latitude, + 'longitude': instance.longitude, + 'isLocal': instance.isLocal, }; + +const _$AppMediaTypeEnumMap = { + AppMediaType.image: 'image', + AppMediaType.video: 'video', +}; + +const _$AppMediaOrientationEnumMap = { + AppMediaOrientation.landscape: 'landscape', + AppMediaOrientation.portrait: 'portrait', +}; diff --git a/data/lib/services/local_media_service.dart b/data/lib/services/local_media_service.dart new file mode 100644 index 0000000..4e5de12 --- /dev/null +++ b/data/lib/services/local_media_service.dart @@ -0,0 +1,43 @@ +import 'package:data/models/media/media.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:photo_manager/photo_manager.dart'; + +final localMediaServiceProvider = Provider( + (ref) => const LocalMediaService(), +); + +class LocalMediaService { + const LocalMediaService(); + + Future> getAssets() async { + await PhotoManager.requestPermissionExtend(); + final imageCount = await PhotoManager.getAssetCount(); + if(imageCount == 0) return []; + final assets = await PhotoManager.getAssetListRange(start: 0, end: imageCount); + + List medias = []; + + for (final asset in assets) { + final file = await asset.file; + if (file == null) continue; + final media = AppMedia( + id: asset.id, + name: asset.title, + path: file.path, + displayHeight: asset.height.toDouble(), + displayWidth: asset.width.toDouble(), + type: AppMediaType.image, + mimeType: asset.type.toString(), + createdTime: asset.createDateTime, + modifiedTime: asset.modifiedDateTime, + orientation: asset.orientation == 90 || asset.orientation == 270 + ? AppMediaOrientation.landscape + : AppMediaOrientation.portrait, + latitude: asset.latitude, + longitude: asset.longitude, + ); + medias.add(media); + } + return medias; + } +} diff --git a/data/pubspec.yaml b/data/pubspec.yaml index 6cf3bcd..8b04b70 100644 --- a/data/pubspec.yaml +++ b/data/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: # services googleapis: ^12.0.0 + photo_manager: ^3.0.0-dev.5 # authentication google_sign_in: ^6.2.1 @@ -20,7 +21,7 @@ dependencies: # state management flutter_riverpod: ^2.4.9 - # ode generation + # code generation freezed: ^2.4.6 freezed_annotation: ^2.4.1 json_serializable: ^6.7.1