diff --git a/.gitignore b/.gitignore index 79c113f..3e463e2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ migrate_working_dir/ *.iml *.ipr *.iws +*.lock .idea/ # The .vscode folder contains launch configuration and tasks you configure in diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 96504e7..3a49a4e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ @@ -44,6 +45,12 @@ + + + + + + + diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..ac3b479 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index a0fa520..43394ed 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -18,8 +18,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false - id("org.jetbrains.kotlin.android") version "1.9.25" apply false + id("com.android.application") version "8.9.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false } include(":app") diff --git a/assets/icons/rasad_ban.svg b/assets/icons/rasad_ban.svg new file mode 100644 index 0000000..fd781ec --- /dev/null +++ b/assets/icons/rasad_ban.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/rasad_bar.svg b/assets/icons/rasad_bar.svg new file mode 100644 index 0000000..bc0a060 --- /dev/null +++ b/assets/icons/rasad_bar.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icons/rasad_bot.svg b/assets/icons/rasad_bot.svg new file mode 100644 index 0000000..19f27a2 --- /dev/null +++ b/assets/icons/rasad_bot.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/icons/rasad_dam.svg b/assets/icons/rasad_dam.svg new file mode 100644 index 0000000..cf84209 --- /dev/null +++ b/assets/icons/rasad_dam.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/rasad_nan.svg b/assets/icons/rasad_nan.svg new file mode 100644 index 0000000..6fd8c7f --- /dev/null +++ b/assets/icons/rasad_nan.svg @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/rasad_toyor.svg b/assets/icons/rasad_toyor.svg new file mode 100644 index 0000000..d98e848 --- /dev/null +++ b/assets/icons/rasad_toyor.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/vec/rasad_ban.svg.vec b/assets/vec/rasad_ban.svg.vec new file mode 100644 index 0000000..53a4631 Binary files /dev/null and b/assets/vec/rasad_ban.svg.vec differ diff --git a/assets/vec/rasad_bar.svg.vec b/assets/vec/rasad_bar.svg.vec new file mode 100644 index 0000000..fea5942 Binary files /dev/null and b/assets/vec/rasad_bar.svg.vec differ diff --git a/assets/vec/rasad_bot.svg.vec b/assets/vec/rasad_bot.svg.vec new file mode 100644 index 0000000..87222b8 Binary files /dev/null and b/assets/vec/rasad_bot.svg.vec differ diff --git a/assets/vec/rasad_dam.svg.vec b/assets/vec/rasad_dam.svg.vec new file mode 100644 index 0000000..d298a1c Binary files /dev/null and b/assets/vec/rasad_dam.svg.vec differ diff --git a/assets/vec/rasad_nan.svg.vec b/assets/vec/rasad_nan.svg.vec new file mode 100644 index 0000000..0452acf Binary files /dev/null and b/assets/vec/rasad_nan.svg.vec differ diff --git a/assets/vec/rasad_toyor.svg.vec b/assets/vec/rasad_toyor.svg.vec new file mode 100644 index 0000000..9bf1f96 Binary files /dev/null and b/assets/vec/rasad_toyor.svg.vec differ diff --git a/lib/data/model/response/slider/slider_model.dart b/lib/data/model/response/slider/slider_model.dart new file mode 100644 index 0000000..da64c8c --- /dev/null +++ b/lib/data/model/response/slider/slider_model.dart @@ -0,0 +1,11 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'slider_model.freezed.dart'; +part 'slider_model.g.dart'; + +@freezed +abstract class SliderModel with _$SliderModel { + const factory SliderModel({List? up, List? down, String? middle}) = _SliderModel; + + factory SliderModel.fromJson(Map json) => _$SliderModelFromJson(json); +} diff --git a/lib/data/model/response/slider/slider_model.freezed.dart b/lib/data/model/response/slider/slider_model.freezed.dart new file mode 100644 index 0000000..225749e --- /dev/null +++ b/lib/data/model/response/slider/slider_model.freezed.dart @@ -0,0 +1,299 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'slider_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$SliderModel { + + List? get up; List? get down; String? get middle; +/// Create a copy of SliderModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$SliderModelCopyWith get copyWith => _$SliderModelCopyWithImpl(this as SliderModel, _$identity); + + /// Serializes this SliderModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is SliderModel&&const DeepCollectionEquality().equals(other.up, up)&&const DeepCollectionEquality().equals(other.down, down)&&(identical(other.middle, middle) || other.middle == middle)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(up),const DeepCollectionEquality().hash(down),middle); + +@override +String toString() { + return 'SliderModel(up: $up, down: $down, middle: $middle)'; +} + + +} + +/// @nodoc +abstract mixin class $SliderModelCopyWith<$Res> { + factory $SliderModelCopyWith(SliderModel value, $Res Function(SliderModel) _then) = _$SliderModelCopyWithImpl; +@useResult +$Res call({ + List? up, List? down, String? middle +}); + + + + +} +/// @nodoc +class _$SliderModelCopyWithImpl<$Res> + implements $SliderModelCopyWith<$Res> { + _$SliderModelCopyWithImpl(this._self, this._then); + + final SliderModel _self; + final $Res Function(SliderModel) _then; + +/// Create a copy of SliderModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? up = freezed,Object? down = freezed,Object? middle = freezed,}) { + return _then(_self.copyWith( +up: freezed == up ? _self.up : up // ignore: cast_nullable_to_non_nullable +as List?,down: freezed == down ? _self.down : down // ignore: cast_nullable_to_non_nullable +as List?,middle: freezed == middle ? _self.middle : middle // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [SliderModel]. +extension SliderModelPatterns on SliderModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _SliderModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _SliderModel value) $default,){ +final _that = this; +switch (_that) { +case _SliderModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _SliderModel value)? $default,){ +final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( List? up, List? down, String? middle)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that.up,_that.down,_that.middle);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( List? up, List? down, String? middle) $default,) {final _that = this; +switch (_that) { +case _SliderModel(): +return $default(_that.up,_that.down,_that.middle);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List? up, List? down, String? middle)? $default,) {final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that.up,_that.down,_that.middle);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SliderModel implements SliderModel { + const _SliderModel({final List? up, final List? down, this.middle}): _up = up,_down = down; + factory _SliderModel.fromJson(Map json) => _$SliderModelFromJson(json); + + final List? _up; +@override List? get up { + final value = _up; + if (value == null) return null; + if (_up is EqualUnmodifiableListView) return _up; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + final List? _down; +@override List? get down { + final value = _down; + if (value == null) return null; + if (_down is EqualUnmodifiableListView) return _down; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + +@override final String? middle; + +/// Create a copy of SliderModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$SliderModelCopyWith<_SliderModel> get copyWith => __$SliderModelCopyWithImpl<_SliderModel>(this, _$identity); + +@override +Map toJson() { + return _$SliderModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _SliderModel&&const DeepCollectionEquality().equals(other._up, _up)&&const DeepCollectionEquality().equals(other._down, _down)&&(identical(other.middle, middle) || other.middle == middle)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_up),const DeepCollectionEquality().hash(_down),middle); + +@override +String toString() { + return 'SliderModel(up: $up, down: $down, middle: $middle)'; +} + + +} + +/// @nodoc +abstract mixin class _$SliderModelCopyWith<$Res> implements $SliderModelCopyWith<$Res> { + factory _$SliderModelCopyWith(_SliderModel value, $Res Function(_SliderModel) _then) = __$SliderModelCopyWithImpl; +@override @useResult +$Res call({ + List? up, List? down, String? middle +}); + + + + +} +/// @nodoc +class __$SliderModelCopyWithImpl<$Res> + implements _$SliderModelCopyWith<$Res> { + __$SliderModelCopyWithImpl(this._self, this._then); + + final _SliderModel _self; + final $Res Function(_SliderModel) _then; + +/// Create a copy of SliderModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? up = freezed,Object? down = freezed,Object? middle = freezed,}) { + return _then(_SliderModel( +up: freezed == up ? _self._up : up // ignore: cast_nullable_to_non_nullable +as List?,down: freezed == down ? _self._down : down // ignore: cast_nullable_to_non_nullable +as List?,middle: freezed == middle ? _self.middle : middle // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/lib/data/model/response/slider/slider_model.g.dart b/lib/data/model/response/slider/slider_model.g.dart new file mode 100644 index 0000000..3fb67f0 --- /dev/null +++ b/lib/data/model/response/slider/slider_model.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'slider_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_SliderModel _$SliderModelFromJson(Map json) => _SliderModel( + up: (json['up'] as List?)?.map((e) => e as String).toList(), + down: (json['down'] as List?)?.map((e) => e as String).toList(), + middle: json['middle'] as String?, +); + +Map _$SliderModelToJson(_SliderModel instance) => + { + 'up': instance.up, + 'down': instance.down, + 'middle': instance.middle, + }; diff --git a/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 6438add..83851bd 100644 --- a/lib/infrastructure/service/app_navigation_observer.dart +++ b/lib/infrastructure/service/app_navigation_observer.dart @@ -4,6 +4,8 @@ import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_inspection/injection/inspection_di.dart'; import 'package:rasadyar_inspection/inspection.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class CustomNavigationObserver extends NavigatorObserver { bool _isWorkDone = false; @@ -14,9 +16,8 @@ class CustomNavigationObserver extends NavigatorObserver { @override void didPush(Route route, Route? previousRoute) async { - super.didPush(route, previousRoute); final routeName = route.settings.name; - if (!_isWorkDone &&( routeName == ChickenRoutes.init || routeName == ChickenRoutes.auth)) { + /* if (!_isWorkDone && (routeName == ChickenRoutes.init || routeName == ChickenRoutes.auth)) { _isWorkDone = true; await setupChickenDI(); } else if (!_isWorkDone && @@ -24,8 +25,12 @@ class CustomNavigationObserver extends NavigatorObserver { _isWorkDone = true; await setupInspectionDI(); - } - tLog('CustomNavigationObserver: didPush - $routeName'); + } else if (!_isWorkDone && + (routeName == LiveStockRoutes.init || routeName == LiveStockRoutes.auth)) { + + }*/ + super.didPush(route, previousRoute); + // tLog('CustomNavigationObserver: didPush - $routeName'); } @override @@ -37,12 +42,12 @@ class CustomNavigationObserver extends NavigatorObserver { @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); - tLog('CustomNavigationObserver: didPop - ${route.settings.name}'); + // tLog('CustomNavigationObserver: didPop - ${route.settings.name}'); } @override void didRemove(Route route, Route? previousRoute) { super.didRemove(route, previousRoute); - tLog('CustomNavigationObserver: didRemove - ${route.settings.name}'); + // tLog('CustomNavigationObserver: didRemove - ${route.settings.name}'); } } diff --git a/lib/infrastructure/service/token_storage_service.dart b/lib/infrastructure/service/token_storage_service.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/main.dart b/lib/main.dart index 09db360..7b63ac2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,7 +8,7 @@ import 'presentation/routes/auth_route_resolver_impl.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - + await Hive.initFlutter(); await setupPreInjection(); Get.put(TokenStorageService()); await Get.find().init(); diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index e73eefe..85685ad 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -1,28 +1,132 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_app/data/model/response/slider/slider_model.dart'; +import 'package:rasadyar_app/presentation/routes/app_pages.dart'; import 'package:rasadyar_core/core.dart'; class ModulesLogic extends GetxController { TokenStorageService tokenService = Get.find(); + SliderLogic upSlider = Get.find(tag: "up"); + SliderLogic downSlider = Get.find(tag: "down"); + RxnString latestNews = RxnString(); + RxBool isLoading = false.obs; List moduleList = [ - ModuleModel(title: 'بازرسی', icon: Assets.icons.inspection.path, module: Module.inspection), -// ModuleModel(title: 'دام', icon: Assets.icons.liveStock.path, module: Module.liveStocks), - ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken), + ModuleModel( + title: 'رصدطیور', + icon: Assets.icons.rasadToyor.path, + module: Module.chicken, + borderColor: Color(0xFF4665AF), + backgroundColor: Color(0xFFECEEF2), + titleColor: Color(0xFF4665AF), + ), + ModuleModel( + title: 'رصدام', + icon: Assets.icons.rasadDam.path, + module: Module.liveStocks, + borderColor: Color(0xFFD7A972), + backgroundColor: Color(0xFFF4F1EF), + titleColor: Color(0xFF7F7F7F), + ), + ModuleModel( + title: 'رصدبان', + icon: Assets.icons.rasadBan.path, + module: Module.inspection, + borderColor: Color(0xFF014856), + backgroundColor: Color(0xFFE9EDED), + titleColor: Color(0xFF014856), + ), + ModuleModel( + title: 'رصدبار', + icon: Assets.icons.rasadBar.path, + borderColor: Color(0xFFF37021), + backgroundColor: Color(0xFFFFECE1), + titleColor: Color(0xFFF37021), + ), + ModuleModel( + title: 'رصدبات', + icon: Assets.icons.rasadBot.path, + borderColor: Color(0xFF4A148C), + backgroundColor: Color(0xFFEDEAF0), + titleColor: Color(0xFF4A148C), + ), + ModuleModel( + title: 'رصدنان', + icon: Assets.icons.rasadNan.path, + borderColor: Color(0xFFD7A972), + backgroundColor: Color(0xFFF4F2EA), + titleColor: Color(0xFF8E8E8E), + ), ]; RxnInt selectedIndex = RxnInt(null); @override - void onReady() { - super.onReady(); - } - - @override - void onClose() { - super.onClose(); + void onInit() { + super.onInit(); + getSliders(); } void saveModule(Module module) { tokenService.saveModule(module); tokenService.appModule.value = module; } + + void onTapCard(Module? module, int index) async { + if (module == null) { + if (Get.isSnackbarOpen) return; + Get.snackbar( + "در حال توسعه", + "این ماژول به زودی اضافه می‌شود", + snackPosition: SnackPosition.BOTTOM, + backgroundColor: AppColor.yellowDark, + ); + } else { + _goToModule(module, index); + } + } + + void _goToModule(Module module, int index) async { + selectedIndex.value = index; + await Future.delayed(Duration(milliseconds: 300)); + selectedIndex.value = null; + saveModule(module); + await navigateToModule(module); + } + + Future navigateToModule(Module module) async { + var target = getAuthTargetPage(module).entries.first; + + if (target.value?[0] != null) { + isLoading.value = !isLoading.value; + await target.value?[0]; + isLoading.value = !isLoading.value; + } + + await Get.toNamed(target.key, arguments: module); + + if (target.value?[1] != null) { + await target.value?[1]; + } + } + + Future getSliders() async { + var dio = Dio(); + dio.interceptors.add( + PrettyDioLogger( + request: true, + enabled: true, + requestHeader: true, + responseHeader: true, + requestBody: true, + responseBody: true, + ), + ); + var res = await dio.get("https://miran.storage.c2.liara.space/app/urllapp.json"); + if (res.statusCode == 200) { + SliderModel sliderModel = SliderModel.fromJson(res.data); + upSlider.onSuccess(sliderModel.up ?? []); + downSlider.onSuccess(sliderModel.down ?? []); + latestNews.value = sliderModel.middle; + } + } } diff --git a/lib/presentation/pages/modules/view.dart b/lib/presentation/pages/modules/view.dart index 880050a..830bd57 100644 --- a/lib/presentation/pages/modules/view.dart +++ b/lib/presentation/pages/modules/view.dart @@ -1,7 +1,6 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:rasadyar_chicken/chicken.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_inspection/inspection.dart'; import 'logic.dart'; @@ -12,43 +11,136 @@ class ModulesPage extends GetView { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('انتخاب سامانه', style: AppFonts.yekan18.copyWith(color: Colors.white)), + title: Row( + spacing: 5.w, + children: [ + Text('سامانه جامع رصدیار', style: AppFonts.yekan18Bold.copyWith(color: Colors.white)), + Assets.logos.finalLogo.image(width: 40.w, height: 40.h), + ], + ), centerTitle: true, backgroundColor: AppColor.blueNormal, ), - body: GridView.builder( - padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), + body: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + Positioned.fill( + child: Column( + children: [ + SizedBox(height: 24.h), + SliderWidget(widgetTag: "up"), - itemBuilder: (context, index) { - final module = controller.moduleList[index]; - return CardIcon( - title: module.title, - icon: module.icon, - onTap: () { - controller.selectedIndex.value = index; - controller.saveModule(module.module); + Expanded( + child: GridView.builder( + padding: EdgeInsets.symmetric(horizontal: 25.w, vertical: 24.h), + itemBuilder: (context, index) { + final module = controller.moduleList[index]; + return CardIcon( + title: module.title, + icon: module.icon, + borderColor: module.borderColor, + backgroundColor: module.backgroundColor, + titleColor: module.titleColor, + onTap: () => controller.onTapCard(module.module, index), + ); + }, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + mainAxisSpacing: 24.h, + crossAxisSpacing: 16.w, + ), + physics: BouncingScrollPhysics(), + itemCount: controller.moduleList.length, + ), + ), - // Navigate to the appropriate route based on the selected module - switch (module.module) { - case Module.inspection: - Get.toNamed(InspectionRoutes.init); - break; - case Module.liveStocks: - //TODO: Implement liveStocks module navigation - case Module.chicken: - Get.toNamed(ChickenRoutes.init); - break; - } - }, - ); - }, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - ), - physics: BouncingScrollPhysics(), - itemCount: controller.moduleList.length, + Container( + height: 107.h, + margin: EdgeInsets.symmetric(horizontal: 16.w), + padding: EdgeInsets.fromLTRB(11.w, 8.h, 8.w, 12.h), + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment(0.00, 0.50), + end: Alignment(1.00, 0.50), + colors: [const Color(0xFFC9D5FF), Colors.white], + ), + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 1.w, color: const Color(0xFFD3D3D3)), + ), + child: Row( + spacing: 11.w, + children: [ + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'آخرین اخبار ', + textAlign: TextAlign.right, + style: AppFonts.yekan16.copyWith( + color: Color(0xFF5B5B5B), + height: 1.90, + ), + ), + ObxValue( + (data) => Text( + data.value ?? + 'اخبار مربوط به جوجه ریزی استان از آخرین روند مطلع شوید...', + maxLines: 2, + style: AppFonts.yekan12.copyWith( + color: Color(0xFF5B5B5B), + height: 1.5, + overflow: TextOverflow.ellipsis, + ), + ), + controller.latestNews, + ), + ], + ), + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + width: 103.w, + height: 24.h, + alignment: Alignment.center, + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50.r), + ), + ), + child: Text( + 'اطلاعات بیشتر', + textAlign: TextAlign.right, + style: AppFonts.yekan14, + ), + ), + ], + ), + ], + ), + ), + + SizedBox(height: 12.h), + SliderWidget(height: 160, widgetTag: "down"), + SizedBox(height: 20.h), + ], + ), + ), + ObxValue((loading) { + if (!controller.isLoading.value) return SizedBox.shrink(); + return Container( + color: Colors.grey.withValues(alpha: 0.5), + child: Center( + child: CupertinoActivityIndicator(color: AppColor.greenNormal, radius: 30), + ), + ); + }, controller.isLoading), + ], ), ); } diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart index a9f1a8d..562829a 100644 --- a/lib/presentation/pages/splash/logic.dart +++ b/lib/presentation/pages/splash/logic.dart @@ -154,8 +154,11 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { if (isUpdateNeeded) return; tokenService.getModule(); final module = tokenService.appModule.value; - final target = getTargetPage(module); - Get.offAndToNamed(target); + final target = getTargetModule(module); + if (target.values.first != null) { + await target.values.first; + } + Get.offAndToNamed(target.keys.first); } catch (e, st) { debugPrint("onReady error: $e\n$st"); } diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index 44675f4..c0a0e8a 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -4,8 +4,11 @@ import 'package:rasadyar_app/presentation/pages/splash/logic.dart'; import 'package:rasadyar_app/presentation/pages/splash/view.dart'; import 'package:rasadyar_app/presentation/pages/system_design/system_design.dart'; import 'package:rasadyar_chicken/chicken.dart'; +import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_inspection/injection/inspection_di.dart'; import 'package:rasadyar_inspection/inspection.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; part 'app_paths.dart'; @@ -22,7 +25,11 @@ sealed class AppPages { GetPage( name: AppPaths.moduleList, page: () => ModulesPage(), - binding: BindingsBuilder.put(() => ModulesLogic()), + binding: BindingsBuilder(() { + Get.lazyPut(() => SliderLogic(), tag: "up"); + Get.lazyPut(() => SliderLogic(), tag: "down"); + Get.put(ModulesLogic()); + }), ), GetPage( @@ -32,21 +39,39 @@ sealed class AppPages { ), ...InspectionPages.pages, - ...LiveStockPages.pages, ...ChickenPages.pages, ]; } -String getTargetPage(Module? value) { +Map?> getTargetModule(Module? value) { switch (value) { case Module.inspection: - return InspectionRoutes.init; + return {InspectionRoutes.init: setupInspectionDI()}; case Module.liveStocks: - return LiveStockRoutes.init; + return {LiveStockRoutes.init: setupLiveStockDI()}; case Module.chicken: - return ChickenRoutes.init; + return {ChickenRoutes.init: setupChickenDI()}; default: - return AppPaths.moduleList; + return {AppPaths.moduleList: null}; + } +} + +Map?>?> getAuthTargetPage(Module? value) { + switch (value) { + case Module.inspection: + return { + InspectionRoutes.auth: [setupInspectionDI(), removeInspectionDI()], + }; + case Module.liveStocks: + return { + LiveStockRoutes.auth: [setupLiveStockDI(), removeLiveStockDI()], + }; + case Module.chicken: + return { + ChickenRoutes.auth: [setupChickenDI(), removeChickenDI()], + }; + default: + return {AppPaths.moduleList: null}; } } diff --git a/lib/presentation/routes/auth_route_resolver_impl.dart b/lib/presentation/routes/auth_route_resolver_impl.dart index c932919..6f77831 100644 --- a/lib/presentation/routes/auth_route_resolver_impl.dart +++ b/lib/presentation/routes/auth_route_resolver_impl.dart @@ -14,9 +14,7 @@ class AppAuthRouteResolver implements AuthRouteResolver { return LiveStockRoutes.auth; case Module.chicken: return ChickenRoutes.auth; - default: - throw UnimplementedError('No auth route for module: $module'); - } + } } @override diff --git a/packages/chicken/.gitignore b/packages/chicken/.gitignore index 3cceda5..c40e34e 100644 --- a/packages/chicken/.gitignore +++ b/packages/chicken/.gitignore @@ -1,7 +1,4 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ - -# Avoid committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock +.dart_tool +*.lock +.flutter-plugins-dependencies +.flutter-plugins \ No newline at end of file diff --git a/packages/chicken/lib/data/data_source/remote/chicken/chicken_remote_imp.dart b/packages/chicken/lib/data/data_source/remote/chicken/chicken_remote_imp.dart index 57df1fa..4fa0122 100644 --- a/packages/chicken/lib/data/data_source/remote/chicken/chicken_remote_imp.dart +++ b/packages/chicken/lib/data/data_source/remote/chicken/chicken_remote_imp.dart @@ -36,7 +36,6 @@ class ChickenRemoteDatasourceImp implements ChickenRemoteDatasource { required String token, CancelToken? cancelToken, }) async { - eLog(_httpClient.baseUrl); var res = await _httpClient.get( '/roles-products/?role=Steward', headers: {'Authorization': 'Bearer $token'}, diff --git a/packages/chicken/lib/data/di/chicken_di.dart b/packages/chicken/lib/data/di/chicken_di.dart index d85f410..8f23e29 100644 --- a/packages/chicken/lib/data/di/chicken_di.dart +++ b/packages/chicken/lib/data/di/chicken_di.dart @@ -1,8 +1,15 @@ import 'package:rasadyar_chicken/chicken.dart'; import 'package:rasadyar_chicken/data/common/dio_error_handler.dart'; +import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart'; +import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart'; import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart'; import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote_imp.dart'; +import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote.dart'; +import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote_imp.dart'; +import 'package:rasadyar_chicken/data/repositories/auth/auth_repository.dart'; import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart'; +import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository.dart'; +import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository_imp.dart'; import 'package:rasadyar_core/core.dart'; GetIt diChicken = GetIt.instance; @@ -13,7 +20,7 @@ Future setupChickenDI() async { diChicken.registerLazySingleton( () => AppInterceptor( - //فعلا سامانه مرغ برای رفرش توکن چیزی ندارد + // سامانه مرغ فعلاً رفرش توکن ندارد refreshTokenCallback: () async => null, saveTokenCallback: (String newToken) async { await tokenService.saveAccessToken(newToken); @@ -26,24 +33,42 @@ Future setupChickenDI() async { instanceName: 'chickenInterceptor', ); + var baseUrl = tokenService.baseurl.value; + diChicken.registerLazySingleton( - () => - DioRemote(interceptors: diChicken.get(instanceName: 'chickenInterceptor')), + () => DioRemote( + baseUrl: baseUrl, + interceptors: diChicken.get(instanceName: 'chickenInterceptor'), + ), ); final dioRemote = diChicken.get(); await dioRemote.init(); - diChicken.registerLazySingleton( - () => AuthRemoteDataSourceImp(diChicken.get()), + diChicken.registerLazySingleton( + () => AuthRemoteDataSourceImp(dioRemote), ); - diChicken.registerLazySingleton( - () => AuthRepositoryImpl(diChicken.get()), + diChicken.registerLazySingleton( + () => AuthRepositoryImpl(diChicken.get()), + ); + + diChicken.registerLazySingleton( + () => ChickenRemoteDatasourceImp(diChicken.get()), + ); + + diChicken.registerLazySingleton(() => ChickenLocalDataSourceImp()); + + diChicken.registerLazySingleton( + () => ChickenRepositoryImp( + remote: diChicken.get(), + local: diChicken.get(), + ), ); } Future newSetupAuthDI(String newUrl) async { + tLog("setup 2"); var tokenService = Get.find(); if (tokenService.baseurl.value == null) { await tokenService.saveBaseUrl(newUrl); @@ -52,7 +77,10 @@ Future newSetupAuthDI(String newUrl) async { if (diChicken.isRegistered()) { await diChicken.unregister(); diChicken.registerLazySingleton( - () => DioRemote(baseUrl: newUrl, interceptors: diChicken.get()), + () => DioRemote( + baseUrl: newUrl, + interceptors: diChicken.get(instanceName: 'chickenInterceptor'), + ), ); final dioRemote = diChicken.get(); await dioRemote.init(); @@ -60,15 +88,66 @@ Future newSetupAuthDI(String newUrl) async { if (diChicken.isRegistered()) { await diChicken.unregister(); - diChicken.registerLazySingleton( + diChicken.registerLazySingleton( () => AuthRemoteDataSourceImp(diChicken.get()), ); } - if (diChicken.isRegistered()) { - await diChicken.unregister(); - diChicken.registerLazySingleton( + if (diChicken.isRegistered()) { + await diChicken.unregister(); + diChicken.registerLazySingleton( () => AuthRepositoryImpl(diChicken.get()), ); } + + if (diChicken.isRegistered()) { + await diChicken.unregister(); + diChicken.registerLazySingleton( + () => ChickenRemoteDatasourceImp(diChicken.get()), + ); + } + + if (diChicken.isRegistered()) { + await diChicken.unregister(); + diChicken.registerLazySingleton(() => ChickenLocalDataSourceImp()); + } + + if (diChicken.isRegistered()) { + await diChicken.unregister(); + diChicken.registerLazySingleton( + () => ChickenRepositoryImp( + remote: diChicken.get(), + local: diChicken.get(), + ), + ); + } } + + + +Future removeChickenDI() async { + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered(instanceName: 'chickenInterceptor')) { + diChicken.unregister(instanceName: 'chickenInterceptor'); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } + if (diChicken.isRegistered()) { + diChicken.unregister(); + } +} \ No newline at end of file diff --git a/packages/chicken/lib/data/repositories/chicken/chicken_repository_imp.dart b/packages/chicken/lib/data/repositories/chicken/chicken_repository_imp.dart index d9d829e..63e9545 100644 --- a/packages/chicken/lib/data/repositories/chicken/chicken_repository_imp.dart +++ b/packages/chicken/lib/data/repositories/chicken/chicken_repository_imp.dart @@ -1,5 +1,5 @@ -import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart'; -import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote_imp.dart'; +import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart'; +import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote.dart'; import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart'; import 'package:rasadyar_chicken/data/models/request/change_password/change_password_request_model.dart'; import 'package:rasadyar_chicken/data/models/request/conform_allocation/conform_allocation.dart'; @@ -29,8 +29,8 @@ import 'package:rasadyar_core/core.dart'; import 'chicken_repository.dart'; class ChickenRepositoryImp implements ChickenRepository { - final ChickenRemoteDatasourceImp remote; - final ChickenLocalDataSourceImp local; + final ChickenRemoteDatasource remote; + final ChickenLocalDataSource local; ChickenRepositoryImp({required this.remote, required this.local}); diff --git a/packages/chicken/lib/presentation/pages/auth/logic.dart b/packages/chicken/lib/presentation/pages/auth/logic.dart index bec91ab..b1cfbe2 100644 --- a/packages/chicken/lib/presentation/pages/auth/logic.dart +++ b/packages/chicken/lib/presentation/pages/auth/logic.dart @@ -1,12 +1,13 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:rasadyar_chicken/chicken.dart'; import 'package:rasadyar_chicken/data/common/dio_error_handler.dart'; import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_chicken/data/models/request/login_request/login_request_model.dart'; import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart'; import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart'; -import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart'; +import 'package:rasadyar_chicken/data/repositories/auth/auth_repository.dart'; import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart'; import 'package:rasadyar_core/core.dart'; @@ -22,6 +23,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { late AnimationController _textAnimationController; late Animation textAnimation; RxBool showCard = false.obs; + RxBool rememberMe = false.obs; Rx> formKeyOtp = GlobalKey().obs; Rx> formKeySentOtp = GlobalKey().obs; @@ -44,7 +46,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { RxInt secondsRemaining = 120.obs; Timer? _timer; - AuthRepositoryImpl authRepository = diChicken.get(); + AuthRepository authRepository = diChicken.get(); final Module _module = Get.arguments; @@ -59,12 +61,13 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { }); textAnimation = CurvedAnimation(parent: _textAnimationController, curve: Curves.easeInOut); + + initUserPassData(); } @override void onReady() { super.onReady(); - } @override @@ -118,7 +121,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { Future submitLoginForm() async { if (!_isFormValid()) return; - AuthRepositoryImpl authTmp = diChicken.get(instanceName: 'newUrl'); + AuthRepository authTmp = diChicken.get(); isLoading.value = true; await safeCall( call: () => authTmp.login( @@ -131,6 +134,17 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { await tokenStorageService.saveModule(_module); await tokenStorageService.saveAccessToken(result?.accessToken ?? ''); await tokenStorageService.saveRefreshToken(result?.accessToken ?? ''); + if (rememberMe.value) { + await tokenStorageService.saveUserPass( + UserLocalModel( + username: usernameController.value.text, + password: passwordController.value.text, + module: _module, + ), + ); + } + + Get.offAndToNamed(ChickenRoutes.init); }, onError: (error, stackTrace) { if (error is DioException) { @@ -162,4 +176,13 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { ); isLoading.value = false; } + + void initUserPassData() { + UserLocalModel? userPass = tokenStorageService.getUserPass(_module); + if (userPass != null) { + usernameController.value.text = userPass.username ?? ''; + passwordController.value.text = userPass.password ?? ''; + rememberMe.value = true; + } + } } diff --git a/packages/chicken/lib/presentation/pages/auth/view.dart b/packages/chicken/lib/presentation/pages/auth/view.dart index 1700994..ef0d429 100644 --- a/packages/chicken/lib/presentation/pages/auth/view.dart +++ b/packages/chicken/lib/presentation/pages/auth/view.dart @@ -13,31 +13,34 @@ class AuthPage extends GetView { return Scaffold( body: Stack( alignment: Alignment.center, + fit: StackFit.expand, children: [ Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: FadeTransition( - opacity: controller.textAnimation, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 12, - children: [ - Text( - 'به سامانه رصدیار خوش آمدید!', - textAlign: TextAlign.right, - style: AppFonts.yekan25Bold.copyWith(color: Colors.white), - ), - Text( - 'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی', - textAlign: TextAlign.center, - style: AppFonts.yekan16.copyWith(color: Colors.white), - ), - ], + Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: FadeTransition( + opacity: controller.textAnimation, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 12, + children: [ + Text( + 'به سامانه رصدیار خوش آمدید!', + textAlign: TextAlign.right, + style: AppFonts.yekan25Bold.copyWith(color: Colors.white), + ), + Text( + 'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith(color: Colors.white), + ), + ], + ), ), ), ), @@ -194,7 +197,33 @@ class AuthPage extends GetView { ), SizedBox(height: 26), CaptchaWidget(), - SizedBox(height: 23), + + GestureDetector( + onTap: () { + controller.rememberMe.value = !controller.rememberMe.value; + }, + child: Row( + children: [ + ObxValue((data) { + return Checkbox( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity(horizontal: -4, vertical: 4), + tristate: true, + value: data.value, + onChanged: (value) { + data.value = value ?? false; + }, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + activeColor: AppColor.blueNormal, + ); + }, controller.rememberMe), + Text( + 'مرا به خاطر بسپار', + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), Obx(() { return RElevated( diff --git a/packages/chicken/lib/presentation/pages/profile/view.dart b/packages/chicken/lib/presentation/pages/profile/view.dart index 23ccba7..7328c0d 100644 --- a/packages/chicken/lib/presentation/pages/profile/view.dart +++ b/packages/chicken/lib/presentation/pages/profile/view.dart @@ -3,9 +3,9 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/chicken.dart'; +import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart'; import 'package:rasadyar_chicken/data/models/response/user_profile/user_profile.dart'; - import 'package:rasadyar_core/core.dart'; import 'logic.dart'; @@ -27,49 +27,41 @@ class ProfilePage extends GetView { crossAxisAlignment: CrossAxisAlignment.center, children: [ Row(), - ObxValue( - (data) { - final status = data.value.status; + ObxValue((data) { + final status = data.value.status; - if (status == ResourceStatus.loading) { - return Container( - width: 128.w, - height: 128.h, - child: Center(child: CupertinoActivityIndicator(color: AppColor - .greenNormal,)), - ); - } - - if (status == ResourceStatus.error) { - return Container( - width: 128.w, - height: 128.h, - child: Center(child: Text('خطا در دریافت اطلاعات')), - ); - } - - - // Default UI + if (status == ResourceStatus.loading) { return Container( width: 128.w, height: 128.h, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColor.blueLightActive, - ), - child: Center( - child: CircleAvatar( - radius: 64.w, - backgroundImage: - NetworkImage(data.value.data!.image!) - - - ), - ), + child: Center(child: CupertinoActivityIndicator(color: AppColor.greenNormal)), ); - }, - controller.userProfile, - ) + } + + if (status == ResourceStatus.error) { + return Container( + width: 128.w, + height: 128.h, + child: Center(child: Text('خطا در دریافت اطلاعات')), + ); + } + + // Default UI + return Container( + width: 128.w, + height: 128.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.blueLightActive, + ), + child: Center( + child: CircleAvatar( + radius: 64.w, + backgroundImage: NetworkImage(data.value.data!.image!), + ), + ), + ); + }, controller.userProfile), ], ), ), @@ -126,17 +118,16 @@ class ProfilePage extends GetView { Container invoiceIssuanceInformation() => Container(); - Widget bankInformationWidget() => - Column( - spacing: 16, - children: [ - itemList(title: 'نام بانک', content: 'سامان'), - itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'), - itemList(title: 'شماره کارت ', content: '54154545415'), - itemList(title: 'شماره حساب', content: '62565263263652'), - itemList(title: 'شماره شبا', content: '62565263263652'), - ], - ); + Widget bankInformationWidget() => Column( + spacing: 16, + children: [ + itemList(title: 'نام بانک', content: 'سامان'), + itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'), + itemList(title: 'شماره کارت ', content: '54154545415'), + itemList(title: 'شماره حساب', content: '62565263263652'), + itemList(title: 'شماره شبا', content: '62565263263652'), + ], + ); Widget userProfileInformation() { return ObxValue((data) { @@ -152,7 +143,10 @@ class ProfilePage extends GetView { buildRowOnTapped( onTap: () { Get.bottomSheet( - userInformationBottomSheet(), isScrollControlled: true, ignoreSafeArea: false); + userInformationBottomSheet(), + isScrollControlled: true, + ignoreSafeArea: false, + ); }, titleWidget: Column( spacing: 3, @@ -216,34 +210,33 @@ class ProfilePage extends GetView { required String content, String? icon, bool hasColoredBox = false, - }) => - Container( - padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h), - decoration: BoxDecoration( - color: hasColoredBox ? AppColor.greenLight : Colors.transparent, - borderRadius: BorderRadius.circular(8), - border: hasColoredBox - ? Border.all(width: 0.25, color: AppColor.bgDark) - : Border.all(width: 0, color: Colors.transparent), - ), - child: Row( - spacing: 4, - children: [ - if (icon != null) - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: SvgGenImage.vec(icon).svg( - width: 20.w, - height: 20.h, - colorFilter: ColorFilter.mode(AppColor.mediumGreyNormalActive, BlendMode.srcIn), - ), - ), - Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.mediumGreyNormalActive)), - Spacer(), - Text(content, style: AppFonts.yekan13.copyWith(color: AppColor.mediumGreyNormalHover)), - ], - ), - ); + }) => Container( + padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h), + decoration: BoxDecoration( + color: hasColoredBox ? AppColor.greenLight : Colors.transparent, + borderRadius: BorderRadius.circular(8), + border: hasColoredBox + ? Border.all(width: 0.25, color: AppColor.bgDark) + : Border.all(width: 0, color: Colors.transparent), + ), + child: Row( + spacing: 4, + children: [ + if (icon != null) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: SvgGenImage.vec(icon).svg( + width: 20.w, + height: 20.h, + colorFilter: ColorFilter.mode(AppColor.mediumGreyNormalActive, BlendMode.srcIn), + ), + ), + Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.mediumGreyNormalActive)), + Spacer(), + Text(content, style: AppFonts.yekan13.copyWith(color: AppColor.mediumGreyNormalHover)), + ], + ), + ); Widget cardActionWidget({ required String title, @@ -271,7 +264,7 @@ class ProfilePage extends GetView { width: 40, height: 40, colorFilter: - color ?? + color ?? ColorFilter.mode( selected ? AppColor.blueNormal : AppColor.whiteLight, BlendMode.srcIn, @@ -355,8 +348,6 @@ class ProfilePage extends GetView { }, controller.birthDate), SizedBox(), - - ], ), ), @@ -372,8 +363,10 @@ class ProfilePage extends GetView { child: Column( spacing: 8, children: [ - Text('عکس پروفایل', - style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal)), + Text( + 'عکس پروفایل', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), ObxValue((data) { return Container( width: Get.width, @@ -386,9 +379,11 @@ class ProfilePage extends GetView { child: Center( child: data.value == null ? Padding( - padding: const EdgeInsets.fromLTRB(30, 10, 10, 30), - child: Image.network(controller.userProfile.value.data?.image ?? '') - ) + padding: const EdgeInsets.fromLTRB(30, 10, 10, 30), + child: Image.network( + controller.userProfile.value.data?.image ?? '', + ), + ) : Image.file(File(data.value!.path), fit: BoxFit.cover), ), ); @@ -447,7 +442,7 @@ class ProfilePage extends GetView { Get.back(); }, ); - },controller.isOnLoading), + }, controller.isOnLoading), ROutlinedElevated( height: 40.h, text: 'انصراف', @@ -618,7 +613,7 @@ class ProfilePage extends GetView { text: 'خروج', backgroundColor: AppColor.error, onPressed: () async { - await controller.rootLogic.tokenService.deleteTokens().then((value) { + await controller.rootLogic.tokenService.deleteTokens().then((value){ Get.back(); Get.offAllNamed(ChickenRoutes.auth, arguments: Module.chicken); }); diff --git a/packages/chicken/lib/presentation/pages/root/logic.dart b/packages/chicken/lib/presentation/pages/root/logic.dart index 570614a..286803e 100644 --- a/packages/chicken/lib/presentation/pages/root/logic.dart +++ b/packages/chicken/lib/presentation/pages/root/logic.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; +import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart'; import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart'; import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart'; @@ -32,7 +33,7 @@ class RootLogic extends GetxController { late DioRemote dioRemote; var tokenService = Get.find(); late ChickenRepository chickenRepository; - late ChickenLocalDataSourceImp localDatasource; + late ChickenLocalDataSource localDatasource; RxList errorLocationType = RxList(); RxMap inventoryExpandedList = RxMap(); @@ -46,8 +47,9 @@ class RootLogic extends GetxController { @override void onInit() { super.onInit(); - localDatasource = diChicken.get(); - chickenRepository = diChicken.get(); + localDatasource = diChicken.get(); + chickenRepository = diChicken.get(); + localDatasource.openBox().then((value) async { widelyUsedList.value = localDatasource.getAllWidely(); }); diff --git a/packages/chicken/pubspec.yaml b/packages/chicken/pubspec.yaml index 55b6790..683ba53 100644 --- a/packages/chicken/pubspec.yaml +++ b/packages/chicken/pubspec.yaml @@ -3,7 +3,7 @@ description: A starting point for Dart libraries or applications. version: 1.2.1+2 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: diff --git a/packages/core/.gitignore b/packages/core/.gitignore new file mode 100644 index 0000000..38a41ed --- /dev/null +++ b/packages/core/.gitignore @@ -0,0 +1,33 @@ +# Ignore build output and other generated files +build/ + +# Dart/Pub related +.dart_tool/ +.packages +.pub/ + +# IDE files +.idea/ +*.iml +*.ipr +*.iws +*.lock +# VS Code +.vscode/ + +# macOS +.DS_Store + +# Other +*.log +*.swp +*.pyc + +# Flutter specific +.flutter-plugins +.flutter-plugins-dependencies +pubspec.lock + +# Test outputs +test_cache/ + diff --git a/packages/core/build/unit_test_assets/AssetManifest.json b/packages/core/build/unit_test_assets/AssetManifest.json deleted file mode 100644 index 52a2006..0000000 --- a/packages/core/build/unit_test_assets/AssetManifest.json +++ /dev/null @@ -1 +0,0 @@ -{"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"],"packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf":["packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf"],"packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf":["packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf"],"packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf":["packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf"]} \ No newline at end of file diff --git a/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png b/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png deleted file mode 100644 index 8603d0a..0000000 Binary files a/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png and /dev/null differ diff --git a/packages/core/devtools_options.yaml b/packages/core/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/packages/core/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index c881e08..55eeb79 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -2,17 +2,22 @@ library; export 'package:android_intent_plus/android_intent.dart'; export 'package:android_intent_plus/flag.dart'; +export 'package:cached_network_image/cached_network_image.dart'; +export 'package:collection/collection.dart'; +export 'package:connectivity_plus/connectivity_plus.dart'; export 'package:device_info_plus/device_info_plus.dart'; export 'package:dio/dio.dart'; //other packages export 'package:flutter_localizations/flutter_localizations.dart'; +//map export 'package:flutter_map/flutter_map.dart'; export 'package:flutter_map_animations/flutter_map_animations.dart'; +export 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart'; +export 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart' hide DownloadProgress; export 'package:flutter_rating_bar/flutter_rating_bar.dart'; export 'package:flutter_screenutil/flutter_screenutil.dart'; export 'package:flutter_secure_storage/flutter_secure_storage.dart'; export 'package:flutter_slidable/flutter_slidable.dart'; -export 'package:font_awesome_flutter/font_awesome_flutter.dart'; //freezed export 'package:freezed_annotation/freezed_annotation.dart'; export 'package:geolocator/geolocator.dart'; @@ -21,6 +26,7 @@ export 'package:get/get.dart' hide FormData, MultipartFile, Response; export 'package:get_it/get_it.dart'; //local storage export 'package:hive_ce_flutter/hive_flutter.dart'; +export 'package:image_cropper/image_cropper.dart'; ///image picker export 'package:image_picker/image_picker.dart'; //encryption @@ -36,7 +42,7 @@ export 'package:pretty_dio_logger/pretty_dio_logger.dart'; export 'package:rasadyar_core/presentation/common/common.dart'; export 'package:rasadyar_core/presentation/utils/utils.dart'; export 'package:rasadyar_core/presentation/widget/widget.dart'; -export 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart'; +export 'package:smooth_page_indicator/smooth_page_indicator.dart'; //models export 'data/model/model.dart'; @@ -57,5 +63,4 @@ export 'utils/map_utils.dart'; export 'utils/network/network.dart'; export 'utils/route_utils.dart'; export 'utils/separator_input_formatter.dart'; - export 'utils/utils.dart'; diff --git a/packages/core/lib/data/model/local/module/module_model.dart b/packages/core/lib/data/model/local/module/module_model.dart index 3ca5760..2d036cc 100644 --- a/packages/core/lib/data/model/local/module/module_model.dart +++ b/packages/core/lib/data/model/local/module/module_model.dart @@ -1,16 +1,18 @@ -import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/data/model/local/user_local/user_local_model.dart'; +import 'package:flutter/material.dart'; part 'module_model.freezed.dart'; @freezed abstract class ModuleModel with _$ModuleModel{ - const factory ModuleModel({ + factory ModuleModel({ required String title, required String icon, - required Module module, + required Color borderColor, + required Color backgroundColor, + required Color titleColor, + Module? module, }) = _ModuleModel; } \ No newline at end of file diff --git a/packages/core/lib/data/model/local/module/module_model.freezed.dart b/packages/core/lib/data/model/local/module/module_model.freezed.dart index aedd18f..28a5bdd 100644 --- a/packages/core/lib/data/model/local/module/module_model.freezed.dart +++ b/packages/core/lib/data/model/local/module/module_model.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$ModuleModel { - String get title; String get icon; Module get module; + String get title; String get icon; Color get borderColor; Color get backgroundColor; Color get titleColor; Module? get module; /// Create a copy of ModuleModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $ModuleModelCopyWith get copyWith => _$ModuleModelCopyWithImpl Object.hash(runtimeType,title,icon,module); +int get hashCode => Object.hash(runtimeType,title,icon,borderColor,backgroundColor,titleColor,module); @override String toString() { - return 'ModuleModel(title: $title, icon: $icon, module: $module)'; + return 'ModuleModel(title: $title, icon: $icon, borderColor: $borderColor, backgroundColor: $backgroundColor, titleColor: $titleColor, module: $module)'; } @@ -45,7 +45,7 @@ abstract mixin class $ModuleModelCopyWith<$Res> { factory $ModuleModelCopyWith(ModuleModel value, $Res Function(ModuleModel) _then) = _$ModuleModelCopyWithImpl; @useResult $Res call({ - String title, String icon, Module module + String title, String icon, Color borderColor, Color backgroundColor, Color titleColor, Module? module }); @@ -62,12 +62,15 @@ class _$ModuleModelCopyWithImpl<$Res> /// Create a copy of ModuleModel /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? icon = null,Object? module = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? icon = null,Object? borderColor = null,Object? backgroundColor = null,Object? titleColor = null,Object? module = freezed,}) { return _then(_self.copyWith( title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable -as String,module: null == module ? _self.module : module // ignore: cast_nullable_to_non_nullable -as Module, +as String,borderColor: null == borderColor ? _self.borderColor : borderColor // ignore: cast_nullable_to_non_nullable +as Color,backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable +as Color,titleColor: null == titleColor ? _self.titleColor : titleColor // ignore: cast_nullable_to_non_nullable +as Color,module: freezed == module ? _self.module : module // ignore: cast_nullable_to_non_nullable +as Module?, )); } @@ -152,10 +155,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String title, String icon, Module module)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String title, String icon, Color borderColor, Color backgroundColor, Color titleColor, Module? module)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _ModuleModel() when $default != null: -return $default(_that.title,_that.icon,_that.module);case _: +return $default(_that.title,_that.icon,_that.borderColor,_that.backgroundColor,_that.titleColor,_that.module);case _: return orElse(); } @@ -173,10 +176,10 @@ return $default(_that.title,_that.icon,_that.module);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String title, String icon, Module module) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String title, String icon, Color borderColor, Color backgroundColor, Color titleColor, Module? module) $default,) {final _that = this; switch (_that) { case _ModuleModel(): -return $default(_that.title,_that.icon,_that.module);case _: +return $default(_that.title,_that.icon,_that.borderColor,_that.backgroundColor,_that.titleColor,_that.module);case _: throw StateError('Unexpected subclass'); } @@ -193,10 +196,10 @@ return $default(_that.title,_that.icon,_that.module);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String title, String icon, Module module)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String title, String icon, Color borderColor, Color backgroundColor, Color titleColor, Module? module)? $default,) {final _that = this; switch (_that) { case _ModuleModel() when $default != null: -return $default(_that.title,_that.icon,_that.module);case _: +return $default(_that.title,_that.icon,_that.borderColor,_that.backgroundColor,_that.titleColor,_that.module);case _: return null; } @@ -208,12 +211,15 @@ return $default(_that.title,_that.icon,_that.module);case _: class _ModuleModel implements ModuleModel { - const _ModuleModel({required this.title, required this.icon, required this.module}); + _ModuleModel({required this.title, required this.icon, required this.borderColor, required this.backgroundColor, required this.titleColor, this.module}); @override final String title; @override final String icon; -@override final Module module; +@override final Color borderColor; +@override final Color backgroundColor; +@override final Color titleColor; +@override final Module? module; /// Create a copy of ModuleModel /// with the given fields replaced by the non-null parameter values. @@ -225,16 +231,16 @@ _$ModuleModelCopyWith<_ModuleModel> get copyWith => __$ModuleModelCopyWithImpl<_ @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _ModuleModel&&(identical(other.title, title) || other.title == title)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.module, module) || other.module == module)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ModuleModel&&(identical(other.title, title) || other.title == title)&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.borderColor, borderColor) || other.borderColor == borderColor)&&(identical(other.backgroundColor, backgroundColor) || other.backgroundColor == backgroundColor)&&(identical(other.titleColor, titleColor) || other.titleColor == titleColor)&&(identical(other.module, module) || other.module == module)); } @override -int get hashCode => Object.hash(runtimeType,title,icon,module); +int get hashCode => Object.hash(runtimeType,title,icon,borderColor,backgroundColor,titleColor,module); @override String toString() { - return 'ModuleModel(title: $title, icon: $icon, module: $module)'; + return 'ModuleModel(title: $title, icon: $icon, borderColor: $borderColor, backgroundColor: $backgroundColor, titleColor: $titleColor, module: $module)'; } @@ -245,7 +251,7 @@ abstract mixin class _$ModuleModelCopyWith<$Res> implements $ModuleModelCopyWith factory _$ModuleModelCopyWith(_ModuleModel value, $Res Function(_ModuleModel) _then) = __$ModuleModelCopyWithImpl; @override @useResult $Res call({ - String title, String icon, Module module + String title, String icon, Color borderColor, Color backgroundColor, Color titleColor, Module? module }); @@ -262,12 +268,15 @@ class __$ModuleModelCopyWithImpl<$Res> /// Create a copy of ModuleModel /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? icon = null,Object? module = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? icon = null,Object? borderColor = null,Object? backgroundColor = null,Object? titleColor = null,Object? module = freezed,}) { return _then(_ModuleModel( title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable as String,icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable -as String,module: null == module ? _self.module : module // ignore: cast_nullable_to_non_nullable -as Module, +as String,borderColor: null == borderColor ? _self.borderColor : borderColor // ignore: cast_nullable_to_non_nullable +as Color,backgroundColor: null == backgroundColor ? _self.backgroundColor : backgroundColor // ignore: cast_nullable_to_non_nullable +as Color,titleColor: null == titleColor ? _self.titleColor : titleColor // ignore: cast_nullable_to_non_nullable +as Color,module: freezed == module ? _self.module : module // ignore: cast_nullable_to_non_nullable +as Module?, )); } diff --git a/packages/core/lib/data/model/local/user_local/user_local_model.dart b/packages/core/lib/data/model/local/user_local/user_local_model.dart index beb08f2..d5a4afd 100644 --- a/packages/core/lib/data/model/local/user_local/user_local_model.dart +++ b/packages/core/lib/data/model/local/user_local/user_local_model.dart @@ -1,5 +1,4 @@ import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/utils/local/local_utils.dart'; part 'user_local_model.g.dart'; @@ -13,27 +12,18 @@ class UserLocalModel extends HiveObject { String? token; @HiveField(3) String? refreshToken; - @HiveField(4) - String? name; - @HiveField(5) Module? module; - @HiveField(6) String? backend; - @HiveField(7) - String? apiKey; - UserLocalModel({ this.username, this.password, this.token, this.refreshToken, - this.name, this.module, this.backend, - this.apiKey, }); UserLocalModel copyWith({ @@ -41,20 +31,16 @@ class UserLocalModel extends HiveObject { String? password, String? token, String? refreshToken, - String? name, Module? module, String? backend, - String? apiKey, }) { return UserLocalModel( username: username ?? this.username, password: password ?? this.password, token: token ?? this.token, refreshToken: refreshToken ?? this.refreshToken, - name: name ?? this.name, module: module ?? this.module, backend: backend ?? this.backend, - apiKey: apiKey ?? this.apiKey, ); } } diff --git a/packages/core/lib/data/model/local/user_local/user_local_model.g.dart b/packages/core/lib/data/model/local/user_local/user_local_model.g.dart index 93e49af..cde7c65 100644 --- a/packages/core/lib/data/model/local/user_local/user_local_model.g.dart +++ b/packages/core/lib/data/model/local/user_local/user_local_model.g.dart @@ -21,17 +21,15 @@ class UserLocalModelAdapter extends TypeAdapter { password: fields[1] as String?, token: fields[2] as String?, refreshToken: fields[3] as String?, - name: fields[4] as String?, module: fields[5] as Module?, backend: fields[6] as String?, - apiKey: fields[7] as String?, ); } @override void write(BinaryWriter writer, UserLocalModel obj) { writer - ..writeByte(8) + ..writeByte(6) ..writeByte(0) ..write(obj.username) ..writeByte(1) @@ -40,14 +38,10 @@ class UserLocalModelAdapter extends TypeAdapter { ..write(obj.token) ..writeByte(3) ..write(obj.refreshToken) - ..writeByte(4) - ..write(obj.name) ..writeByte(5) ..write(obj.module) ..writeByte(6) - ..write(obj.backend) - ..writeByte(7) - ..write(obj.apiKey); + ..write(obj.backend); } @override diff --git a/packages/core/lib/data/services/network_status.dart b/packages/core/lib/data/services/network_status.dart new file mode 100644 index 0000000..6eb646c --- /dev/null +++ b/packages/core/lib/data/services/network_status.dart @@ -0,0 +1,24 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:get/get.dart'; + +class NetworkStatus { + NetworkStatus._(); + + static final NetworkStatus _instance = NetworkStatus._(); + + factory NetworkStatus() => _instance; + + final Connectivity _connectivity = Connectivity(); + + RxBool isConnected = false.obs; + + void startListening() { + _connectivity.onConnectivityChanged.listen((result) { + isConnected.value = !result.contains(ConnectivityResult.none); + }); + + _connectivity.checkConnectivity().then((result) { + isConnected.value = !result.contains(ConnectivityResult.none); + }); + } +} diff --git a/packages/core/lib/data/services/token_storage_service.dart b/packages/core/lib/data/services/token_storage_service.dart index ab551c9..19a19f2 100644 --- a/packages/core/lib/data/services/token_storage_service.dart +++ b/packages/core/lib/data/services/token_storage_service.dart @@ -5,6 +5,7 @@ import 'package:rasadyar_core/hive_registrar.g.dart'; class TokenStorageService extends GetxService { static const String _tokenBoxName = 'TokenBox'; + static const String _userPassBox = 'UserPassBox'; static const String _appBoxName = 'AppBox'; static const String _accessTokenKey = 'accessToken'; static const String _refreshTokenKey = 'refreshToken'; @@ -21,7 +22,6 @@ class TokenStorageService extends GetxService { Rxn appModule = Rxn(null); Future init() async { - await Hive.initFlutter(); Hive.registerAdapters(); final String? encryptedKey = await _secureStorage.read(key: 'hive_enc_key'); @@ -36,6 +36,7 @@ class TokenStorageService extends GetxService { await _localStorage.init(); await _localStorage.openBox(_tokenBoxName, encryptionCipher: HiveAesCipher(encryptionKey)); await _localStorage.openBox(_appBoxName); + await _localStorage.openBox(_userPassBox); accessToken.value = _localStorage.read(boxName: _tokenBoxName, key: _accessTokenKey); refreshToken.value = _localStorage.read(boxName: _tokenBoxName, key: _refreshTokenKey); @@ -86,4 +87,18 @@ class TokenStorageService extends GetxService { Future saveApiKey(String key) async { await _localStorage.save(boxName: _tokenBoxName, key: _apiKey, value: key); } + + Future saveUserPass(UserLocalModel model) async { + await _localStorage.save( + boxName: _userPassBox, + key: model.module!.name, + value: model, + ); + } + + UserLocalModel? getUserPass(Module module) { + return _localStorage + .readBox(boxName: _userPassBox) + ?.firstWhereOrNull((element) => element.module == module); + } } diff --git a/packages/core/lib/infrastructure/remote/app_interceptor.dart b/packages/core/lib/infrastructure/remote/app_interceptor.dart index 8af53d5..5685f57 100644 --- a/packages/core/lib/infrastructure/remote/app_interceptor.dart +++ b/packages/core/lib/infrastructure/remote/app_interceptor.dart @@ -10,7 +10,7 @@ class AppInterceptor extends Interceptor { final RefreshTokenCallback? refreshTokenCallback; final SaveTokenCallback saveTokenCallback; final ClearTokenCallback clearTokenCallback; - late final Dio dio; + late Dio dio; dynamic authArguments; static Completer? _refreshCompleter; static bool _isRefreshing = false; @@ -44,7 +44,7 @@ class AppInterceptor extends Interceptor { @override Future onError(DioException err, ErrorInterceptorHandler handler) async { - if (err.response?.statusCode == 401) { + if (err.response?.statusCode == 401 && err.response?.data['detail'] != "No active account found with the given credentials") { final retryResult = await _handleUnauthorizedError(err); if (retryResult != null) { handler.resolve(retryResult); @@ -104,6 +104,7 @@ class AppInterceptor extends Interceptor { return dio.fetch(newOptions); } + //TODO void _handleRefreshFailure() { ApiHandler.cancelAllRequests("Token refresh failed"); diff --git a/packages/core/lib/infrastructure/remote/app_interceptor_n.dart b/packages/core/lib/infrastructure/remote/app_interceptor_n.dart new file mode 100644 index 0000000..bbfb0e0 --- /dev/null +++ b/packages/core/lib/infrastructure/remote/app_interceptor_n.dart @@ -0,0 +1,168 @@ +import 'dart:async'; + +import '../../core.dart'; + +/// Callback to refresh the authentication token. +/// Typically used to request a new token from the server. +typedef RefreshTokenCallback = Future Function(); + +/// Callback to save a new authentication token. +typedef SaveTokenCallback = Future Function(String token); + +/// Callback to clear the authentication token, e.g., on logout or failure. +typedef ClearTokenCallback = Future Function(); + +/// Callback invoked when token refresh fails. +/// Typically used to redirect the user to login or show a logout message. +typedef OnRefreshFailedCallback = Future Function(); + +/// Represents a queued request waiting for token refresh. +class QueuedRequest { + /// The original request options. + final RequestOptions options; + + /// Completer used to complete the response once the request is retried. + final Completer completer; + + /// Constructs a queued request. + QueuedRequest(this.options, this.completer); +} + +/// An interceptor for automatic token management and refresh handling. +/// +/// Features: +/// - Queues requests while a token refresh is in progress. +/// - Saves and clears tokens via provided callbacks. +/// - Calls [OnRefreshFailedCallback] if token refresh fails. +class AppInterceptorN extends Interceptor { + /// Callback to refresh the authentication token. + final RefreshTokenCallback? refreshTokenCallback; + + /// Callback to save the new token. + final SaveTokenCallback saveTokenCallback; + + /// Callback to clear the token. + final ClearTokenCallback clearTokenCallback; + + /// Callback executed when token refresh fails. + final OnRefreshFailedCallback onRefreshFailed; + + /// Optional additional arguments for authentication. + final dynamic authArguments; + + /// The Dio instance used to send requests. + final Dio dio; + + /// Maximum number of retry attempts for failed requests. + final int maxRetries; + + /// Whether a token refresh is currently in progress. + bool _isRefreshing = false; + + /// Queue of requests waiting for a new token. + final List _queue = []; + + /// Current token in use. + String? _currentToken; + + /// Constructs the interceptor. + AppInterceptorN({ + required this.dio, + required this.saveTokenCallback, + required this.clearTokenCallback, + required this.onRefreshFailed, + this.refreshTokenCallback, + this.authArguments, + this.maxRetries = 3, + }); + + /// Called before sending a request. + /// If a token refresh is in progress, the request is added to the queue. + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) async { + if (_isRefreshing) { + final completer = Completer(); + _queue.add(QueuedRequest(options, completer)); + return handler.resolve(await completer.future); + } + handler.next(options); + } + + /// Called when an error occurs during a request. + /// + /// - If the error is a 401 (unauthorized) and retry count is below `maxRetries`, + /// the token is refreshed and queued requests are retried. + /// - If the token refresh fails, all queued requests are cancelled and + /// [onRefreshFailed] is executed. + @override + Future onError(DioException err, ErrorInterceptorHandler handler) async { + int currentRetry = err.requestOptions.extra['retryCount'] ?? 0; + + if (err.response?.statusCode == 401 && + err.type != DioExceptionType.cancel && + currentRetry < maxRetries) { + final completer = Completer(); + final updatedOptions = err.requestOptions.copyWith( + extra: {...err.requestOptions.extra, 'retryCount': currentRetry + 1}, + ); + _queue.add(QueuedRequest(updatedOptions, completer)); + + if (!_isRefreshing) { + _isRefreshing = true; + try { + final newToken = await refreshTokenCallback?.call(); + if (newToken != null && newToken.isNotEmpty) { + _currentToken = newToken; + await saveTokenCallback(newToken); + + for (var req in _queue) { + final newOptions = req.options.copyWith( + headers: {...req.options.headers, 'Authorization': 'Bearer $newToken'}, + ); + dio + .fetch(newOptions) + .then(req.completer.complete) + .catchError(req.completer.completeError); + } + } else { + await clearTokenCallback(); + await _handleRefreshFailure(); + for (var req in _queue) { + req.completer.completeError( + DioException(requestOptions: req.options, type: DioExceptionType.cancel), + ); + } + } + } catch (e) { + await clearTokenCallback(); + await _handleRefreshFailure(); + for (var req in _queue) { + req.completer.completeError(e); + } + } finally { + _queue.clear(); + _isRefreshing = false; + } + } + + return handler.resolve(await completer.future); + } + + handler.next(err); + } + + /// Handles token refresh failure: + /// - Cancels all ongoing requests via [ApiHandler]. + /// - Executes external [onRefreshFailed] callback. + Future _handleRefreshFailure() async { + ApiHandler.cancelAllRequests("Token refresh failed"); + + await onRefreshFailed.call(); + } + + @visibleForTesting + set isRefreshingForTest(bool value) => _isRefreshing = value; + + @visibleForTesting + List get queue => _queue; +} diff --git a/packages/core/lib/infrastructure/remote/dio_remote.dart b/packages/core/lib/infrastructure/remote/dio_remote.dart index 473ca3e..184595a 100644 --- a/packages/core/lib/infrastructure/remote/dio_remote.dart +++ b/packages/core/lib/infrastructure/remote/dio_remote.dart @@ -12,6 +12,7 @@ class DioRemote implements IHttpClient { Future init() async { dio = Dio(BaseOptions(baseUrl: baseUrl ?? '')); if (interceptors != null) { + interceptors!.dio = dio; dio.interceptors.add(interceptors!); } diff --git a/packages/core/lib/injection/di.dart b/packages/core/lib/injection/di.dart index d5bc011..c7bc829 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -1,15 +1,21 @@ -import 'package:get_it/get_it.dart'; import 'package:logger/logger.dart'; -import 'package:rasadyar_core/data/services/auth_middelware.dart'; -import 'package:rasadyar_core/infrastructure/local/hive_local_storage.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; final diCore = GetIt.instance; Future setupAllCoreProvider() async { - await _setUpLogger(); await _setupLocalStorage(); await _setupRemote(); + diCore.registerSingleton(NetworkStatus()..startListening()); + + //max 500MB Map Cashing + await FMTCObjectBoxBackend().initialise(); + + + + await diCore.allReady(); } @@ -23,4 +29,4 @@ Future _setupLocalStorage() async { Future _setupRemote() async { // diCore.registerSingleton(HiveLocalStorage()); -} \ No newline at end of file +} diff --git a/packages/core/lib/presentation/common/app_fonts.dart b/packages/core/lib/presentation/common/app_fonts.dart index 72c1d45..cd31938 100644 --- a/packages/core/lib/presentation/common/app_fonts.dart +++ b/packages/core/lib/presentation/common/app_fonts.dart @@ -166,6 +166,15 @@ class AppFonts { height: _height, ); + + static TextStyle yekan18Bold = TextStyle( + fontFamily: yekan, + fontWeight: bold, // Use bold weight + fontSize: 18.sp, + height: _height, + ); + + static TextStyle yekan16Bold = TextStyle( // Base size bold fontFamily: yekan, diff --git a/packages/core/lib/presentation/common/assets.gen.dart b/packages/core/lib/presentation/common/assets.gen.dart index b349f7c..0ea224c 100644 --- a/packages/core/lib/presentation/common/assets.gen.dart +++ b/packages/core/lib/presentation/common/assets.gen.dart @@ -211,6 +211,24 @@ class $AssetsIconsGen { /// File path: assets/icons/profile_user.svg SvgGenImage get profileUser => const SvgGenImage('assets/icons/profile_user.svg'); + /// File path: assets/icons/rasad_ban.svg + SvgGenImage get rasadBan => const SvgGenImage('assets/icons/rasad_ban.svg'); + + /// File path: assets/icons/rasad_bar.svg + SvgGenImage get rasadBar => const SvgGenImage('assets/icons/rasad_bar.svg'); + + /// File path: assets/icons/rasad_bot.svg + SvgGenImage get rasadBot => const SvgGenImage('assets/icons/rasad_bot.svg'); + + /// File path: assets/icons/rasad_dam.svg + SvgGenImage get rasadDam => const SvgGenImage('assets/icons/rasad_dam.svg'); + + /// File path: assets/icons/rasad_nan.svg + SvgGenImage get rasadNan => const SvgGenImage('assets/icons/rasad_nan.svg'); + + /// File path: assets/icons/rasad_toyor.svg + SvgGenImage get rasadToyor => const SvgGenImage('assets/icons/rasad_toyor.svg'); + /// File path: assets/icons/receipt_discount.svg SvgGenImage get receiptDiscount => const SvgGenImage('assets/icons/receipt_discount.svg'); @@ -339,6 +357,12 @@ class $AssetsIconsGen { profile2Outline, profileCircle, profileUser, + rasadBan, + rasadBar, + rasadBot, + rasadDam, + rasadNan, + rasadToyor, receiptDiscount, sale, scan, @@ -576,6 +600,24 @@ class $AssetsVecGen { /// File path: assets/vec/profile_user.svg.vec SvgGenImage get profileUserSvg => const SvgGenImage.vec('assets/vec/profile_user.svg.vec'); + /// File path: assets/vec/rasad_ban.svg.vec + SvgGenImage get rasadBanSvg => const SvgGenImage.vec('assets/vec/rasad_ban.svg.vec'); + + /// File path: assets/vec/rasad_bar.svg.vec + SvgGenImage get rasadBarSvg => const SvgGenImage.vec('assets/vec/rasad_bar.svg.vec'); + + /// File path: assets/vec/rasad_bot.svg.vec + SvgGenImage get rasadBotSvg => const SvgGenImage.vec('assets/vec/rasad_bot.svg.vec'); + + /// File path: assets/vec/rasad_dam.svg.vec + SvgGenImage get rasadDamSvg => const SvgGenImage.vec('assets/vec/rasad_dam.svg.vec'); + + /// File path: assets/vec/rasad_nan.svg.vec + SvgGenImage get rasadNanSvg => const SvgGenImage.vec('assets/vec/rasad_nan.svg.vec'); + + /// File path: assets/vec/rasad_toyor.svg.vec + SvgGenImage get rasadToyorSvg => const SvgGenImage.vec('assets/vec/rasad_toyor.svg.vec'); + /// File path: assets/vec/receipt_discount.svg.vec SvgGenImage get receiptDiscountSvg => const SvgGenImage.vec('assets/vec/receipt_discount.svg.vec'); @@ -704,6 +746,12 @@ class $AssetsVecGen { profile2OutlineSvg, profileCircleSvg, profileUserSvg, + rasadBanSvg, + rasadBarSvg, + rasadBotSvg, + rasadDamSvg, + rasadNanSvg, + rasadToyorSvg, receiptDiscountSvg, saleSvg, scanSvg, diff --git a/packages/core/lib/presentation/utils/list_extensions.dart b/packages/core/lib/presentation/utils/list_extensions.dart index b97cced..621e529 100644 --- a/packages/core/lib/presentation/utils/list_extensions.dart +++ b/packages/core/lib/presentation/utils/list_extensions.dart @@ -1,4 +1,4 @@ -extension ListExtensions on List { +extension AppListExtensions on List { void toggle(T item) { if (contains(item)) { diff --git a/packages/core/lib/presentation/widget/app_bar/r_app_bar.dart b/packages/core/lib/presentation/widget/app_bar/r_app_bar.dart index e04ebaf..edfeaea 100644 --- a/packages/core/lib/presentation/widget/app_bar/r_app_bar.dart +++ b/packages/core/lib/presentation/widget/app_bar/r_app_bar.dart @@ -11,7 +11,7 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { final TextStyle? titleTextStyle; final VoidCallback? onBackPressed; final List? additionalActions; - final int? leadingWidth; + final double? leadingWidth; final Widget? leading; final PreferredSizeWidget? bottom; @@ -80,3 +80,78 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); } + +class RAppBar2 extends StatelessWidget implements PreferredSizeWidget { + final String? title; + final String? iconTitle; + final Color backgroundColor; + final Color iconColor; + final bool hasBack; + final bool centerTitle; + final TextStyle? titleTextStyle; + final VoidCallback? onBackPressed; + final List? additionalActions; + final double? leadingWidth; + final Widget? leading; + final PreferredSizeWidget? bottom; + + const RAppBar2({ + super.key, + this.title, + this.iconTitle, + this.backgroundColor = AppColor.blueNormal, + this.iconColor = Colors.white, + this.titleTextStyle, + this.onBackPressed, + this.additionalActions, + this.leading, + this.hasBack = true, + this.centerTitle = false, + this.leadingWidth, + this.bottom, + }); + + @override + Widget build(BuildContext context) { + return AppBar( + automaticallyImplyLeading: false, + backgroundColor: backgroundColor, + elevation: 0, + excludeHeaderSemantics: true, + scrolledUnderElevation: 0, + centerTitle: centerTitle, + titleTextStyle: titleTextStyle ?? AppFonts.yekan16.copyWith(color: Colors.white), + title: Row( + children: [ + if (leading != null) ...{ + Padding(padding: const EdgeInsets.only(right: 6), child: leading), + }, + if (title != null) ...[Text(title!), if (iconTitle != null) const SizedBox(width: 8)], + if (iconTitle != null) ...{const SizedBox(width: 8)}, + if (iconTitle != null) ...{SvgGenImage.vec(iconTitle!).svg(width: 24, height: 24)}, + ], + ), + titleSpacing: 8, + actions: [ + if (additionalActions != null) ...additionalActions!, + if (hasBack) ...{ + GestureDetector( + onTap: onBackPressed ?? () => Get.back(), + child: Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 2, 0), + child: Assets.vec.arrowLeftSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode(iconColor ?? Colors.white, BlendMode.srcIn), + ), + ), + ), + }, + ], + bottom: bottom, + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/packages/core/lib/presentation/widget/bottom_navigation/r_bottom_navigation.dart b/packages/core/lib/presentation/widget/bottom_navigation/r_bottom_navigation.dart index d4299bc..fc129e6 100644 --- a/packages/core/lib/presentation/widget/bottom_navigation/r_bottom_navigation.dart +++ b/packages/core/lib/presentation/widget/bottom_navigation/r_bottom_navigation.dart @@ -49,8 +49,11 @@ class RBottomNavigationItem extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - width: 70.w, - height: 70.h, + constraints: BoxConstraints( + minWidth: 70.h, + minHeight: 70.h, + maxHeight: 70.h + ), padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: isSelected ? Colors.white.withAlpha(208) : Colors.transparent, diff --git a/packages/core/lib/presentation/widget/buttons/elevated.dart b/packages/core/lib/presentation/widget/buttons/elevated.dart index 592254b..d28a4b5 100644 --- a/packages/core/lib/presentation/widget/buttons/elevated.dart +++ b/packages/core/lib/presentation/widget/buttons/elevated.dart @@ -18,6 +18,7 @@ class RElevated extends StatelessWidget { this.isFullWidth = false, this.isLoading = false, this.child, + this.enabled = true, }) : assert(text != null || child != null, 'Either text or child must be provided'); final String? text; @@ -33,10 +34,11 @@ class RElevated extends StatelessWidget { final double radius; final TextStyle? textStyle; final bool isLoading; + final bool enabled; @override Widget build(BuildContext context) { - final bool isEnabled = onPressed != null && !isLoading; + final bool isEnabled = enabled && !isLoading; return ElevatedButton( onPressed: isEnabled ? onPressed : null, diff --git a/packages/core/lib/presentation/widget/buttons/outline_elevated.dart b/packages/core/lib/presentation/widget/buttons/outline_elevated.dart index 4d1e629..5e116e4 100644 --- a/packages/core/lib/presentation/widget/buttons/outline_elevated.dart +++ b/packages/core/lib/presentation/widget/buttons/outline_elevated.dart @@ -16,7 +16,8 @@ class ROutlinedElevated extends StatefulWidget { this.child, this.width, this.height, - }):assert(text!=null || child != null, 'Either text or child must be provided'); + this.enabled = true, + }) : assert(text != null || child != null, 'Either text or child must be provided'); final String? text; final VoidCallback? onPressed; @@ -30,6 +31,7 @@ class ROutlinedElevated extends StatefulWidget { double? radius; TextStyle? textStyle; Widget? child; + bool enabled; @override State createState() => _ROutlinedElevatedState(); @@ -73,14 +75,14 @@ class _ROutlinedElevatedState extends State { child: OutlinedButton( key: _widgetKey, statesController: _statesController, - onPressed: widget.onPressed, + onPressed: widget.enabled ? widget.onPressed : null, style: ButtonStyle( side: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.pressed)) { return BorderSide(color: widget.borderColor ?? AppColor.blueNormal, width: 2); } else if (states.contains(WidgetState.disabled)) { return BorderSide( - color: widget.borderColor ?? AppColor.blueNormal.withAlpha(38), + color: widget.borderColor?.disabledColor ?? AppColor.blueNormal.withAlpha(38), width: 2, ); } @@ -103,7 +105,9 @@ class _ROutlinedElevatedState extends State { if (states.contains(WidgetState.pressed)) { return Colors.white; } else if (states.contains(WidgetState.disabled)) { - return AppColor.blueNormal.withAlpha(38); + return widget.foregroundColor?.disabledColor ?? + widget.borderColor?.disabledColor ?? + AppColor.blueNormal.disabledColor; } return widget.foregroundColor ?? widget.borderColor ?? AppColor.blueNormal; }), @@ -115,9 +119,9 @@ class _ROutlinedElevatedState extends State { textStyle: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.pressed)) { return widget.textStyle?.copyWith(color: Colors.white) ?? - AppFonts.yekan20.copyWith(color: Colors.white); + AppFonts.yekan18.copyWith(color: Colors.white); } - return widget.textStyle ?? AppFonts.yekan20.copyWith(color: AppColor.blueNormal); + return widget.textStyle ?? AppFonts.yekan18.copyWith(color: AppColor.blueNormal); }), ), child: widget.child ?? Text(widget.text ?? ''), diff --git a/packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart b/packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart index ca7d2b6..6986431 100644 --- a/packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart +++ b/packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart @@ -7,38 +7,53 @@ class CardIcon extends StatelessWidget { required this.title, required this.icon, this.onTap, + this.titleColor = AppColor.blueNormal, + this.titleStyle, + this.borderColor = AppColor.blueNormal, + this.backgroundColor = Colors.white, + this.borderRadius = 8, + this.width = 110, + this.height = 110, + this.borderWidth = 1, }); final String title; final String icon; final VoidCallback? onTap; + final Color titleColor; + final TextStyle? titleStyle; + + final Color borderColor; + final Color backgroundColor; + final double borderRadius; + final double borderWidth; + + final double width; + final double height; @override Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: const BorderSide(color: AppColor.blueNormal, width: 1), - ), - child: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - color: Colors.white, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgGenImage(icon).svg(width: 50, height: 50), - const SizedBox(height: 8), - Text( - title, - style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal), - ), - ], - ), + return Container( + clipBehavior: Clip.hardEdge, + padding: EdgeInsets.fromLTRB(17.w, 10.h, 17.w, 8.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(borderRadius.r), + color: backgroundColor, + border: Border.all(color: borderColor, width: borderWidth.w), + ), + child: InkWell( + onTap: onTap, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded(child: SvgGenImage(icon).svg(fit: BoxFit.fill)), + SizedBox(height: 10.h), + Text( + title, + textAlign: TextAlign.center, + style: titleStyle ?? AppFonts.yekan16Bold.copyWith(color: titleColor, height: 1.20), + ), + ], ), ), ); diff --git a/packages/core/lib/presentation/widget/list_item/list_item2.dart b/packages/core/lib/presentation/widget/list_item/list_item2.dart index cd62606..bfcc0c8 100644 --- a/packages/core/lib/presentation/widget/list_item/list_item2.dart +++ b/packages/core/lib/presentation/widget/list_item/list_item2.dart @@ -11,6 +11,7 @@ class ExpandableListItem2 extends StatelessWidget { required this.labelIcon, required this.onTap, required this.selected, + this.isTag = false, this.labelIconColor = AppColor.mediumGreyDarkHover, }); @@ -22,6 +23,7 @@ class ExpandableListItem2 extends StatelessWidget { final Color? labelIconColor; final VoidCallback onTap; final bool selected; + final bool isTag; @override Widget build(BuildContext context) { @@ -92,21 +94,40 @@ class ExpandableListItem2 extends StatelessWidget { Positioned( right: -12, - child: Container( - width: index < 999 ? 24 : null, - height: index < 999 ? 24 : null, - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - color: AppColor.greenLightHover, - borderRadius: BorderRadius.circular(4), - border: Border.all(width: 0.50, color: AppColor.greenDarkActive), - ), - alignment: Alignment.center, - child: Text( - (index + 1).toString(), - style: AppFonts.yekan12.copyWith(color: Colors.black), - ), - ), + child: isTag + ? Container( + width: index < 999 ? 24 : 34, + height: index < 999 ? 34 : 34, + alignment: Alignment.center, + child: Stack( + alignment: Alignment.center, + children: [ + Assets.vec.tagLabelSvg.svg(), + Positioned( + top: 15, + child: Text( + (index + 1).toString(), + style: AppFonts.yekan10.copyWith(color: Colors.black), + ), + ) + ], + ), + ) + : Container( + width: index < 999 ? 24 : null, + height: index < 999 ? 24 : null, + padding: EdgeInsets.all(2), + decoration: BoxDecoration( + color: AppColor.greenLightHover, + borderRadius: BorderRadius.circular(4), + border: Border.all(width: 0.50, color: AppColor.greenDarkActive), + ), + alignment: Alignment.center, + child: Text( + (index + 1).toString(), + style: AppFonts.yekan12.copyWith(color: Colors.black), + ), + ), ), ], ), diff --git a/packages/core/lib/presentation/widget/list_view/list_view.dart b/packages/core/lib/presentation/widget/list_view/list_view.dart index 5336777..fac1513 100644 --- a/packages/core/lib/presentation/widget/list_view/list_view.dart +++ b/packages/core/lib/presentation/widget/list_view/list_view.dart @@ -1,3 +1,4 @@ export 'r_shimmer_list.dart'; export 'r_paginated_list_view.dart'; +export 'r_list_view.dart'; diff --git a/packages/core/lib/presentation/widget/list_view/r_list_view.dart b/packages/core/lib/presentation/widget/list_view/r_list_view.dart index 1e62589..b5a8298 100644 --- a/packages/core/lib/presentation/widget/list_view/r_list_view.dart +++ b/packages/core/lib/presentation/widget/list_view/r_list_view.dart @@ -1,12 +1,11 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:rasadyar_core/presentation/widget/list_view/r_paginated_list_view.dart'; import 'package:rasadyar_core/utils/network/resource.dart'; import 'r_shimmer_list.dart'; -enum ListType { builder, separated } - class RListView extends StatelessWidget { final ListType type; final Axis scrollDirection; @@ -68,7 +67,7 @@ class RListView extends StatelessWidget { this.addAutomaticKeepAlives = true, this.addRepaintBoundaries = true, this.addSemanticIndexes = true, - this.loadingWidget = const RShimmerList(isSeparated: true), + this.loadingWidget = const RShimmerList(isSeparated: true), this.emptyWidget = const Center(child: Text("هیچ آیتمی یافت نشد")), this.errorWidget = const Center(child: CircularProgressIndicator()), required this.resource, diff --git a/packages/core/lib/presentation/widget/map/custom_marker.dart b/packages/core/lib/presentation/widget/map/custom_marker.dart deleted file mode 100644 index d1e5cae..0000000 --- a/packages/core/lib/presentation/widget/map/custom_marker.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:latlong2/latlong.dart'; - -class CustomMarker { - final LatLng point; - final VoidCallback? onTap; -final int? id; - - CustomMarker({ this.id, required this.point, this.onTap}); -} \ No newline at end of file diff --git a/packages/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart deleted file mode 100644 index 4204919..0000000 --- a/packages/core/lib/presentation/widget/map/view.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_map/flutter_map.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:get/get.dart'; -import 'package:rasadyar_core/presentation/common/app_color.dart'; -import 'package:rasadyar_core/presentation/common/app_fonts.dart'; -import 'package:rasadyar_core/presentation/common/assets.gen.dart'; -import 'package:rasadyar_core/presentation/widget/buttons/elevated.dart'; -import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; -import 'package:rasadyar_core/presentation/widget/buttons/outline_elevated.dart'; - -import 'logic.dart'; - -class MapWidget extends GetView { - final VoidCallback? initOnTap; - final Widget? initMarkerWidget; - final Widget markerWidget; - - const MapWidget({ - this.initOnTap, - this.initMarkerWidget, - required this.markerWidget, - super.key, - }); - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - ObxValue((errorType) { - if (errorType.isNotEmpty) { - if (errorType.contains(ErrorLocationType.serviceDisabled)) { - Future.microtask(() { - Get.defaultDialog( - title: 'خطا', - content: const Text('سرویس مکان‌یابی غیرفعال است'), - cancel: ROutlinedElevated( - text: 'بررسی مجدد', - width: 120, - textStyle: AppFonts.yekan16, - onPressed: () async { - var service = await controller.locationServiceEnabled(); - if (service) { - controller.errorLocationType.remove( - ErrorLocationType.serviceDisabled, - ); - Get.back(); - } - // Don't call Get.back() if service is still disabled - }, - ), - confirm: RElevated( - text: 'روشن کردن', - textStyle: AppFonts.yekan16, - width: 120, - onPressed: () async { - var res = await Geolocator.openLocationSettings(); - if (res) { - var service = await controller.locationServiceEnabled(); - if (service) { - controller.errorLocationType.remove( - ErrorLocationType.serviceDisabled, - ); - Get.back(); - } - } - }, - ), - contentPadding: EdgeInsets.all(8), - onWillPop: () async { - return controller.errorLocationType.isEmpty; - }, - barrierDismissible: false, - ); - }); - } else { - Future.microtask(() { - Get.defaultDialog( - title: 'خطا', - content: const Text(' دسترسی به سرویس مکان‌یابی غیرفعال است'), - cancel: ROutlinedElevated( - text: 'بررسی مجدد', - width: 120, - textStyle: AppFonts.yekan16, - onPressed: () async { - await controller.checkPermission(); - }, - ), - confirm: RElevated( - text: 'اجازه دادن', - textStyle: AppFonts.yekan16, - width: 120, - onPressed: () async { - var res = await controller.checkPermission(request: true); - if (res) { - controller.errorLocationType.remove( - ErrorLocationType.permissionDenied, - ); - Get.back(); - } - }, - ), - - contentPadding: EdgeInsets.all(8), - onWillPop: () async { - return controller.errorLocationType.isEmpty; - }, - barrierDismissible: false, - ); - }); - } - } - return const SizedBox.shrink(); - }, controller.errorLocationType), - _buildMap(), - _buildGpsButton(), - _buildFilterButton(), - ], - ); - } - - Widget _buildMap() { - return ObxValue((currentLocation) { - return FlutterMap( - mapController: controller.animatedMapController.mapController, - options: MapOptions( - initialCenter: currentLocation.value, - initialZoom: 18, - onPositionChanged: (camera, hasGesture) { - if (hasGesture) { - controller.debouncedUpdateVisibleMarkers(center: camera.center); - } - //controller.debouncedUpdateVisibleMarkers(center: camera.center); - }, - ), - children: [ - TileLayer(urlTemplate: controller.tileType), - ObxValue((markers) { - return MarkerLayer( - markers: - markers - .map( - (e) => Marker( - point: e.point, - child: GestureDetector( - onTap: e.id != -1 ? e.onTap : initOnTap, - child: - e.id != -1 - ? markerWidget - : initMarkerWidget ?? SizedBox.shrink(), - ), - ), - ) - .toList(), - ); - }, controller.markers), - ], - ); - }, controller.currentLocation); - } - - Widget _buildGpsButton() { - return Positioned( - right: 10, - bottom: 83, - child: ObxValue((data) { - return RFab.small( - backgroundColor: AppColor.greenNormal, - isLoading: data.value, - icon: Assets.vec.gpsSvg.svg(), - onPressed: () async { - controller.isLoading.value = true; - await controller.determineCurrentPosition(); - controller.isLoading.value = false; - }, - ); - }, controller.isLoading), - ); - } - - Widget _buildFilterButton() { - return Positioned( - right: 10, - bottom: 30, - child: RFab.small( - backgroundColor: AppColor.blueNormal, - icon: Assets.vec.filterSvg.svg(width: 24, height: 24), - onPressed: () {}, - ), - ); - } - - /*Marker markerWidget({required LatLng marker, required VoidCallback onTap}) { - return Marker( - point: marker, - child: GestureDetector( - onTap: onTap, - behavior: HitTestBehavior.opaque, - child: SizedBox( - width: 36, - height: 36, - child: Assets.vec.mapMarkerSvg.svg(width: 30, height: 30), - ), - ), - ); - }*/ -} diff --git a/packages/core/lib/presentation/widget/marquee/r_marquee.dart b/packages/core/lib/presentation/widget/marquee/r_marquee.dart new file mode 100644 index 0000000..4035a16 --- /dev/null +++ b/packages/core/lib/presentation/widget/marquee/r_marquee.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class RMarquee extends StatefulWidget { + const RMarquee({super.key, required this.text, this.duration = const Duration(seconds: 5)}); + + final String text; + final Duration duration; + + @override + State createState() => _RMarqueeState(); +} + +class _RMarqueeState extends State with SingleTickerProviderStateMixin { + late ScrollController _scrollController; + late double _textWidth; + late double _screenWidth; + + @override + void initState() { + super.initState(); + _scrollController = ScrollController(); + + WidgetsBinding.instance.addPostFrameCallback((_) { + _startScrolling(); + }); + } + + void _startScrolling() async { + while (true) { + await _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: widget.duration, + curve: Curves.linear, + ); + + await _scrollController.animateTo(0, duration: Duration(seconds: 0), curve: Curves.linear); + } + } + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 40, + child: ListView( + controller: _scrollController, + scrollDirection: Axis.horizontal, + children: [ + Text(widget.text, style: AppFonts.yekan16Bold), + SizedBox(width: 50), + ], + ), + ); + } +} diff --git a/packages/core/lib/presentation/widget/slider/logic.dart b/packages/core/lib/presentation/widget/slider/logic.dart new file mode 100644 index 0000000..28ec188 --- /dev/null +++ b/packages/core/lib/presentation/widget/slider/logic.dart @@ -0,0 +1,45 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class SliderLogic extends GetxController with StateMixin> { + final PageController pageController = PageController(initialPage: 0, viewportFraction: .93); + late Timer _timer; + late Duration duration; + + @override + void onInit() { + super.onInit(); + + duration = Duration(seconds: randomInt(8, 18)); + } + + void _startSliding(int itemCount) { + _timer = Timer.periodic(duration, (timer) { + if (pageController.hasClients) { + int nextPage = pageController.page!.round() + 1; + if (nextPage == itemCount) { + nextPage = 0; + } + pageController.animateToPage( + nextPage, + duration: Duration(milliseconds: 300), + curve: Curves.easeIn, + ); + } + }); + } + + @override + void onClose() { + _timer.cancel(); + pageController.dispose(); + super.onClose(); + } + + void onSuccess(List data) { + change(data, status: RxStatus.success()); + _startSliding(data.length); + } +} diff --git a/packages/core/lib/presentation/widget/slider/slider.dart b/packages/core/lib/presentation/widget/slider/slider.dart new file mode 100644 index 0000000..fe087c2 --- /dev/null +++ b/packages/core/lib/presentation/widget/slider/slider.dart @@ -0,0 +1,2 @@ +export 'logic.dart'; +export 'view.dart'; \ No newline at end of file diff --git a/packages/core/lib/presentation/widget/slider/view.dart b/packages/core/lib/presentation/widget/slider/view.dart new file mode 100644 index 0000000..a7c22de --- /dev/null +++ b/packages/core/lib/presentation/widget/slider/view.dart @@ -0,0 +1,86 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class SliderWidget extends GetView { + const SliderWidget({super.key, this.height = 210, this.widgetTag}); + + final int height; + final String? widgetTag; + + @override + String? get tag => widgetTag; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: height.h, + child: controller.obx( + (state) => Stack( + alignment: AlignmentDirectional.bottomCenter, + fit: StackFit.expand, + children: [ + Positioned.fill( + child: PageView.builder( + controller: controller.pageController, + itemCount: state?.length ?? 0, + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + String? image = state?[index]; + return Container( + height: height.h, + margin: EdgeInsets.symmetric(horizontal: 6.w), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.r)), + clipBehavior: Clip.hardEdge, + child: CachedNetworkImage( + imageUrl: image ?? '', + fit: BoxFit.cover, + placeholder: (context, url) => const Center( + child: CupertinoActivityIndicator(color: AppColor.blueNormal), + ), + errorWidget: (context, url, error) => const Center(child: Icon(Icons.error)), + ), + ); + }, + ), + ), + Visibility( + visible: (state?.length ?? 0) > 1, + child: Positioned( + bottom: 5, + child: Container( + height: 13.36, + padding: const EdgeInsets.symmetric(horizontal: 8), + margin: const EdgeInsets.symmetric(vertical: 12), + decoration: ShapeDecoration( + color: Colors.white38, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(9999)), + ), + child: SmoothPageIndicator( + controller: controller.pageController, // PageController + count: state?.length ?? 0, + effect: const WormEffect( + dotWidth: 6.0, + dotHeight: 6.0, + activeDotColor: Colors.white, + dotColor: Colors.white38, + ), // your preferred effect + onDotClicked: (index) { + controller.pageController.animateToPage( + index, + duration: const Duration(milliseconds: 500), + curve: Curves.easeIn, + ); + }, + ), + ), + ), + ), + ], + ), + onLoading: const Center(child: CupertinoActivityIndicator(color: AppColor.blueNormal)), + onError: (error) => Center(child: Text('خطا در بارگذاری اسلایدر: $error')), + ), + ); + } +} diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 9a8b1a3..2564871 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -22,6 +22,9 @@ export 'list_item/list_item_with_out_number.dart'; export 'list_row_item.dart'; export 'list_view/list_view.dart'; export 'loading_widget.dart'; +// other +export 'logo_widget.dart'; +export 'marquee/r_marquee.dart'; export 'overlay_dropdown_widget/view.dart'; export 'pagination/pagination_from_until.dart'; export 'pagination/show_more.dart'; @@ -29,6 +32,4 @@ export 'tabs/new_tab.dart'; export 'tabs/r_segment.dart'; export 'tabs/tab.dart'; export 'vec_widget.dart'; - -// other -export 'logo_widget.dart'; +export 'slider/slider.dart'; \ No newline at end of file diff --git a/packages/core/lib/utils/file_utils.dart b/packages/core/lib/utils/file_utils.dart new file mode 100644 index 0000000..3bb6cb3 --- /dev/null +++ b/packages/core/lib/utils/file_utils.dart @@ -0,0 +1,10 @@ +import 'dart:io'; + +import 'logger_utils.dart'; + +void getFileSizeInKB(String filePath, {String? tag}) { + final file = File(filePath); + final bytes = file.lengthSync(); + var size = (bytes / 1024).ceil(); + iLog('${tag ?? 'Picked'} image Size: $size'); +} \ No newline at end of file diff --git a/packages/core/lib/utils/local/local_utils.dart b/packages/core/lib/utils/local/local_utils.dart index 04f3e5d..d6cf456 100644 --- a/packages/core/lib/utils/local/local_utils.dart +++ b/packages/core/lib/utils/local/local_utils.dart @@ -4,4 +4,12 @@ const int authModuleTypeId = 1; //chicken const int chickenWidelyUsedLocalModelTypeId = 2; -const int chickenWidelyUsedLocalItemTypeId = 3; \ No newline at end of file +const int chickenWidelyUsedLocalItemTypeId = 3; + +//liveStock + +const int liveStockDataLocalModelTypeId = 4; +const int liveStockDataRancherLocalModelTypeId = 5; +const int liveStockDataHerdLocalModelTypeId = 6; +const int liveStockDataLocationLocalModelTypeId = 7; +const int liveStockDataLivestockLocalModelTypeId = 8; \ No newline at end of file diff --git a/packages/core/lib/utils/network/safe_call_utils.dart b/packages/core/lib/utils/network/safe_call_utils.dart index 18588b6..0c2b117 100644 --- a/packages/core/lib/utils/network/safe_call_utils.dart +++ b/packages/core/lib/utils/network/safe_call_utils.dart @@ -1,16 +1,21 @@ import 'package:flutter/material.dart'; import '../../core.dart'; - +/// Handles global API requests management with CancelToken. class ApiHandler { + // Global CancelToken for all requests. static CancelToken _globalCancelToken = CancelToken(); + /// Returns the current global CancelToken. static CancelToken get globalCancelToken => _globalCancelToken; + /// Resets the global CancelToken to a new one. static Future reset() async { _globalCancelToken = CancelToken(); } + /// Cancels all ongoing requests and resets the CancelToken. + /// [reason] is optional text explaining why requests are canceled. static void cancelAllRequests(String reason) { if (!_globalCancelToken.isCancelled) { _globalCancelToken.cancel(reason); diff --git a/packages/core/lib/utils/number_utils.dart b/packages/core/lib/utils/number_utils.dart new file mode 100644 index 0000000..c44012f --- /dev/null +++ b/packages/core/lib/utils/number_utils.dart @@ -0,0 +1,13 @@ +import 'dart:math'; + +final _random = Random(); + + +int randomInt(int min, int max) { + return min + _random.nextInt(max - min + 1); +} + + +double randomDouble(double min, double max) { + return min + _random.nextDouble() * (max - min); +} \ No newline at end of file diff --git a/packages/core/lib/utils/utils.dart b/packages/core/lib/utils/utils.dart index ba7f6b2..cbb70e5 100644 --- a/packages/core/lib/utils/utils.dart +++ b/packages/core/lib/utils/utils.dart @@ -2,6 +2,7 @@ export 'apk_updater.dart'; export 'extension/date_time_utils.dart'; export 'extension/num_utils.dart'; export 'extension/string_utils.dart'; +export 'file_utils.dart'; export 'local/local_utils.dart'; export 'logger_utils.dart'; export 'map_utils.dart'; @@ -10,3 +11,4 @@ export 'network/network.dart'; export 'parser.dart'; export 'route_utils.dart'; export 'separator_input_formatter.dart'; +export 'number_utils.dart'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index 9eea597..c191946 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: "direct main" description: name: android_intent_plus - sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.1" animated_stack_widget: dependency: transitive description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build - sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4" + sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -101,26 +101,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2" + sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d + sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62 + sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.3.0" built_collection: dependency: transitive description: @@ -133,10 +133,34 @@ packages: dependency: transitive description: name: built_value - sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62" + sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb url: "https://pub.dev" source: hosted - version: "8.11.0" + version: "8.11.1" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" characters: dependency: transitive description: @@ -153,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.4" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" clock: dependency: transitive description: @@ -170,7 +202,7 @@ packages: source: hosted version: "4.10.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" @@ -185,6 +217,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -193,6 +241,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" cross_file: dependency: transitive description: @@ -269,10 +325,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 url: "https://pub.dev" source: hosted - version: "5.8.0+1" + version: "5.9.0" dio_web_adapter: dependency: transitive description: @@ -325,10 +381,10 @@ packages: dependency: transitive description: name: file_selector_macos - sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" + sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c" url: "https://pub.dev" source: hosted - version: "0.9.4+3" + version: "0.9.4+4" file_selector_platform_interface: dependency: transitive description: @@ -353,11 +409,27 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flat_buffers: + dependency: transitive + description: + name: flat_buffers + sha256: "380bdcba5664a718bfd4ea20a45d39e13684f5318fcd8883066a55e21f37f4c3" + url: "https://pub.dev" + source: hosted + version: "23.5.26" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_gen_core: dependency: transitive description: @@ -419,14 +491,22 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + flutter_map_tile_caching: + dependency: "direct main" + description: + name: flutter_map_tile_caching + sha256: "1839c6157cf9b444083a626b30f3ba9f6db802ac8bb5292440e1628882faa392" + url: "https://pub.dev" + source: hosted + version: "10.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e + sha256: b0694b7fb1689b0e6cc193b3f1fcac6423c4f93c74fb20b806c6b6f196db0c31 url: "https://pub.dev" source: hosted - version: "2.0.28" + version: "2.0.30" flutter_rating_bar: dependency: "direct main" description: @@ -495,10 +575,10 @@ packages: dependency: "direct main" description: name: flutter_slidable - sha256: ab7dbb16f783307c9d7762ede2593ce32c220ba2ba0fd540a3db8e9a3acba71a + sha256: e6bd17290cf0d011f9ed66c74d4159b8fe3b3050afedac0f11fab1ba8687e710 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" flutter_svg: dependency: "direct main" description: @@ -517,14 +597,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" - description: - name: font_awesome_flutter - sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a - url: "https://pub.dev" - source: hosted - version: "10.8.0" freezed: dependency: "direct dev" description: @@ -625,10 +697,10 @@ packages: dependency: "direct main" description: name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.2.0" get_test: dependency: "direct dev" description: @@ -681,10 +753,10 @@ packages: dependency: "direct main" description: name: hive_ce_flutter - sha256: a0989670652eab097b47544f1e5a4456e861b1b01b050098ea0b80a5fabe9909 + sha256: f5bd57fda84402bca7557fedb8c629c96c8ea10fab4a542968d7b60864ca02cc url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" hive_ce_generator: dependency: "direct dev" description: @@ -697,10 +769,10 @@ packages: dependency: transitive description: name: http - sha256: "85ab0074f9bf2b24625906d8382bbec84d3d6919d285ba9c106b07b65791fb99" + sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 url: "https://pub.dev" source: hosted - version: "1.5.0-beta.2" + version: "1.5.0" http_multi_server: dependency: transitive description: @@ -725,78 +797,102 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + image_cropper: + dependency: "direct main" + description: + name: image_cropper + sha256: "4e9c96c029eb5a23798da1b6af39787f964da6ffc78fd8447c140542a9f7c6fc" + url: "https://pub.dev" + source: hosted + version: "9.1.0" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: fd81ebe36f636576094377aab32673c4e5d1609b32dec16fad98d2b71f1250a9 + url: "https://pub.dev" + source: hosted + version: "6.1.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: "6ca6b81769abff9a4dcc3bbd3d75f5dfa9de6b870ae9613c8cd237333a4283af" + url: "https://pub.dev" + source: hosted + version: "7.1.0" image_picker: dependency: "direct main" description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e" url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13+1" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: name: image_size_getter - sha256: "9a299e3af2ebbcfd1baf21456c3c884037ff524316c97d8e56035ea8fdf35653" + sha256: "7c26937e0ae341ca558b7556591fd0cc456fcc454583b7cb665d2f03e93e590f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" intl: dependency: "direct main" description: @@ -841,10 +937,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: ce2cf974ccdee13be2a510832d7fba0b94b364e0b0395dee42abaa51b855be27 + sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd" url: "https://pub.dev" source: hosted - version: "6.10.0" + version: "6.11.0" latlong2: dependency: "direct main" description: @@ -857,26 +953,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -981,6 +1077,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + objectbox: + dependency: transitive + description: + name: objectbox + sha256: "25c2e24b417d938decb5598682dc831bc6a21856eaae65affbc57cfad326808d" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + objectbox_flutter_libs: + dependency: transitive + description: + name: objectbox_flutter_libs + sha256: "574b0233ba79a7159fca9049c67974f790a2180b6141d4951112b20bd146016a" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" package_config: dependency: transitive description: @@ -993,18 +1129,18 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.3.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" path: dependency: transitive description: @@ -1033,18 +1169,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" url: "https://pub.dev" source: hosted - version: "2.2.17" + version: "2.2.18" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" path_provider_linux: dependency: transitive description: @@ -1121,18 +1257,18 @@ packages: dependency: "direct main" description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "7.0.1" platform: dependency: transitive description: @@ -1201,10 +1337,10 @@ packages: dependency: transitive description: name: provider - sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" url: "https://pub.dev" source: hosted - version: "6.1.5" + version: "6.1.5+1" pub_semver: dependency: transitive description: @@ -1245,6 +1381,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" shelf_web_socket: dependency: transitive description: @@ -1266,22 +1418,46 @@ packages: description: flutter source: sdk version: "0.0.0" + smooth_page_indicator: + dependency: "direct main" + description: + name: smooth_page_indicator + sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c + url: "https://pub.dev" + source: hosted + version: "1.2.1" source_gen: dependency: transitive description: name: source_gen - sha256: fc787b1f89ceac9580c3616f899c9a447413cbdac1df071302127764c023a134 + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" source_helper: dependency: transitive description: name: source_helper - sha256: "4f81479fe5194a622cdd1713fe1ecb683a6e6c85cd8cec8e2e35ee5ab3fdf2a1" + sha256: a447acb083d3a5ef17f983dd36201aeea33fedadb3228fa831f2f0c92f0f3aca url: "https://pub.dev" source: hosted - version: "1.3.6" + version: "1.3.7" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" source_span: dependency: transitive description: @@ -1298,6 +1474,46 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -1330,6 +1546,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" term_glyph: dependency: transitive description: @@ -1338,14 +1562,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" + url: "https://pub.dev" + source: hosted + version: "1.26.2" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" + test_core: + dependency: transitive + description: + name: test_core + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" + url: "https://pub.dev" + source: hosted + version: "0.6.11" time: dependency: transitive description: @@ -1406,34 +1646,34 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" + sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc url: "https://pub.dev" source: hosted - version: "1.1.17" + version: "1.1.19" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "15.0.2" watcher: dependency: transitive description: name: watcher - sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" + sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" web: dependency: transitive description: @@ -1458,6 +1698,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: @@ -1494,10 +1742,10 @@ packages: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.6.1" yaml: dependency: transitive description: @@ -1515,5 +1763,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index f87b92b..8cac455 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none version: 1.2.0+2 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: @@ -14,18 +14,19 @@ dependencies: #utils device_info_plus: ^11.5.0 - package_info_plus: ^8.3.0 + package_info_plus: ^8.3.1 ##image_picker - image_picker: ^1.1.2 - + image_picker: ^1.2.0 + image_cropper: ^9.1.0 #UI cupertino_icons: ^1.0.8 - flutter_slidable: ^4.0.0 + flutter_slidable: ^4.0.1 flutter_rating_bar: ^4.0.1 lottie: ^3.3.1 flutter_screenutil: ^5.9.3 + smooth_page_indicator: ^1.2.1 ##Log logger: ^2.6.1 @@ -42,7 +43,8 @@ dependencies: #SVG flutter_svg: ^2.2.0 - font_awesome_flutter: ^10.8.0 + cached_network_image: ^3.4.1 + #Shimmer shimmer: ^3.0.0 @@ -54,28 +56,32 @@ dependencies: get: ^4.7.2 ##Di - get_it: ^8.0.3 + get_it: ^8.2.0 #other permission_handler: ^12.0.1 - persian_datetime_picker: ^3.1.0 + persian_datetime_picker: ^3.1.1 encrypt: ^5.0.3 + collection: ^1.19.1 #L10N tools intl: ^0.20.2 #INITENT - android_intent_plus: ^5.3.0 + android_intent_plus: ^5.3.1 #Map flutter_map: ^7.0.0 flutter_map_animations: ^0.8.0 flutter_map_marker_cluster: ^1.4.0 + flutter_map_tile_caching: ^10.0.0 + #location latlong2: ^0.9.1 geolocator: ^14.0.2 #network - dio: ^5.8.0+1 + dio: ^5.9.0 + connectivity_plus: ^6.1.5 #networkLogger pretty_dio_logger: ^1.4.0 @@ -88,10 +94,11 @@ dev_dependencies: sdk: flutter flutter_lints: ^6.0.0 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 - json_serializable: ^6.10.0 + json_serializable: ^6.11.0 + test: ^1.24.0 ##test diff --git a/packages/core/test/infrastructure/remote/app_interceptor_test.dart b/packages/core/test/infrastructure/remote/app_interceptor_test.dart new file mode 100644 index 0000000..b0bd2bf --- /dev/null +++ b/packages/core/test/infrastructure/remote/app_interceptor_test.dart @@ -0,0 +1,106 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:rasadyar_core/infrastructure/remote/app_interceptor_n.dart'; + +class MockDio extends Mock implements Dio {} + +class MockResponse extends Mock implements Response {} + +class MockRequestOptions extends Mock implements RequestOptions {} + + +class FakeRequestOptions extends Fake implements RequestOptions {} + + +void main() { + late MockDio dio; + late AppInterceptorN interceptor; + late MockResponse response; + late MockRequestOptions requestOptions; + + late bool saveCalled; + late bool clearCalled; + late bool refreshFailedCalled; + String? savedToken; + + setUp(() { + dio = MockDio(); + response = MockResponse(); + requestOptions = MockRequestOptions(); + + saveCalled = false; + clearCalled = false; + refreshFailedCalled = false; + savedToken = null; + interceptor = AppInterceptorN( + dio: dio, + saveTokenCallback: (token) async { + savedToken = token; + saveCalled = true; + }, + clearTokenCallback: () async { + clearCalled = true; + }, + refreshTokenCallback: () async => 'newToken', + onRefreshFailed: () async { + refreshFailedCalled = true; + }, + ); + }); + + setUpAll(() { + registerFallbackValue(FakeRequestOptions()); + }); + + + + test('should refresh token and retry queued requests on 401', () async { + final options = RequestOptions(path: "/test"); + final response = Response(requestOptions: options, statusCode: 200, data: 'ok'); + when(() => dio.fetch(any())).thenAnswer((_) async => response); + final handler = ErrorInterceptorHandler(); + final dioException = DioException( + requestOptions: options, + response: Response(requestOptions: options, statusCode: 401), + type: DioExceptionType.badResponse, + ); + await interceptor.onError(dioException, handler); + expect(saveCalled, isTrue); + expect(savedToken, 'newToken'); + expect(interceptor.queue.isEmpty, isTrue); + expect(clearCalled, isFalse); + expect(refreshFailedCalled, isFalse); + }); + + + test('should queue request if refreshing', () async { + interceptor.isRefreshingForTest = true; + final options = RequestOptions(path: "/test"); + final handler = RequestInterceptorHandler(); + final completer = Completer(); + interceptor.queue.add(QueuedRequest(options, completer)); + interceptor.onRequest(options, handler); + expect(interceptor.queue.length, 2); // One added in setUp, one here + }); + + test('should refresh token and retry queued requests on 401', () async { + final options = RequestOptions(path: "/test"); + final response = Response(requestOptions: options, statusCode: 200, data: 'ok'); + when(() => dio.fetch(any())).thenAnswer((_) async => response); + final handler = ErrorInterceptorHandler(); + final dioException = DioException( + requestOptions: options, + response: Response(requestOptions: options, statusCode: 401), + type: DioExceptionType.badResponse, + ); + await interceptor.onError(dioException, handler); + expect(saveCalled, isTrue); + expect(savedToken, 'newToken'); + expect(interceptor.queue.isEmpty, isTrue); + expect(clearCalled, isFalse); + expect(refreshFailedCalled, isFalse); + }); +} diff --git a/packages/core/test/infrastructure/remote/dio_form_data.dart b/packages/core/test/infrastructure/remote/dio_form_data.dart deleted file mode 100644 index 8e74832..0000000 --- a/packages/core/test/infrastructure/remote/dio_form_data.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; - -import 'interfaces/i_form_data.dart'; - -class DioFormData implements IFormData { - final FormData _formData = FormData(); - - @override - void addFile(String field, Uint8List bytes, String filename) { - _formData.files.add(MapEntry( - field, - MultipartFile.fromBytes(bytes, filename: filename), - )); - } - - @override - void addField(String key, String value) { - _formData.fields.add(MapEntry(key, value)); - } - - FormData get raw => _formData; -} diff --git a/packages/core/test/infrastructure/remote/dio_form_data_test.dart b/packages/core/test/infrastructure/remote/dio_form_data_test.dart new file mode 100644 index 0000000..a25d9da --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_form_data_test.dart @@ -0,0 +1,55 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/core.dart'; + +void main() { + group('DioFormData', () { + late DioFormData formData; + + setUp(() { + formData = DioFormData(); + }); + + test('addField should add a field to FormData', () { + formData.addField('userName', 'mojtaba'); + expect(formData.raw.fields.length, 1); + expect(formData.raw.fields.first.key, 'userName'); + expect(formData.raw.fields.first.value, 'mojtaba'); + }); + + test('addFile should add a file to FormData', () async { + final bytes = Uint8List.fromList([1, 2, 3, 4]); + formData.addFile('fileField', bytes, 'test.txt'); + + expect(formData.raw.files.length, 1); + + final fileEntry = formData.raw.files.first; + expect(fileEntry.key, 'fileField'); + + final multipart = fileEntry.value; + expect(multipart.filename, 'test.txt'); + + final uploadedBytes = await multipart.finalize().toBytes(); + expect(uploadedBytes, bytes); + + }); + + test('raw getter should return the internal FormData instance', () { + final tmp = formData.raw; + expect(tmp, isA()); + }); + + + }); +} + +extension on Stream> { + /// Helper to collect stream into a single Uint8List for comparison + Future toBytes() async { + final chunks = []; + await for (final chunk in this) { + chunks.addAll(chunk); + } + return Uint8List.fromList(chunks); + } +} diff --git a/packages/core/test/infrastructure/remote/dio_remote_test.dart b/packages/core/test/infrastructure/remote/dio_remote_test.dart index e69de29..e3b62e1 100644 --- a/packages/core/test/infrastructure/remote/dio_remote_test.dart +++ b/packages/core/test/infrastructure/remote/dio_remote_test.dart @@ -0,0 +1,201 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:rasadyar_core/core.dart'; + +class MockDio extends Mock implements Dio {} + +class MockInterceptor extends Mock implements AppInterceptor {} + +class FakeRequestOptions extends Fake implements RequestOptions {} + +void main() { + setUpAll(() { + registerFallbackValue(FakeRequestOptions()); + registerFallbackValue(RequestOptions(path: '')); + registerFallbackValue(Options()); + registerFallbackValue(CancelToken()); + }); + + group('Dio Remote', () { + late DioRemote dioRemote; + late MockDio mockDio; + + setUp(() { + mockDio = MockDio(); + dioRemote = DioRemote(); + dioRemote.dio = mockDio; + }); + + test('init sets dio and adds interceptor if provided', () async { + final interceptor = MockInterceptor(); + + final client = DioRemote(interceptors: interceptor); + await client.init(); + + expect(client.dio, isA()); + + }); + + test('get returns DioResponse with raw data', () async { + final response = Response( + requestOptions: RequestOptions(path: '/test'), + statusCode: 200, + data: {'message': 'ok'}, + ); + when( + () => mockDio.get( + any(), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.get>('/test'); + + expect(result, isA>>()); + expect(result.data, {'message': 'ok'}); + expect(result.statusCode, 200); + }); + + test('get applies fromJson mapper', () async { + final response = Response( + requestOptions: RequestOptions(path: '/user'), + statusCode: 200, + data: {'id': 1, 'name': 'Ali'}, + ); + when( + () => mockDio.get( + any(), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.get( + '/user', + fromJson: (json) => "User: ${json['name']}", + ); + + expect(result.data, 'User: Ali'); + }); + + test('post applies fromJson correctly', () async { + final response = Response( + requestOptions: RequestOptions(path: '/post'), + statusCode: 200, + data: {'id': 99}, + ); + when( + () => mockDio.post( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.post( + '/post', + fromJson: (json) => json['id'], + ); + + expect(result.data, 99); + }); + + test('put returns parsed data', () async { + final response = Response( + requestOptions: RequestOptions(path: '/put'), + statusCode: 200, + data: {'value': 'updated'}, + ); + when( + () => mockDio.put( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.put('/put', fromJson: (json) => json['value']); + + expect(result.data, 'updated'); + }); + + test('delete works with fromJson', () async { + final response = Response( + requestOptions: RequestOptions(path: '/delete'), + statusCode: 200, + data: {'removed': true}, + ); + when( + () => mockDio.delete( + any(), + data: any(named: 'data'), + queryParameters: any(named: 'queryParameters'), + options: any(named: 'options'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.delete('/delete', fromJson: (json) => json['removed']); + + expect(result.data, true); + }); + + test('download returns DioResponse with bytes', () async { + final response = Response( + requestOptions: RequestOptions(path: '/download'), + statusCode: 200, + data: Uint8List.fromList([1, 2, 3]), + ); + when( + () => mockDio.get( + any(), + options: any(named: 'options'), + onReceiveProgress: any(named: 'onReceiveProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.download('/download'); + + expect(result.data, isA()); + expect(result.data!.length, 3); + }); + + test('upload sends DioFormData and returns DioResponse', () async { + final formData = DioFormData(); + formData.addField('field', 'value'); + final response = Response( + requestOptions: RequestOptions(path: '/upload'), + statusCode: 200, + data: 'uploaded', + ); + when( + () => mockDio.post( + any(), + data: any(named: 'data'), + options: any(named: 'options'), + onSendProgress: any(named: 'onSendProgress'), + cancelToken: any(named: 'cancelToken'), + ), + ).thenAnswer((_) async => response); + + final result = await dioRemote.upload('/upload', formData: formData); + + expect(result.data, 'uploaded'); + }); + }); +} diff --git a/packages/core/test/infrastructure/remote/dio_response.dart b/packages/core/test/infrastructure/remote/dio_response.dart deleted file mode 100644 index 30f54eb..0000000 --- a/packages/core/test/infrastructure/remote/dio_response.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'interfaces/i_http_response.dart'; -import 'package:dio/dio.dart'; - -class DioResponse implements IHttpResponse { - final Response _response; - - DioResponse(this._response); - - @override - T? get data => _response.data; - - @override - int get statusCode => _response.statusCode ?? 0; - - @override - Map? get headers => _response.headers.map; - - @override - bool get isSuccessful => statusCode >= 200 && statusCode < 300; -} diff --git a/packages/core/test/infrastructure/remote/dio_response_test.dart b/packages/core/test/infrastructure/remote/dio_response_test.dart new file mode 100644 index 0000000..7d68452 --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_response_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/core.dart'; + +void main() { + group('DioResponse', () { + test('data should return response data', () { + final response = Response( + requestOptions: RequestOptions(path: "/"), + data: 'hello', + ); + + final dioResponse = DioResponse(response); + + expect(dioResponse.data, 'hello'); + }); + + test('status Code should return 0 if null', () { + final response = Response(requestOptions: RequestOptions(path: "/"), statusCode: null); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 0); + }); + + test('headers should return response headers map', () { + final headers = Headers.fromMap({ + 'content-type': ['application/json'], + }); + final response = Response( + requestOptions: RequestOptions(path: "/"), + headers: headers, + ); + final dioResponse = DioResponse(response); + + expect(dioResponse.headers, isA()); + expect(dioResponse.headers, { + 'content-type': ['application/json'], + }); + }); + + test('isSuccessful should return true for 2xx codes', () { + final response = Response(requestOptions: RequestOptions(path: "/"), statusCode: 200); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 200); + + expect(dioResponse.isSuccessful, true); + }); + + test('isSuccessful should return false for non-2xx codes', () { + final response = Response(requestOptions: RequestOptions(path: "/"),statusCode: 404); + final dioResponse = DioResponse(response); + + expect(dioResponse.statusCode, 404); + + expect(dioResponse.isSuccessful, false); + + }); + + }); +} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart b/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart deleted file mode 100644 index ddbda85..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:flutter/foundation.dart'; - -abstract class IFormData{ - void addFile(String field, Uint8List bytes, String filename); - void addField(String key, String value); -} \ No newline at end of file diff --git a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart deleted file mode 100644 index 3e6327c..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart +++ /dev/null @@ -1,53 +0,0 @@ - -import 'package:dio/dio.dart'; -import 'i_form_data.dart'; -import 'i_http_response.dart'; - -abstract class IHttpClient { - Future init(); - - Future> get( - String path, { - Map? queryParameters, - Map? headers, - ProgressCallback? onReceiveProgress, - }); - - - Future> post( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - ProgressCallback? onSendProgress, - ProgressCallback? onReceiveProgress, - }); - - Future> put( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - ProgressCallback? onSendProgress, - ProgressCallback? onReceiveProgress, - }); - - Future> delete( - String path, { - dynamic data, - Map? queryParameters, - Map? headers, - }); - - Future> download( - String url, { - ProgressCallback? onReceiveProgress, - }); - - Future> upload( - String path, { - required IFormData formData, - Map? headers, - ProgressCallback? onSendProgress, - }); -} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart b/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart deleted file mode 100644 index 461146a..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart +++ /dev/null @@ -1,6 +0,0 @@ -abstract class IHttpResponse { - T? get data; - int get statusCode; - Map? get headers; - bool get isSuccessful; -} diff --git a/packages/core/test/infrastructure/remote/interfaces/i_remote.dart b/packages/core/test/infrastructure/remote/interfaces/i_remote.dart deleted file mode 100644 index 648883b..0000000 --- a/packages/core/test/infrastructure/remote/interfaces/i_remote.dart +++ /dev/null @@ -1,4 +0,0 @@ -abstract class IRemote{ - Future init(); -} - diff --git a/packages/inspection/.gitignore b/packages/inspection/.gitignore new file mode 100644 index 0000000..c40e34e --- /dev/null +++ b/packages/inspection/.gitignore @@ -0,0 +1,4 @@ +.dart_tool +*.lock +.flutter-plugins-dependencies +.flutter-plugins \ No newline at end of file diff --git a/packages/inspection/devtools_options.yaml b/packages/inspection/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/packages/inspection/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/packages/inspection/lib/injection/inspection_di.dart b/packages/inspection/lib/injection/inspection_di.dart index 456896e..b266b78 100644 --- a/packages/inspection/lib/injection/inspection_di.dart +++ b/packages/inspection/lib/injection/inspection_di.dart @@ -30,21 +30,20 @@ Future setupInspectionDI() async { }, authArguments: Module.inspection, ), - instanceName: 'inspectionInterceptor', ); diInspection.registerLazySingleton(() { return DioRemote( baseUrl: tokenService.baseurl.value, - interceptors: diInspection.get(instanceName: 'inspectionInterceptor'), + interceptors: diInspection.get(), ); - }, instanceName: 'inspectionDioRemote'); + }); - var dioRemote = diInspection.get(instanceName: 'inspectionDioRemote'); + var dioRemote = diInspection.get(); await dioRemote.init(); diInspection.registerLazySingleton( - () => AuthRemoteImp(diInspection.get(instanceName: 'inspectionDioRemote')), + () => AuthRemoteImp(dioRemote), ); diInspection.registerSingleton( @@ -52,7 +51,7 @@ Future setupInspectionDI() async { ); diInspection.registerSingleton( - UserRemoteDataSourceImp(diInspection.get(instanceName: 'inspectionDioRemote')), + UserRemoteDataSourceImp(dioRemote), ); diInspection.registerSingleton( @@ -60,7 +59,7 @@ Future setupInspectionDI() async { ); diInspection.registerSingleton( - InspectionRemoteDataSourceImp(diInspection.get(instanceName: 'inspectionDioRemote')), + InspectionRemoteDataSourceImp(dioRemote), ); diInspection.registerSingleton( @@ -69,3 +68,37 @@ Future setupInspectionDI() async { diInspection.registerSingleton(ImagePicker()); } + + +Future removeInspectionDI() async { + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } + if (diInspection.isRegistered()) { + diInspection.unregister(); + } +} diff --git a/packages/inspection/lib/presentation/pages/auth/logic.dart b/packages/inspection/lib/presentation/pages/auth/logic.dart index 3d3bc58..6b1cfc0 100644 --- a/packages/inspection/lib/presentation/pages/auth/logic.dart +++ b/packages/inspection/lib/presentation/pages/auth/logic.dart @@ -22,7 +22,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { late AnimationController _textAnimationController; late Animation textAnimation; RxBool showCard = false.obs; - + RxBool rememberMe = false.obs; Rx> formKeyOtp = GlobalKey().obs; Rx> formKeySentOtp = GlobalKey().obs; Rx usernameController = TextEditingController().obs; @@ -127,6 +127,16 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { await tokenStorageService.saveModule(_module); await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); await tokenStorageService.saveAccessToken(result?.access ?? ''); + if (rememberMe.value) { + await tokenStorageService.saveUserPass( + UserLocalModel( + username: usernameController.value.text, + password: passwordController.value.text, + module: _module, + ), + ); + } + Get.offAllNamed(InspectionRoutes.init); }, onError: (error, stackTrace) { diff --git a/packages/inspection/lib/presentation/pages/auth/view.dart b/packages/inspection/lib/presentation/pages/auth/view.dart index 6ab8612..b0c6431 100644 --- a/packages/inspection/lib/presentation/pages/auth/view.dart +++ b/packages/inspection/lib/presentation/pages/auth/view.dart @@ -2,6 +2,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_inspection/presentation/widget/captcha/view.dart'; + import 'logic.dart'; class AuthPage extends GetView { @@ -12,40 +13,40 @@ class AuthPage extends GetView { return Scaffold( body: Stack( alignment: Alignment.center, + fit: StackFit.expand, children: [ Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: FadeTransition( - opacity: controller.textAnimation, - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 12, - children: [ - Text( - 'به سامانه رصدیار خوش آمدید!', - textAlign: TextAlign.right, - style: AppFonts.yekan25Bold.copyWith(color: Colors.white), - ), - Text( - 'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی', - textAlign: TextAlign.center, - style: AppFonts.yekan16.copyWith(color: Colors.white), - ), - ], + Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: FadeTransition( + opacity: controller.textAnimation, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 12, + children: [ + Text( + 'به سامانه رصدیار خوش آمدید!', + textAlign: TextAlign.right, + style: AppFonts.yekan25Bold.copyWith(color: Colors.white), + ), + Text( + 'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith(color: Colors.white), + ), + ], + ), ), ), ), Obx(() { - final screenHeight = MediaQuery - .of(context) - .size - .height; + final screenHeight = MediaQuery.of(context).size.height; final targetTop = (screenHeight - 676) / 2; return AnimatedPositioned( @@ -129,13 +130,11 @@ class AuthPage extends GetView { padding: const EdgeInsets.fromLTRB(0, 8, 6, 8), child: Assets.vec.callSvg.svg(width: 12, height: 12), ), - suffixIcon: controller.usernameController.value.text - .trim() - .isNotEmpty + suffixIcon: controller.usernameController.value.text.trim().isNotEmpty ? clearButton(() { - controller.usernameController.value.clear(); - controller.usernameController.refresh(); - }) + controller.usernameController.value.clear(); + controller.usernameController.refresh(); + }) : null, validator: (value) { if (value == null || value.isEmpty) { @@ -157,47 +156,72 @@ class AuthPage extends GetView { ), const SizedBox(height: 26), ObxValue( - (passwordController) => - RTextField( - label: 'رمز عبور', - filled: false, - obscure: true, - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide(color: AppColor.textColor, width: 1), - ), - controller: passwordController.value, - autofillHints: [AutofillHints.password], - variant: RTextFieldVariant.password, - initText: passwordController.value.text, - onChanged: (value) { - passwordController.refresh(); - }, - validator: (value) { - if (value == null || value.isEmpty) { - return '⚠️ رمز عبور را وارد کنید'; - } - return null; - }, - style: AppFonts.yekan13, - errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal), - labelStyle: AppFonts.yekan13, - prefixIcon: Padding( - padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), - child: Assets.vec.keySvg.svg(width: 12, height: 12), - ), - boxConstraints: const BoxConstraints( - maxHeight: 34, - minHeight: 34, - maxWidth: 34, - minWidth: 34, - ), - ), + (passwordController) => RTextField( + label: 'رمز عبور', + filled: false, + obscure: true, + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: AppColor.textColor, width: 1), + ), + controller: passwordController.value, + autofillHints: [AutofillHints.password], + variant: RTextFieldVariant.password, + initText: passwordController.value.text, + onChanged: (value) { + passwordController.refresh(); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return '⚠️ رمز عبور را وارد کنید'; + } + return null; + }, + style: AppFonts.yekan13, + errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal), + labelStyle: AppFonts.yekan13, + prefixIcon: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), + child: Assets.vec.keySvg.svg(width: 12, height: 12), + ), + boxConstraints: const BoxConstraints( + maxHeight: 34, + minHeight: 34, + maxWidth: 34, + minWidth: 34, + ), + ), controller.passwordController, ), SizedBox(height: 26), CaptchaWidget(), - SizedBox(height: 23), + + GestureDetector( + onTap: () { + controller.rememberMe.value = !controller.rememberMe.value; + }, + child: Row( + children: [ + ObxValue((data) { + return Checkbox( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity(horizontal: -4, vertical: 4), + tristate: true, + value: data.value, + onChanged: (value) { + data.value = value ?? false; + }, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + activeColor: AppColor.blueNormal, + ); + }, controller.rememberMe), + Text( + 'مرا به خاطر بسپار', + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), Obx(() { return RElevated( @@ -206,8 +230,8 @@ class AuthPage extends GetView { onPressed: controller.isDisabled.value ? null : () async { - await controller.submitLoginForm(); - }, + await controller.submitLoginForm(); + }, width: Get.width, height: 48, ); @@ -308,7 +332,7 @@ class AuthPage extends GetView { ); } -/* + /* Widget sendCodeForm() { return ObxValue((data) { return Form( diff --git a/packages/inspection/lib/presentation/pages/location_details/view.dart b/packages/inspection/lib/presentation/pages/location_details/view.dart index 559508c..5d9792a 100644 --- a/packages/inspection/lib/presentation/pages/location_details/view.dart +++ b/packages/inspection/lib/presentation/pages/location_details/view.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/presentation/utils/color_utils.dart'; @@ -69,7 +70,7 @@ class LocationDetailsPage extends GetView { children: [ Expanded( child: ROutlinedElevatedIcon( - icon: FaIcon(FontAwesomeIcons.calendar), + icon: Icon(CupertinoIcons.calendar), onPressed:() async { Jalali? picked = await showPersianDatePicker( @@ -91,7 +92,7 @@ class LocationDetailsPage extends GetView { ), Expanded( child: ROutlinedElevatedIcon( - icon: FaIcon(FontAwesomeIcons.calendar), + icon: Icon(CupertinoIcons.calendar), onPressed: () async { Jalali? picked = await showPersianDatePicker( diff --git a/packages/inspection/pubspec.lock b/packages/inspection/pubspec.lock index dda8513..fcb6541 100644 --- a/packages/inspection/pubspec.lock +++ b/packages/inspection/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: android_intent_plus - sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.1" animated_stack_widget: dependency: transitive description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build - sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4" + sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -101,26 +101,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2" + sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d + sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62 + sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.3.0" built_collection: dependency: transitive description: @@ -137,6 +137,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.11.0" + cached_network_image: + dependency: transitive + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" characters: dependency: transitive description: @@ -193,6 +217,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -285,10 +325,10 @@ packages: dependency: transitive description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 url: "https://pub.dev" source: hosted - version: "5.8.0+1" + version: "5.9.0" dio_web_adapter: dependency: transitive description: @@ -369,11 +409,27 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flat_buffers: + dependency: transitive + description: + name: flat_buffers + sha256: "380bdcba5664a718bfd4ea20a45d39e13684f5318fcd8883066a55e21f37f4c3" + url: "https://pub.dev" + source: hosted + version: "23.5.26" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_gen_core: dependency: transitive description: @@ -435,6 +491,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + flutter_map_tile_caching: + dependency: transitive + description: + name: flutter_map_tile_caching + sha256: "1839c6157cf9b444083a626b30f3ba9f6db802ac8bb5292440e1628882faa392" + url: "https://pub.dev" + source: hosted + version: "10.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -511,10 +575,10 @@ packages: dependency: transitive description: name: flutter_slidable - sha256: ab7dbb16f783307c9d7762ede2593ce32c220ba2ba0fd540a3db8e9a3acba71a + sha256: e6bd17290cf0d011f9ed66c74d4159b8fe3b3050afedac0f11fab1ba8687e710 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" flutter_svg: dependency: transitive description: @@ -533,14 +597,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: transitive - description: - name: font_awesome_flutter - sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a - url: "https://pub.dev" - source: hosted - version: "10.8.0" freezed: dependency: "direct dev" description: @@ -641,10 +697,10 @@ packages: dependency: transitive description: name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.2.0" get_test: dependency: "direct dev" description: @@ -741,70 +797,94 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + image_cropper: + dependency: transitive + description: + name: image_cropper + sha256: "4e9c96c029eb5a23798da1b6af39787f964da6ffc78fd8447c140542a9f7c6fc" + url: "https://pub.dev" + source: hosted + version: "9.1.0" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: fd81ebe36f636576094377aab32673c4e5d1609b32dec16fad98d2b71f1250a9 + url: "https://pub.dev" + source: hosted + version: "6.1.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: "6ca6b81769abff9a4dcc3bbd3d75f5dfa9de6b870ae9613c8cd237333a4283af" + url: "https://pub.dev" + source: hosted + version: "7.1.0" image_picker: dependency: transitive description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -857,10 +937,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: ce2cf974ccdee13be2a510832d7fba0b94b364e0b0395dee42abaa51b855be27 + sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd" url: "https://pub.dev" source: hosted - version: "6.10.0" + version: "6.11.0" latlong2: dependency: transitive description: @@ -873,26 +953,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: "direct dev" description: @@ -997,6 +1077,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" node_preamble: dependency: transitive description: @@ -1005,6 +1093,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + objectbox: + dependency: transitive + description: + name: objectbox + sha256: "25c2e24b417d938decb5598682dc831bc6a21856eaae65affbc57cfad326808d" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + objectbox_flutter_libs: + dependency: transitive + description: + name: objectbox_flutter_libs + sha256: "574b0233ba79a7159fca9049c67974f790a2180b6141d4951112b20bd146016a" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" package_config: dependency: transitive description: @@ -1017,18 +1129,18 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.3.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" path: dependency: transitive description: @@ -1145,10 +1257,10 @@ packages: dependency: transitive description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: @@ -1313,14 +1425,22 @@ packages: description: flutter source: sdk version: "0.0.0" + smooth_page_indicator: + dependency: transitive + description: + name: smooth_page_indicator + sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c + url: "https://pub.dev" + source: hosted + version: "1.2.1" source_gen: dependency: transitive description: name: source_gen - sha256: fc787b1f89ceac9580c3616f899c9a447413cbdac1df071302127764c023a134 + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" source_helper: dependency: transitive description: @@ -1361,6 +1481,46 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -1393,6 +1553,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" term_glyph: dependency: transitive description: @@ -1405,26 +1573,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e" + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" url: "https://pub.dev" source: hosted - version: "1.25.15" + version: "1.26.2" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" test_core: dependency: transitive description: name: test_core - sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa" + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" url: "https://pub.dev" source: hosted - version: "0.6.8" + version: "0.6.11" time: dependency: transitive description: @@ -1493,10 +1661,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1602,5 +1770,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/packages/inspection/pubspec.yaml b/packages/inspection/pubspec.yaml index 0a3d2b2..1021d3b 100644 --- a/packages/inspection/pubspec.yaml +++ b/packages/inspection/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.2.0 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: @@ -21,10 +21,10 @@ dev_dependencies: lints: ^6.0.0 test: ^1.25.15 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 - json_serializable: ^6.10.0 + json_serializable: ^6.11.0 ##test mocktail: ^1.0.4 diff --git a/packages/livestock/.gitignore b/packages/livestock/.gitignore index 3cceda5..c40e34e 100644 --- a/packages/livestock/.gitignore +++ b/packages/livestock/.gitignore @@ -1,7 +1,4 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ - -# Avoid committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock +.dart_tool +*.lock +.flutter-plugins-dependencies +.flutter-plugins \ No newline at end of file diff --git a/packages/livestock/build.yaml b/packages/livestock/build.yaml new file mode 100644 index 0000000..840029b --- /dev/null +++ b/packages/livestock/build.yaml @@ -0,0 +1,6 @@ +targets: + $default: + builders: + json_serializable: + options: + field_rename: snake \ No newline at end of file diff --git a/packages/livestock/devtools_options.yaml b/packages/livestock/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/packages/livestock/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/packages/livestock/lib/data/common/checkk_di_middleware.dart b/packages/livestock/lib/data/common/checkk_di_middleware.dart new file mode 100644 index 0000000..32c9f0f --- /dev/null +++ b/packages/livestock/lib/data/common/checkk_di_middleware.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; + +class CheckDiMiddleWare extends GetMiddleware { + @override + Future redirectDelegate(GetNavConfig route) async { + return super.redirectDelegate(route); + } + + @override + GetPage? onPageCalled(GetPage? page) { + return super.onPageCalled(page); + } +} diff --git a/packages/livestock/lib/data/common/constant.dart b/packages/livestock/lib/data/common/constant.dart new file mode 100644 index 0000000..ea42090 --- /dev/null +++ b/packages/livestock/lib/data/common/constant.dart @@ -0,0 +1 @@ +const String mapStoreKey = 'mapStoreLiveStock'; \ No newline at end of file diff --git a/packages/livestock/lib/data/common/dio_exception_handeler.dart b/packages/livestock/lib/data/common/dio_exception_handeler.dart new file mode 100644 index 0000000..e3f34d2 --- /dev/null +++ b/packages/livestock/lib/data/common/dio_exception_handeler.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class DioErrorHandler { + void handle(DioException error) { + switch (error.response?.statusCode) { + case 401: + _handleGeneric(error); + break; + case 403: + _handleGeneric(error); + break; + + case 410: + _handle410(); + break; + default: + _handleGeneric(error); + } + } + + //wrong password/user name => "detail": "No active account found with the given credentials" - 401 + void _handle410() { + Get.showSnackbar(_errorSnackBar('نام کاربری یا رمز عبور اشتباه است')); + } + + //wrong captcha => "detail": "Captcha code is incorrect" - 403 + void _handle403() {} + + void _handleGeneric(DioException error) { + Get.showSnackbar( + _errorSnackBar( + error.response?.data.keys.first == 'is_user' + ? 'کاربر با این شماره تلفن وجود ندارد' + : '${error.response?.statusCode} - ${error.response?.data[error.response?.data.keys.first]}' ?? + 'خطا در برقراری ارتباط با سرور', + ), + ); + } + + GetSnackBar _errorSnackBar(String message) { + return GetSnackBar( + titleText: Text('خطا', style: AppFonts.yekan14.copyWith(color: Colors.white)), + messageText: Text(message, style: AppFonts.yekan12.copyWith(color: Colors.white)), + backgroundColor: AppColor.error, + margin: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + borderRadius: 12, + duration: Duration(milliseconds: 3500), + snackPosition: SnackPosition.TOP, + ); + } +} diff --git a/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart b/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart new file mode 100644 index 0000000..ca0b98b --- /dev/null +++ b/packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart @@ -0,0 +1,18 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; + +class TmpLocalDataSource { + Future addLocations(List list) async { + IsolatedBox box = await IsolatedHive.openBox('TmpBox'); + if (await box.isNotEmpty) { + box.clear(); + } + box.addAll(list); + } + + Future> getLocations() async { + IsolatedBox box = await IsolatedHive.openBox('TmpBox'); + var res = await box.values; + return res.toList(); + } +} diff --git a/packages/livestock/lib/data/data_source/remote/auth/auth_remote.dart b/packages/livestock/lib/data/data_source/remote/auth/auth_remote.dart new file mode 100644 index 0000000..e22cae2 --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/auth/auth_remote.dart @@ -0,0 +1,16 @@ + + +import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; +import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; + +abstract class AuthRemoteDataSource { + Future login({required Map authRequest}); + + Future captcha(); + + Future logout(); + + Future hasAuthenticated(); + + Future loginWithRefreshToken({required Map authRequest}); +} diff --git a/packages/livestock/lib/data/data_source/remote/auth/auth_remote_imp.dart b/packages/livestock/lib/data/data_source/remote/auth/auth_remote_imp.dart new file mode 100644 index 0000000..e4f227b --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/auth/auth_remote_imp.dart @@ -0,0 +1,70 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; +import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; + +import 'auth_remote.dart'; + +class AuthRemoteDataSourceImp extends AuthRemoteDataSource { + final DioRemote _httpClient; + final String _BASE_URL = 'auth/api/v1/'; + + AuthRemoteDataSourceImp(this._httpClient); + + @override + Future login({required Map authRequest}) async { + var res = await _httpClient.post( + '${_BASE_URL}login/', + data: authRequest, + fromJson: AuthResponseModel.fromJson, + ); + return res.data; + } + + @override + Future captcha() async { + var res = await _httpClient.post( + 'captcha/', + fromJson: CaptchaResponseModel.fromJson, + ); + return res.data; + } + + @override + Future loginWithRefreshToken({ + required Map authRequest, + }) async { + var res = await _httpClient.post( + '$_BASE_URL/login/', + data: authRequest, + headers: {'Content-Type': 'application/json'}, + ); + return res.data; + } + + @override + Future logout() { + // TODO: implement logout + throw UnimplementedError(); + } + + @override + Future hasAuthenticated() async { + final response = await _httpClient.get( + '$_BASE_URL/login/', + headers: {'Content-Type': 'application/json'}, + ); + + return response.data ?? false; + } + + /* @override + Future getUserInfo(String phoneNumber) async { + var res = await _httpClient.post( + 'https://userbackend.rasadyaar.ir/api/send_otp/', + data: {"mobile": phoneNumber, "state": ""}, + fromJson: UserProfileModel.fromJson, + headers: {'Content-Type': 'application/json'}, + ); + return res.data; + }*/ +} diff --git a/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart new file mode 100644 index 0000000..f16fc1e --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart @@ -0,0 +1,11 @@ +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; + +abstract class LivestockRemoteDataSource { + Future getLocationDetailsByLatLng({ + required double latitude, + required double longitude, + }); + + Future createTaggingLiveStock({required LivestockData data}); +} diff --git a/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart new file mode 100644 index 0000000..f6cfb01 --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart @@ -0,0 +1,55 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; + +class LivestockRemoteDataSourceImp implements LivestockRemoteDataSource { + @override + Future getLocationDetailsByLatLng({ + required double latitude, + required double longitude, + }) async { + try { + Dio dio = Dio(); + dio.options.baseUrl = 'https://nominatim.openstreetmap.org/'; + dio.options.headers['User-Agent'] = 'RasadyarLivestock/2.0'; + final response = await dio.get( + 'reverse', + queryParameters: {'lat': latitude, 'lon': longitude, 'format': 'json'}, + ); + if (response.statusCode == 200) { + final data = response.data; + return LocationDetails.fromJson(data); + } else { + throw Exception('Failed to load address'); + } + } catch (e) { + rethrow; + } + } + + @override + Future createTaggingLiveStock({required LivestockData data}) async { + try { + Dio dio = Dio(); + dio.interceptors.add(PrettyDioLogger( + requestBody: false, + responseBody: false, + requestHeader: true, + responseHeader: true, + error: true, + compact: true, + )); + dio.options.baseUrl = 'https://everestacademy.ir/live/'; + final response = await dio.post('api.php', data: data.toJson()); + if (response.statusCode == 200) { + final data = response.data; + return true; + } else { + throw Exception('Failed to load address'); + } + } catch (e) { + rethrow; + } + } +} diff --git a/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.dart b/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.dart new file mode 100644 index 0000000..a42cfb6 --- /dev/null +++ b/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.dart @@ -0,0 +1,97 @@ +import 'package:rasadyar_core/core.dart'; + + +part 'livestock_local_model.g.dart'; + +@HiveType(typeId: liveStockDataLocalModelTypeId) + class LivestockLocalModel extends HiveObject { + + + @HiveField(0) + RancherLocal? rancher; + + @HiveField(1) + HerdLocal? herd; + + @HiveField(2) + List? livestock; + +} + + + +@HiveType(typeId: liveStockDataRancherLocalModelTypeId) + class RancherLocal extends HiveObject { + + @HiveField(0) + String? name; + + @HiveField(1) + String? phone; + + @HiveField(2) + String? image; +} + + +@HiveType(typeId: liveStockDataHerdLocalModelTypeId) +class HerdLocal extends HiveObject{ + + @HiveField(0) + LocationLocal? location; + + @HiveField(1) + String? address; + + @HiveField(2) + String? image; + + +} + + +@HiveType(typeId: liveStockDataLocationLocalModelTypeId) +class LocationLocal extends HiveObject { + + @HiveField(0) + double? lat; + + @HiveField(1) + double? lng; + +} + + +@HiveType(typeId: liveStockDataLivestockLocalModelTypeId) +class LivestockLocal extends HiveObject { + + + @HiveField(0) + String? species; + + @HiveField(1) + String? breed; + + @HiveField(2) + String? dateOfBirth; + + @HiveField(3) + String? sex; + + @HiveField(4) + String? motherTag; + + @HiveField(5) + String? fatherTag; + + @HiveField(6) + String? tagNumber; + + @HiveField(7) + String? tagType; + + @HiveField(8) + String? image; + + +} diff --git a/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.g.dart b/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.g.dart new file mode 100644 index 0000000..921da9a --- /dev/null +++ b/packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.g.dart @@ -0,0 +1,217 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'livestock_local_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LivestockLocalModelAdapter extends TypeAdapter { + @override + final typeId = 4; + + @override + LivestockLocalModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LivestockLocalModel() + ..rancher = fields[0] as RancherLocal? + ..herd = fields[1] as HerdLocal? + ..livestock = (fields[2] as List?)?.cast(); + } + + @override + void write(BinaryWriter writer, LivestockLocalModel obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.rancher) + ..writeByte(1) + ..write(obj.herd) + ..writeByte(2) + ..write(obj.livestock); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LivestockLocalModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class RancherLocalAdapter extends TypeAdapter { + @override + final typeId = 5; + + @override + RancherLocal read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return RancherLocal() + ..name = fields[0] as String? + ..phone = fields[1] as String? + ..image = fields[2] as String?; + } + + @override + void write(BinaryWriter writer, RancherLocal obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.name) + ..writeByte(1) + ..write(obj.phone) + ..writeByte(2) + ..write(obj.image); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is RancherLocalAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class HerdLocalAdapter extends TypeAdapter { + @override + final typeId = 6; + + @override + HerdLocal read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return HerdLocal() + ..location = fields[0] as LocationLocal? + ..address = fields[1] as String? + ..image = fields[2] as String?; + } + + @override + void write(BinaryWriter writer, HerdLocal obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.location) + ..writeByte(1) + ..write(obj.address) + ..writeByte(2) + ..write(obj.image); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is HerdLocalAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class LocationLocalAdapter extends TypeAdapter { + @override + final typeId = 7; + + @override + LocationLocal read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LocationLocal() + ..lat = (fields[0] as num?)?.toDouble() + ..lng = (fields[1] as num?)?.toDouble(); + } + + @override + void write(BinaryWriter writer, LocationLocal obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.lat) + ..writeByte(1) + ..write(obj.lng); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LocationLocalAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class LivestockLocalAdapter extends TypeAdapter { + @override + final typeId = 8; + + @override + LivestockLocal read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LivestockLocal() + ..species = fields[0] as String? + ..breed = fields[1] as String? + ..dateOfBirth = fields[2] as String? + ..sex = fields[3] as String? + ..motherTag = fields[4] as String? + ..fatherTag = fields[5] as String? + ..tagNumber = fields[6] as String? + ..tagType = fields[7] as String? + ..image = fields[8] as String?; + } + + @override + void write(BinaryWriter writer, LivestockLocal obj) { + writer + ..writeByte(9) + ..writeByte(0) + ..write(obj.species) + ..writeByte(1) + ..write(obj.breed) + ..writeByte(2) + ..write(obj.dateOfBirth) + ..writeByte(3) + ..write(obj.sex) + ..writeByte(4) + ..write(obj.motherTag) + ..writeByte(5) + ..write(obj.fatherTag) + ..writeByte(6) + ..write(obj.tagNumber) + ..writeByte(7) + ..write(obj.tagType) + ..writeByte(8) + ..write(obj.image); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LivestockLocalAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/packages/livestock/lib/data/model/local/location/tmp_locations.dart b/packages/livestock/lib/data/model/local/location/tmp_locations.dart new file mode 100644 index 0000000..f9413fd --- /dev/null +++ b/packages/livestock/lib/data/model/local/location/tmp_locations.dart @@ -0,0 +1,16 @@ +import 'package:rasadyar_core/core.dart'; + +part 'tmp_locations.g.dart'; + +@HiveType(typeId: 100) +class TmpLocations extends HiveObject{ + + @HiveField(0) + double? lat; + + + @HiveField(1) + double? long; + + TmpLocations({this.lat, this.long}); +} \ No newline at end of file diff --git a/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart new file mode 100644 index 0000000..2c70c49 --- /dev/null +++ b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart @@ -0,0 +1,43 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'tmp_locations.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class TmpLocationsAdapter extends TypeAdapter { + @override + final typeId = 100; + + @override + TmpLocations read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return TmpLocations() + ..lat = (fields[0] as num?)?.toDouble() + ..long = (fields[1] as num?)?.toDouble(); + } + + @override + void write(BinaryWriter writer, TmpLocations obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.lat) + ..writeByte(1) + ..write(obj.long); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is TmpLocationsAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/packages/livestock/lib/data/model/request/login_request/login_request_model.dart b/packages/livestock/lib/data/model/request/login_request/login_request_model.dart new file mode 100644 index 0000000..0e76bc2 --- /dev/null +++ b/packages/livestock/lib/data/model/request/login_request/login_request_model.dart @@ -0,0 +1,34 @@ +import 'package:rasadyar_core/core.dart'; + +part 'login_request_model.freezed.dart'; +part 'login_request_model.g.dart'; + +@freezed +abstract class LoginRequestModel with _$LoginRequestModel { + const factory LoginRequestModel({ + String? username, + String? password, + String? captchaCode, + String? captchaKey, + }) = _LoginRequestModel; + + factory LoginRequestModel.createWithCaptcha({ + required String username, + required String password, + required String captchaCode, + required String captchaKey, + }) { + return LoginRequestModel( + username: username, + password: password, + captchaCode: captchaCode, + captchaKey: 'rest_captcha_$captchaKey.0', + ); + } + + factory LoginRequestModel.fromJson(Map json) => + _$LoginRequestModelFromJson(json); + + const LoginRequestModel._(); + +} diff --git a/packages/livestock/lib/data/model/request/login_request/login_request_model.freezed.dart b/packages/livestock/lib/data/model/request/login_request/login_request_model.freezed.dart new file mode 100644 index 0000000..9b91ad6 --- /dev/null +++ b/packages/livestock/lib/data/model/request/login_request/login_request_model.freezed.dart @@ -0,0 +1,286 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'login_request_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$LoginRequestModel { + + String? get username; String? get password; String? get captchaCode; String? get captchaKey; +/// Create a copy of LoginRequestModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LoginRequestModelCopyWith get copyWith => _$LoginRequestModelCopyWithImpl(this as LoginRequestModel, _$identity); + + /// Serializes this LoginRequestModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LoginRequestModel&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.captchaCode, captchaCode) || other.captchaCode == captchaCode)&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,username,password,captchaCode,captchaKey); + +@override +String toString() { + return 'LoginRequestModel(username: $username, password: $password, captchaCode: $captchaCode, captchaKey: $captchaKey)'; +} + + +} + +/// @nodoc +abstract mixin class $LoginRequestModelCopyWith<$Res> { + factory $LoginRequestModelCopyWith(LoginRequestModel value, $Res Function(LoginRequestModel) _then) = _$LoginRequestModelCopyWithImpl; +@useResult +$Res call({ + String? username, String? password, String? captchaCode, String? captchaKey +}); + + + + +} +/// @nodoc +class _$LoginRequestModelCopyWithImpl<$Res> + implements $LoginRequestModelCopyWith<$Res> { + _$LoginRequestModelCopyWithImpl(this._self, this._then); + + final LoginRequestModel _self; + final $Res Function(LoginRequestModel) _then; + +/// Create a copy of LoginRequestModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? username = freezed,Object? password = freezed,Object? captchaCode = freezed,Object? captchaKey = freezed,}) { + return _then(_self.copyWith( +username: freezed == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String?,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,captchaCode: freezed == captchaCode ? _self.captchaCode : captchaCode // ignore: cast_nullable_to_non_nullable +as String?,captchaKey: freezed == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [LoginRequestModel]. +extension LoginRequestModelPatterns on LoginRequestModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LoginRequestModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LoginRequestModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LoginRequestModel value) $default,){ +final _that = this; +switch (_that) { +case _LoginRequestModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LoginRequestModel value)? $default,){ +final _that = this; +switch (_that) { +case _LoginRequestModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? username, String? password, String? captchaCode, String? captchaKey)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LoginRequestModel() when $default != null: +return $default(_that.username,_that.password,_that.captchaCode,_that.captchaKey);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? username, String? password, String? captchaCode, String? captchaKey) $default,) {final _that = this; +switch (_that) { +case _LoginRequestModel(): +return $default(_that.username,_that.password,_that.captchaCode,_that.captchaKey);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? username, String? password, String? captchaCode, String? captchaKey)? $default,) {final _that = this; +switch (_that) { +case _LoginRequestModel() when $default != null: +return $default(_that.username,_that.password,_that.captchaCode,_that.captchaKey);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _LoginRequestModel extends LoginRequestModel { + const _LoginRequestModel({this.username, this.password, this.captchaCode, this.captchaKey}): super._(); + factory _LoginRequestModel.fromJson(Map json) => _$LoginRequestModelFromJson(json); + +@override final String? username; +@override final String? password; +@override final String? captchaCode; +@override final String? captchaKey; + +/// Create a copy of LoginRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LoginRequestModelCopyWith<_LoginRequestModel> get copyWith => __$LoginRequestModelCopyWithImpl<_LoginRequestModel>(this, _$identity); + +@override +Map toJson() { + return _$LoginRequestModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LoginRequestModel&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.captchaCode, captchaCode) || other.captchaCode == captchaCode)&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,username,password,captchaCode,captchaKey); + +@override +String toString() { + return 'LoginRequestModel(username: $username, password: $password, captchaCode: $captchaCode, captchaKey: $captchaKey)'; +} + + +} + +/// @nodoc +abstract mixin class _$LoginRequestModelCopyWith<$Res> implements $LoginRequestModelCopyWith<$Res> { + factory _$LoginRequestModelCopyWith(_LoginRequestModel value, $Res Function(_LoginRequestModel) _then) = __$LoginRequestModelCopyWithImpl; +@override @useResult +$Res call({ + String? username, String? password, String? captchaCode, String? captchaKey +}); + + + + +} +/// @nodoc +class __$LoginRequestModelCopyWithImpl<$Res> + implements _$LoginRequestModelCopyWith<$Res> { + __$LoginRequestModelCopyWithImpl(this._self, this._then); + + final _LoginRequestModel _self; + final $Res Function(_LoginRequestModel) _then; + +/// Create a copy of LoginRequestModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? username = freezed,Object? password = freezed,Object? captchaCode = freezed,Object? captchaKey = freezed,}) { + return _then(_LoginRequestModel( +username: freezed == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String?,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,captchaCode: freezed == captchaCode ? _self.captchaCode : captchaCode // ignore: cast_nullable_to_non_nullable +as String?,captchaKey: freezed == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/packages/livestock/lib/data/model/request/login_request/login_request_model.g.dart b/packages/livestock/lib/data/model/request/login_request/login_request_model.g.dart new file mode 100644 index 0000000..4504142 --- /dev/null +++ b/packages/livestock/lib/data/model/request/login_request/login_request_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'login_request_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_LoginRequestModel _$LoginRequestModelFromJson(Map json) => + _LoginRequestModel( + username: json['username'] as String?, + password: json['password'] as String?, + captchaCode: json['captcha_code'] as String?, + captchaKey: json['captcha_key'] as String?, + ); + +Map _$LoginRequestModelToJson(_LoginRequestModel instance) => + { + 'username': instance.username, + 'password': instance.password, + 'captcha_code': instance.captchaCode, + 'captcha_key': instance.captchaKey, + }; diff --git a/packages/livestock/lib/data/model/response/address/address.dart b/packages/livestock/lib/data/model/response/address/address.dart new file mode 100644 index 0000000..4a1737d --- /dev/null +++ b/packages/livestock/lib/data/model/response/address/address.dart @@ -0,0 +1,49 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'address.freezed.dart'; + +part 'address.g.dart'; + +@freezed +abstract class Address with _$Address { + const factory Address({ + String? road, + String? neighbourhood, + String? suburb, + String? state, + String? borough, + String? city, + String? district, + String? county, + String? province, + String? ISO3166_2_lvl4, + String? postcode, + String? country, + String? country_code, + }) = _Address; + + factory Address.fromJson(Map json) => _$AddressFromJson(json); +} + +@freezed +abstract class LocationDetails with _$LocationDetails { + const factory LocationDetails({ + int? place_id, + String? licence, + String? osm_type, + int? osm_id, + String? lat, + String? lon, + String? class_, + String? type, + int? place_rank, + double? importance, + String? addresstype, + String? name, + String? display_name, + Address? address, + List? boundingbox, + }) = _LocationDetails; + + factory LocationDetails.fromJson(Map json) => _$LocationDetailsFromJson(json); +} diff --git a/packages/livestock/lib/data/model/response/address/address.freezed.dart b/packages/livestock/lib/data/model/response/address/address.freezed.dart new file mode 100644 index 0000000..425bb41 --- /dev/null +++ b/packages/livestock/lib/data/model/response/address/address.freezed.dart @@ -0,0 +1,650 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'address.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$Address { + + String? get road; String? get neighbourhood; String? get suburb; String? get state; String? get borough; String? get city; String? get district; String? get county; String? get province; String? get ISO3166_2_lvl4; String? get postcode; String? get country; String? get country_code; +/// Create a copy of Address +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$AddressCopyWith
get copyWith => _$AddressCopyWithImpl
(this as Address, _$identity); + + /// Serializes this Address to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Address&&(identical(other.road, road) || other.road == road)&&(identical(other.neighbourhood, neighbourhood) || other.neighbourhood == neighbourhood)&&(identical(other.suburb, suburb) || other.suburb == suburb)&&(identical(other.state, state) || other.state == state)&&(identical(other.borough, borough) || other.borough == borough)&&(identical(other.city, city) || other.city == city)&&(identical(other.district, district) || other.district == district)&&(identical(other.county, county) || other.county == county)&&(identical(other.province, province) || other.province == province)&&(identical(other.ISO3166_2_lvl4, ISO3166_2_lvl4) || other.ISO3166_2_lvl4 == ISO3166_2_lvl4)&&(identical(other.postcode, postcode) || other.postcode == postcode)&&(identical(other.country, country) || other.country == country)&&(identical(other.country_code, country_code) || other.country_code == country_code)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,road,neighbourhood,suburb,state,borough,city,district,county,province,ISO3166_2_lvl4,postcode,country,country_code); + +@override +String toString() { + return 'Address(road: $road, neighbourhood: $neighbourhood, suburb: $suburb, state: $state, borough: $borough, city: $city, district: $district, county: $county, province: $province, ISO3166_2_lvl4: $ISO3166_2_lvl4, postcode: $postcode, country: $country, country_code: $country_code)'; +} + + +} + +/// @nodoc +abstract mixin class $AddressCopyWith<$Res> { + factory $AddressCopyWith(Address value, $Res Function(Address) _then) = _$AddressCopyWithImpl; +@useResult +$Res call({ + String? road, String? neighbourhood, String? suburb, String? state, String? borough, String? city, String? district, String? county, String? province, String? ISO3166_2_lvl4, String? postcode, String? country, String? country_code +}); + + + + +} +/// @nodoc +class _$AddressCopyWithImpl<$Res> + implements $AddressCopyWith<$Res> { + _$AddressCopyWithImpl(this._self, this._then); + + final Address _self; + final $Res Function(Address) _then; + +/// Create a copy of Address +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? road = freezed,Object? neighbourhood = freezed,Object? suburb = freezed,Object? state = freezed,Object? borough = freezed,Object? city = freezed,Object? district = freezed,Object? county = freezed,Object? province = freezed,Object? ISO3166_2_lvl4 = freezed,Object? postcode = freezed,Object? country = freezed,Object? country_code = freezed,}) { + return _then(_self.copyWith( +road: freezed == road ? _self.road : road // ignore: cast_nullable_to_non_nullable +as String?,neighbourhood: freezed == neighbourhood ? _self.neighbourhood : neighbourhood // ignore: cast_nullable_to_non_nullable +as String?,suburb: freezed == suburb ? _self.suburb : suburb // ignore: cast_nullable_to_non_nullable +as String?,state: freezed == state ? _self.state : state // ignore: cast_nullable_to_non_nullable +as String?,borough: freezed == borough ? _self.borough : borough // ignore: cast_nullable_to_non_nullable +as String?,city: freezed == city ? _self.city : city // ignore: cast_nullable_to_non_nullable +as String?,district: freezed == district ? _self.district : district // ignore: cast_nullable_to_non_nullable +as String?,county: freezed == county ? _self.county : county // ignore: cast_nullable_to_non_nullable +as String?,province: freezed == province ? _self.province : province // ignore: cast_nullable_to_non_nullable +as String?,ISO3166_2_lvl4: freezed == ISO3166_2_lvl4 ? _self.ISO3166_2_lvl4 : ISO3166_2_lvl4 // ignore: cast_nullable_to_non_nullable +as String?,postcode: freezed == postcode ? _self.postcode : postcode // ignore: cast_nullable_to_non_nullable +as String?,country: freezed == country ? _self.country : country // ignore: cast_nullable_to_non_nullable +as String?,country_code: freezed == country_code ? _self.country_code : country_code // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Address]. +extension AddressPatterns on Address { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Address value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Address() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Address value) $default,){ +final _that = this; +switch (_that) { +case _Address(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Address value)? $default,){ +final _that = this; +switch (_that) { +case _Address() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? road, String? neighbourhood, String? suburb, String? state, String? borough, String? city, String? district, String? county, String? province, String? ISO3166_2_lvl4, String? postcode, String? country, String? country_code)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Address() when $default != null: +return $default(_that.road,_that.neighbourhood,_that.suburb,_that.state,_that.borough,_that.city,_that.district,_that.county,_that.province,_that.ISO3166_2_lvl4,_that.postcode,_that.country,_that.country_code);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? road, String? neighbourhood, String? suburb, String? state, String? borough, String? city, String? district, String? county, String? province, String? ISO3166_2_lvl4, String? postcode, String? country, String? country_code) $default,) {final _that = this; +switch (_that) { +case _Address(): +return $default(_that.road,_that.neighbourhood,_that.suburb,_that.state,_that.borough,_that.city,_that.district,_that.county,_that.province,_that.ISO3166_2_lvl4,_that.postcode,_that.country,_that.country_code);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? road, String? neighbourhood, String? suburb, String? state, String? borough, String? city, String? district, String? county, String? province, String? ISO3166_2_lvl4, String? postcode, String? country, String? country_code)? $default,) {final _that = this; +switch (_that) { +case _Address() when $default != null: +return $default(_that.road,_that.neighbourhood,_that.suburb,_that.state,_that.borough,_that.city,_that.district,_that.county,_that.province,_that.ISO3166_2_lvl4,_that.postcode,_that.country,_that.country_code);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Address implements Address { + const _Address({this.road, this.neighbourhood, this.suburb, this.state, this.borough, this.city, this.district, this.county, this.province, this.ISO3166_2_lvl4, this.postcode, this.country, this.country_code}); + factory _Address.fromJson(Map json) => _$AddressFromJson(json); + +@override final String? road; +@override final String? neighbourhood; +@override final String? suburb; +@override final String? state; +@override final String? borough; +@override final String? city; +@override final String? district; +@override final String? county; +@override final String? province; +@override final String? ISO3166_2_lvl4; +@override final String? postcode; +@override final String? country; +@override final String? country_code; + +/// Create a copy of Address +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$AddressCopyWith<_Address> get copyWith => __$AddressCopyWithImpl<_Address>(this, _$identity); + +@override +Map toJson() { + return _$AddressToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Address&&(identical(other.road, road) || other.road == road)&&(identical(other.neighbourhood, neighbourhood) || other.neighbourhood == neighbourhood)&&(identical(other.suburb, suburb) || other.suburb == suburb)&&(identical(other.state, state) || other.state == state)&&(identical(other.borough, borough) || other.borough == borough)&&(identical(other.city, city) || other.city == city)&&(identical(other.district, district) || other.district == district)&&(identical(other.county, county) || other.county == county)&&(identical(other.province, province) || other.province == province)&&(identical(other.ISO3166_2_lvl4, ISO3166_2_lvl4) || other.ISO3166_2_lvl4 == ISO3166_2_lvl4)&&(identical(other.postcode, postcode) || other.postcode == postcode)&&(identical(other.country, country) || other.country == country)&&(identical(other.country_code, country_code) || other.country_code == country_code)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,road,neighbourhood,suburb,state,borough,city,district,county,province,ISO3166_2_lvl4,postcode,country,country_code); + +@override +String toString() { + return 'Address(road: $road, neighbourhood: $neighbourhood, suburb: $suburb, state: $state, borough: $borough, city: $city, district: $district, county: $county, province: $province, ISO3166_2_lvl4: $ISO3166_2_lvl4, postcode: $postcode, country: $country, country_code: $country_code)'; +} + + +} + +/// @nodoc +abstract mixin class _$AddressCopyWith<$Res> implements $AddressCopyWith<$Res> { + factory _$AddressCopyWith(_Address value, $Res Function(_Address) _then) = __$AddressCopyWithImpl; +@override @useResult +$Res call({ + String? road, String? neighbourhood, String? suburb, String? state, String? borough, String? city, String? district, String? county, String? province, String? ISO3166_2_lvl4, String? postcode, String? country, String? country_code +}); + + + + +} +/// @nodoc +class __$AddressCopyWithImpl<$Res> + implements _$AddressCopyWith<$Res> { + __$AddressCopyWithImpl(this._self, this._then); + + final _Address _self; + final $Res Function(_Address) _then; + +/// Create a copy of Address +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? road = freezed,Object? neighbourhood = freezed,Object? suburb = freezed,Object? state = freezed,Object? borough = freezed,Object? city = freezed,Object? district = freezed,Object? county = freezed,Object? province = freezed,Object? ISO3166_2_lvl4 = freezed,Object? postcode = freezed,Object? country = freezed,Object? country_code = freezed,}) { + return _then(_Address( +road: freezed == road ? _self.road : road // ignore: cast_nullable_to_non_nullable +as String?,neighbourhood: freezed == neighbourhood ? _self.neighbourhood : neighbourhood // ignore: cast_nullable_to_non_nullable +as String?,suburb: freezed == suburb ? _self.suburb : suburb // ignore: cast_nullable_to_non_nullable +as String?,state: freezed == state ? _self.state : state // ignore: cast_nullable_to_non_nullable +as String?,borough: freezed == borough ? _self.borough : borough // ignore: cast_nullable_to_non_nullable +as String?,city: freezed == city ? _self.city : city // ignore: cast_nullable_to_non_nullable +as String?,district: freezed == district ? _self.district : district // ignore: cast_nullable_to_non_nullable +as String?,county: freezed == county ? _self.county : county // ignore: cast_nullable_to_non_nullable +as String?,province: freezed == province ? _self.province : province // ignore: cast_nullable_to_non_nullable +as String?,ISO3166_2_lvl4: freezed == ISO3166_2_lvl4 ? _self.ISO3166_2_lvl4 : ISO3166_2_lvl4 // ignore: cast_nullable_to_non_nullable +as String?,postcode: freezed == postcode ? _self.postcode : postcode // ignore: cast_nullable_to_non_nullable +as String?,country: freezed == country ? _self.country : country // ignore: cast_nullable_to_non_nullable +as String?,country_code: freezed == country_code ? _self.country_code : country_code // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + + +/// @nodoc +mixin _$LocationDetails { + + int? get place_id; String? get licence; String? get osm_type; int? get osm_id; String? get lat; String? get lon; String? get class_; String? get type; int? get place_rank; double? get importance; String? get addresstype; String? get name; String? get display_name; Address? get address; List? get boundingbox; +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LocationDetailsCopyWith get copyWith => _$LocationDetailsCopyWithImpl(this as LocationDetails, _$identity); + + /// Serializes this LocationDetails to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LocationDetails&&(identical(other.place_id, place_id) || other.place_id == place_id)&&(identical(other.licence, licence) || other.licence == licence)&&(identical(other.osm_type, osm_type) || other.osm_type == osm_type)&&(identical(other.osm_id, osm_id) || other.osm_id == osm_id)&&(identical(other.lat, lat) || other.lat == lat)&&(identical(other.lon, lon) || other.lon == lon)&&(identical(other.class_, class_) || other.class_ == class_)&&(identical(other.type, type) || other.type == type)&&(identical(other.place_rank, place_rank) || other.place_rank == place_rank)&&(identical(other.importance, importance) || other.importance == importance)&&(identical(other.addresstype, addresstype) || other.addresstype == addresstype)&&(identical(other.name, name) || other.name == name)&&(identical(other.display_name, display_name) || other.display_name == display_name)&&(identical(other.address, address) || other.address == address)&&const DeepCollectionEquality().equals(other.boundingbox, boundingbox)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,place_id,licence,osm_type,osm_id,lat,lon,class_,type,place_rank,importance,addresstype,name,display_name,address,const DeepCollectionEquality().hash(boundingbox)); + +@override +String toString() { + return 'LocationDetails(place_id: $place_id, licence: $licence, osm_type: $osm_type, osm_id: $osm_id, lat: $lat, lon: $lon, class_: $class_, type: $type, place_rank: $place_rank, importance: $importance, addresstype: $addresstype, name: $name, display_name: $display_name, address: $address, boundingbox: $boundingbox)'; +} + + +} + +/// @nodoc +abstract mixin class $LocationDetailsCopyWith<$Res> { + factory $LocationDetailsCopyWith(LocationDetails value, $Res Function(LocationDetails) _then) = _$LocationDetailsCopyWithImpl; +@useResult +$Res call({ + int? place_id, String? licence, String? osm_type, int? osm_id, String? lat, String? lon, String? class_, String? type, int? place_rank, double? importance, String? addresstype, String? name, String? display_name, Address? address, List? boundingbox +}); + + +$AddressCopyWith<$Res>? get address; + +} +/// @nodoc +class _$LocationDetailsCopyWithImpl<$Res> + implements $LocationDetailsCopyWith<$Res> { + _$LocationDetailsCopyWithImpl(this._self, this._then); + + final LocationDetails _self; + final $Res Function(LocationDetails) _then; + +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? place_id = freezed,Object? licence = freezed,Object? osm_type = freezed,Object? osm_id = freezed,Object? lat = freezed,Object? lon = freezed,Object? class_ = freezed,Object? type = freezed,Object? place_rank = freezed,Object? importance = freezed,Object? addresstype = freezed,Object? name = freezed,Object? display_name = freezed,Object? address = freezed,Object? boundingbox = freezed,}) { + return _then(_self.copyWith( +place_id: freezed == place_id ? _self.place_id : place_id // ignore: cast_nullable_to_non_nullable +as int?,licence: freezed == licence ? _self.licence : licence // ignore: cast_nullable_to_non_nullable +as String?,osm_type: freezed == osm_type ? _self.osm_type : osm_type // ignore: cast_nullable_to_non_nullable +as String?,osm_id: freezed == osm_id ? _self.osm_id : osm_id // ignore: cast_nullable_to_non_nullable +as int?,lat: freezed == lat ? _self.lat : lat // ignore: cast_nullable_to_non_nullable +as String?,lon: freezed == lon ? _self.lon : lon // ignore: cast_nullable_to_non_nullable +as String?,class_: freezed == class_ ? _self.class_ : class_ // ignore: cast_nullable_to_non_nullable +as String?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String?,place_rank: freezed == place_rank ? _self.place_rank : place_rank // ignore: cast_nullable_to_non_nullable +as int?,importance: freezed == importance ? _self.importance : importance // ignore: cast_nullable_to_non_nullable +as double?,addresstype: freezed == addresstype ? _self.addresstype : addresstype // ignore: cast_nullable_to_non_nullable +as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String?,display_name: freezed == display_name ? _self.display_name : display_name // ignore: cast_nullable_to_non_nullable +as String?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as Address?,boundingbox: freezed == boundingbox ? _self.boundingbox : boundingbox // ignore: cast_nullable_to_non_nullable +as List?, + )); +} +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AddressCopyWith<$Res>? get address { + if (_self.address == null) { + return null; + } + + return $AddressCopyWith<$Res>(_self.address!, (value) { + return _then(_self.copyWith(address: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [LocationDetails]. +extension LocationDetailsPatterns on LocationDetails { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LocationDetails value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LocationDetails() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LocationDetails value) $default,){ +final _that = this; +switch (_that) { +case _LocationDetails(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LocationDetails value)? $default,){ +final _that = this; +switch (_that) { +case _LocationDetails() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( int? place_id, String? licence, String? osm_type, int? osm_id, String? lat, String? lon, String? class_, String? type, int? place_rank, double? importance, String? addresstype, String? name, String? display_name, Address? address, List? boundingbox)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LocationDetails() when $default != null: +return $default(_that.place_id,_that.licence,_that.osm_type,_that.osm_id,_that.lat,_that.lon,_that.class_,_that.type,_that.place_rank,_that.importance,_that.addresstype,_that.name,_that.display_name,_that.address,_that.boundingbox);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( int? place_id, String? licence, String? osm_type, int? osm_id, String? lat, String? lon, String? class_, String? type, int? place_rank, double? importance, String? addresstype, String? name, String? display_name, Address? address, List? boundingbox) $default,) {final _that = this; +switch (_that) { +case _LocationDetails(): +return $default(_that.place_id,_that.licence,_that.osm_type,_that.osm_id,_that.lat,_that.lon,_that.class_,_that.type,_that.place_rank,_that.importance,_that.addresstype,_that.name,_that.display_name,_that.address,_that.boundingbox);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( int? place_id, String? licence, String? osm_type, int? osm_id, String? lat, String? lon, String? class_, String? type, int? place_rank, double? importance, String? addresstype, String? name, String? display_name, Address? address, List? boundingbox)? $default,) {final _that = this; +switch (_that) { +case _LocationDetails() when $default != null: +return $default(_that.place_id,_that.licence,_that.osm_type,_that.osm_id,_that.lat,_that.lon,_that.class_,_that.type,_that.place_rank,_that.importance,_that.addresstype,_that.name,_that.display_name,_that.address,_that.boundingbox);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _LocationDetails implements LocationDetails { + const _LocationDetails({this.place_id, this.licence, this.osm_type, this.osm_id, this.lat, this.lon, this.class_, this.type, this.place_rank, this.importance, this.addresstype, this.name, this.display_name, this.address, final List? boundingbox}): _boundingbox = boundingbox; + factory _LocationDetails.fromJson(Map json) => _$LocationDetailsFromJson(json); + +@override final int? place_id; +@override final String? licence; +@override final String? osm_type; +@override final int? osm_id; +@override final String? lat; +@override final String? lon; +@override final String? class_; +@override final String? type; +@override final int? place_rank; +@override final double? importance; +@override final String? addresstype; +@override final String? name; +@override final String? display_name; +@override final Address? address; + final List? _boundingbox; +@override List? get boundingbox { + final value = _boundingbox; + if (value == null) return null; + if (_boundingbox is EqualUnmodifiableListView) return _boundingbox; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LocationDetailsCopyWith<_LocationDetails> get copyWith => __$LocationDetailsCopyWithImpl<_LocationDetails>(this, _$identity); + +@override +Map toJson() { + return _$LocationDetailsToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LocationDetails&&(identical(other.place_id, place_id) || other.place_id == place_id)&&(identical(other.licence, licence) || other.licence == licence)&&(identical(other.osm_type, osm_type) || other.osm_type == osm_type)&&(identical(other.osm_id, osm_id) || other.osm_id == osm_id)&&(identical(other.lat, lat) || other.lat == lat)&&(identical(other.lon, lon) || other.lon == lon)&&(identical(other.class_, class_) || other.class_ == class_)&&(identical(other.type, type) || other.type == type)&&(identical(other.place_rank, place_rank) || other.place_rank == place_rank)&&(identical(other.importance, importance) || other.importance == importance)&&(identical(other.addresstype, addresstype) || other.addresstype == addresstype)&&(identical(other.name, name) || other.name == name)&&(identical(other.display_name, display_name) || other.display_name == display_name)&&(identical(other.address, address) || other.address == address)&&const DeepCollectionEquality().equals(other._boundingbox, _boundingbox)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,place_id,licence,osm_type,osm_id,lat,lon,class_,type,place_rank,importance,addresstype,name,display_name,address,const DeepCollectionEquality().hash(_boundingbox)); + +@override +String toString() { + return 'LocationDetails(place_id: $place_id, licence: $licence, osm_type: $osm_type, osm_id: $osm_id, lat: $lat, lon: $lon, class_: $class_, type: $type, place_rank: $place_rank, importance: $importance, addresstype: $addresstype, name: $name, display_name: $display_name, address: $address, boundingbox: $boundingbox)'; +} + + +} + +/// @nodoc +abstract mixin class _$LocationDetailsCopyWith<$Res> implements $LocationDetailsCopyWith<$Res> { + factory _$LocationDetailsCopyWith(_LocationDetails value, $Res Function(_LocationDetails) _then) = __$LocationDetailsCopyWithImpl; +@override @useResult +$Res call({ + int? place_id, String? licence, String? osm_type, int? osm_id, String? lat, String? lon, String? class_, String? type, int? place_rank, double? importance, String? addresstype, String? name, String? display_name, Address? address, List? boundingbox +}); + + +@override $AddressCopyWith<$Res>? get address; + +} +/// @nodoc +class __$LocationDetailsCopyWithImpl<$Res> + implements _$LocationDetailsCopyWith<$Res> { + __$LocationDetailsCopyWithImpl(this._self, this._then); + + final _LocationDetails _self; + final $Res Function(_LocationDetails) _then; + +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? place_id = freezed,Object? licence = freezed,Object? osm_type = freezed,Object? osm_id = freezed,Object? lat = freezed,Object? lon = freezed,Object? class_ = freezed,Object? type = freezed,Object? place_rank = freezed,Object? importance = freezed,Object? addresstype = freezed,Object? name = freezed,Object? display_name = freezed,Object? address = freezed,Object? boundingbox = freezed,}) { + return _then(_LocationDetails( +place_id: freezed == place_id ? _self.place_id : place_id // ignore: cast_nullable_to_non_nullable +as int?,licence: freezed == licence ? _self.licence : licence // ignore: cast_nullable_to_non_nullable +as String?,osm_type: freezed == osm_type ? _self.osm_type : osm_type // ignore: cast_nullable_to_non_nullable +as String?,osm_id: freezed == osm_id ? _self.osm_id : osm_id // ignore: cast_nullable_to_non_nullable +as int?,lat: freezed == lat ? _self.lat : lat // ignore: cast_nullable_to_non_nullable +as String?,lon: freezed == lon ? _self.lon : lon // ignore: cast_nullable_to_non_nullable +as String?,class_: freezed == class_ ? _self.class_ : class_ // ignore: cast_nullable_to_non_nullable +as String?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as String?,place_rank: freezed == place_rank ? _self.place_rank : place_rank // ignore: cast_nullable_to_non_nullable +as int?,importance: freezed == importance ? _self.importance : importance // ignore: cast_nullable_to_non_nullable +as double?,addresstype: freezed == addresstype ? _self.addresstype : addresstype // ignore: cast_nullable_to_non_nullable +as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String?,display_name: freezed == display_name ? _self.display_name : display_name // ignore: cast_nullable_to_non_nullable +as String?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as Address?,boundingbox: freezed == boundingbox ? _self._boundingbox : boundingbox // ignore: cast_nullable_to_non_nullable +as List?, + )); +} + +/// Create a copy of LocationDetails +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$AddressCopyWith<$Res>? get address { + if (_self.address == null) { + return null; + } + + return $AddressCopyWith<$Res>(_self.address!, (value) { + return _then(_self.copyWith(address: value)); + }); +} +} + +// dart format on diff --git a/packages/livestock/lib/data/model/response/address/address.g.dart b/packages/livestock/lib/data/model/response/address/address.g.dart new file mode 100644 index 0000000..9e5f9aa --- /dev/null +++ b/packages/livestock/lib/data/model/response/address/address.g.dart @@ -0,0 +1,81 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'address.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_Address _$AddressFromJson(Map json) => _Address( + road: json['road'] as String?, + neighbourhood: json['neighbourhood'] as String?, + suburb: json['suburb'] as String?, + state: json['state'] as String?, + borough: json['borough'] as String?, + city: json['city'] as String?, + district: json['district'] as String?, + county: json['county'] as String?, + province: json['province'] as String?, + ISO3166_2_lvl4: json['i_s_o3166_2_lvl4'] as String?, + postcode: json['postcode'] as String?, + country: json['country'] as String?, + country_code: json['country_code'] as String?, +); + +Map _$AddressToJson(_Address instance) => { + 'road': instance.road, + 'neighbourhood': instance.neighbourhood, + 'suburb': instance.suburb, + 'state': instance.state, + 'borough': instance.borough, + 'city': instance.city, + 'district': instance.district, + 'county': instance.county, + 'province': instance.province, + 'i_s_o3166_2_lvl4': instance.ISO3166_2_lvl4, + 'postcode': instance.postcode, + 'country': instance.country, + 'country_code': instance.country_code, +}; + +_LocationDetails _$LocationDetailsFromJson(Map json) => + _LocationDetails( + place_id: (json['place_id'] as num?)?.toInt(), + licence: json['licence'] as String?, + osm_type: json['osm_type'] as String?, + osm_id: (json['osm_id'] as num?)?.toInt(), + lat: json['lat'] as String?, + lon: json['lon'] as String?, + class_: json['class_'] as String?, + type: json['type'] as String?, + place_rank: (json['place_rank'] as num?)?.toInt(), + importance: (json['importance'] as num?)?.toDouble(), + addresstype: json['addresstype'] as String?, + name: json['name'] as String?, + display_name: json['display_name'] as String?, + address: json['address'] == null + ? null + : Address.fromJson(json['address'] as Map), + boundingbox: (json['boundingbox'] as List?) + ?.map((e) => e as String) + .toList(), + ); + +Map _$LocationDetailsToJson(_LocationDetails instance) => + { + 'place_id': instance.place_id, + 'licence': instance.licence, + 'osm_type': instance.osm_type, + 'osm_id': instance.osm_id, + 'lat': instance.lat, + 'lon': instance.lon, + 'class_': instance.class_, + 'type': instance.type, + 'place_rank': instance.place_rank, + 'importance': instance.importance, + 'addresstype': instance.addresstype, + 'name': instance.name, + 'display_name': instance.display_name, + 'address': instance.address, + 'boundingbox': instance.boundingbox, + }; diff --git a/packages/livestock/lib/data/model/response/auth/auth_response_model.dart b/packages/livestock/lib/data/model/response/auth/auth_response_model.dart new file mode 100644 index 0000000..1f5faba --- /dev/null +++ b/packages/livestock/lib/data/model/response/auth/auth_response_model.dart @@ -0,0 +1,20 @@ + + +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_response_model.freezed.dart'; +part 'auth_response_model.g.dart'; + +@freezed +abstract class AuthResponseModel with _$AuthResponseModel { + const factory AuthResponseModel({ + String? refresh, + String? access, + bool? otpStatus, + }) = _AuthResponseModel; + + factory AuthResponseModel.fromJson(Map json) => + _$AuthResponseModelFromJson(json); + +} + diff --git a/packages/livestock/lib/data/model/response/auth/auth_response_model.freezed.dart b/packages/livestock/lib/data/model/response/auth/auth_response_model.freezed.dart new file mode 100644 index 0000000..fdca0fc --- /dev/null +++ b/packages/livestock/lib/data/model/response/auth/auth_response_model.freezed.dart @@ -0,0 +1,283 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_response_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$AuthResponseModel { + + String? get refresh; String? get access; bool? get otpStatus; +/// Create a copy of AuthResponseModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$AuthResponseModelCopyWith get copyWith => _$AuthResponseModelCopyWithImpl(this as AuthResponseModel, _$identity); + + /// Serializes this AuthResponseModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is AuthResponseModel&&(identical(other.refresh, refresh) || other.refresh == refresh)&&(identical(other.access, access) || other.access == access)&&(identical(other.otpStatus, otpStatus) || other.otpStatus == otpStatus)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,refresh,access,otpStatus); + +@override +String toString() { + return 'AuthResponseModel(refresh: $refresh, access: $access, otpStatus: $otpStatus)'; +} + + +} + +/// @nodoc +abstract mixin class $AuthResponseModelCopyWith<$Res> { + factory $AuthResponseModelCopyWith(AuthResponseModel value, $Res Function(AuthResponseModel) _then) = _$AuthResponseModelCopyWithImpl; +@useResult +$Res call({ + String? refresh, String? access, bool? otpStatus +}); + + + + +} +/// @nodoc +class _$AuthResponseModelCopyWithImpl<$Res> + implements $AuthResponseModelCopyWith<$Res> { + _$AuthResponseModelCopyWithImpl(this._self, this._then); + + final AuthResponseModel _self; + final $Res Function(AuthResponseModel) _then; + +/// Create a copy of AuthResponseModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? refresh = freezed,Object? access = freezed,Object? otpStatus = freezed,}) { + return _then(_self.copyWith( +refresh: freezed == refresh ? _self.refresh : refresh // ignore: cast_nullable_to_non_nullable +as String?,access: freezed == access ? _self.access : access // ignore: cast_nullable_to_non_nullable +as String?,otpStatus: freezed == otpStatus ? _self.otpStatus : otpStatus // ignore: cast_nullable_to_non_nullable +as bool?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [AuthResponseModel]. +extension AuthResponseModelPatterns on AuthResponseModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _AuthResponseModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _AuthResponseModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _AuthResponseModel value) $default,){ +final _that = this; +switch (_that) { +case _AuthResponseModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _AuthResponseModel value)? $default,){ +final _that = this; +switch (_that) { +case _AuthResponseModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? refresh, String? access, bool? otpStatus)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _AuthResponseModel() when $default != null: +return $default(_that.refresh,_that.access,_that.otpStatus);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? refresh, String? access, bool? otpStatus) $default,) {final _that = this; +switch (_that) { +case _AuthResponseModel(): +return $default(_that.refresh,_that.access,_that.otpStatus);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? refresh, String? access, bool? otpStatus)? $default,) {final _that = this; +switch (_that) { +case _AuthResponseModel() when $default != null: +return $default(_that.refresh,_that.access,_that.otpStatus);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _AuthResponseModel implements AuthResponseModel { + const _AuthResponseModel({this.refresh, this.access, this.otpStatus}); + factory _AuthResponseModel.fromJson(Map json) => _$AuthResponseModelFromJson(json); + +@override final String? refresh; +@override final String? access; +@override final bool? otpStatus; + +/// Create a copy of AuthResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$AuthResponseModelCopyWith<_AuthResponseModel> get copyWith => __$AuthResponseModelCopyWithImpl<_AuthResponseModel>(this, _$identity); + +@override +Map toJson() { + return _$AuthResponseModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _AuthResponseModel&&(identical(other.refresh, refresh) || other.refresh == refresh)&&(identical(other.access, access) || other.access == access)&&(identical(other.otpStatus, otpStatus) || other.otpStatus == otpStatus)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,refresh,access,otpStatus); + +@override +String toString() { + return 'AuthResponseModel(refresh: $refresh, access: $access, otpStatus: $otpStatus)'; +} + + +} + +/// @nodoc +abstract mixin class _$AuthResponseModelCopyWith<$Res> implements $AuthResponseModelCopyWith<$Res> { + factory _$AuthResponseModelCopyWith(_AuthResponseModel value, $Res Function(_AuthResponseModel) _then) = __$AuthResponseModelCopyWithImpl; +@override @useResult +$Res call({ + String? refresh, String? access, bool? otpStatus +}); + + + + +} +/// @nodoc +class __$AuthResponseModelCopyWithImpl<$Res> + implements _$AuthResponseModelCopyWith<$Res> { + __$AuthResponseModelCopyWithImpl(this._self, this._then); + + final _AuthResponseModel _self; + final $Res Function(_AuthResponseModel) _then; + +/// Create a copy of AuthResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? refresh = freezed,Object? access = freezed,Object? otpStatus = freezed,}) { + return _then(_AuthResponseModel( +refresh: freezed == refresh ? _self.refresh : refresh // ignore: cast_nullable_to_non_nullable +as String?,access: freezed == access ? _self.access : access // ignore: cast_nullable_to_non_nullable +as String?,otpStatus: freezed == otpStatus ? _self.otpStatus : otpStatus // ignore: cast_nullable_to_non_nullable +as bool?, + )); +} + + +} + +// dart format on diff --git a/packages/livestock/lib/data/model/response/auth/auth_response_model.g.dart b/packages/livestock/lib/data/model/response/auth/auth_response_model.g.dart new file mode 100644 index 0000000..dc5d66d --- /dev/null +++ b/packages/livestock/lib/data/model/response/auth/auth_response_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_response_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_AuthResponseModel _$AuthResponseModelFromJson(Map json) => + _AuthResponseModel( + refresh: json['refresh'] as String?, + access: json['access'] as String?, + otpStatus: json['otp_status'] as bool?, + ); + +Map _$AuthResponseModelToJson(_AuthResponseModel instance) => + { + 'refresh': instance.refresh, + 'access': instance.access, + 'otp_status': instance.otpStatus, + }; diff --git a/packages/livestock/lib/data/model/response/captcha/captcha_response_model.dart b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.dart new file mode 100644 index 0000000..2b2f986 --- /dev/null +++ b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'captcha_response_model.freezed.dart'; +part 'captcha_response_model.g.dart'; + +@freezed +abstract class CaptchaResponseModel with _$CaptchaResponseModel { + const factory CaptchaResponseModel({ + String? captchaKey, + String? captchaImage, + String? imageType, + String? imageDecode, + }) = _CaptchaResponseModel; + + factory CaptchaResponseModel.fromJson(Map json) => + _$CaptchaResponseModelFromJson(json); +} diff --git a/packages/livestock/lib/data/model/response/captcha/captcha_response_model.freezed.dart b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.freezed.dart new file mode 100644 index 0000000..33d0167 --- /dev/null +++ b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.freezed.dart @@ -0,0 +1,286 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'captcha_response_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$CaptchaResponseModel { + + String? get captchaKey; String? get captchaImage; String? get imageType; String? get imageDecode; +/// Create a copy of CaptchaResponseModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$CaptchaResponseModelCopyWith get copyWith => _$CaptchaResponseModelCopyWithImpl(this as CaptchaResponseModel, _$identity); + + /// Serializes this CaptchaResponseModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is CaptchaResponseModel&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey)&&(identical(other.captchaImage, captchaImage) || other.captchaImage == captchaImage)&&(identical(other.imageType, imageType) || other.imageType == imageType)&&(identical(other.imageDecode, imageDecode) || other.imageDecode == imageDecode)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,captchaKey,captchaImage,imageType,imageDecode); + +@override +String toString() { + return 'CaptchaResponseModel(captchaKey: $captchaKey, captchaImage: $captchaImage, imageType: $imageType, imageDecode: $imageDecode)'; +} + + +} + +/// @nodoc +abstract mixin class $CaptchaResponseModelCopyWith<$Res> { + factory $CaptchaResponseModelCopyWith(CaptchaResponseModel value, $Res Function(CaptchaResponseModel) _then) = _$CaptchaResponseModelCopyWithImpl; +@useResult +$Res call({ + String? captchaKey, String? captchaImage, String? imageType, String? imageDecode +}); + + + + +} +/// @nodoc +class _$CaptchaResponseModelCopyWithImpl<$Res> + implements $CaptchaResponseModelCopyWith<$Res> { + _$CaptchaResponseModelCopyWithImpl(this._self, this._then); + + final CaptchaResponseModel _self; + final $Res Function(CaptchaResponseModel) _then; + +/// Create a copy of CaptchaResponseModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? captchaKey = freezed,Object? captchaImage = freezed,Object? imageType = freezed,Object? imageDecode = freezed,}) { + return _then(_self.copyWith( +captchaKey: freezed == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable +as String?,captchaImage: freezed == captchaImage ? _self.captchaImage : captchaImage // ignore: cast_nullable_to_non_nullable +as String?,imageType: freezed == imageType ? _self.imageType : imageType // ignore: cast_nullable_to_non_nullable +as String?,imageDecode: freezed == imageDecode ? _self.imageDecode : imageDecode // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [CaptchaResponseModel]. +extension CaptchaResponseModelPatterns on CaptchaResponseModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _CaptchaResponseModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _CaptchaResponseModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _CaptchaResponseModel value) $default,){ +final _that = this; +switch (_that) { +case _CaptchaResponseModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _CaptchaResponseModel value)? $default,){ +final _that = this; +switch (_that) { +case _CaptchaResponseModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? captchaKey, String? captchaImage, String? imageType, String? imageDecode)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _CaptchaResponseModel() when $default != null: +return $default(_that.captchaKey,_that.captchaImage,_that.imageType,_that.imageDecode);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? captchaKey, String? captchaImage, String? imageType, String? imageDecode) $default,) {final _that = this; +switch (_that) { +case _CaptchaResponseModel(): +return $default(_that.captchaKey,_that.captchaImage,_that.imageType,_that.imageDecode);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? captchaKey, String? captchaImage, String? imageType, String? imageDecode)? $default,) {final _that = this; +switch (_that) { +case _CaptchaResponseModel() when $default != null: +return $default(_that.captchaKey,_that.captchaImage,_that.imageType,_that.imageDecode);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _CaptchaResponseModel implements CaptchaResponseModel { + const _CaptchaResponseModel({this.captchaKey, this.captchaImage, this.imageType, this.imageDecode}); + factory _CaptchaResponseModel.fromJson(Map json) => _$CaptchaResponseModelFromJson(json); + +@override final String? captchaKey; +@override final String? captchaImage; +@override final String? imageType; +@override final String? imageDecode; + +/// Create a copy of CaptchaResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$CaptchaResponseModelCopyWith<_CaptchaResponseModel> get copyWith => __$CaptchaResponseModelCopyWithImpl<_CaptchaResponseModel>(this, _$identity); + +@override +Map toJson() { + return _$CaptchaResponseModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _CaptchaResponseModel&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey)&&(identical(other.captchaImage, captchaImage) || other.captchaImage == captchaImage)&&(identical(other.imageType, imageType) || other.imageType == imageType)&&(identical(other.imageDecode, imageDecode) || other.imageDecode == imageDecode)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,captchaKey,captchaImage,imageType,imageDecode); + +@override +String toString() { + return 'CaptchaResponseModel(captchaKey: $captchaKey, captchaImage: $captchaImage, imageType: $imageType, imageDecode: $imageDecode)'; +} + + +} + +/// @nodoc +abstract mixin class _$CaptchaResponseModelCopyWith<$Res> implements $CaptchaResponseModelCopyWith<$Res> { + factory _$CaptchaResponseModelCopyWith(_CaptchaResponseModel value, $Res Function(_CaptchaResponseModel) _then) = __$CaptchaResponseModelCopyWithImpl; +@override @useResult +$Res call({ + String? captchaKey, String? captchaImage, String? imageType, String? imageDecode +}); + + + + +} +/// @nodoc +class __$CaptchaResponseModelCopyWithImpl<$Res> + implements _$CaptchaResponseModelCopyWith<$Res> { + __$CaptchaResponseModelCopyWithImpl(this._self, this._then); + + final _CaptchaResponseModel _self; + final $Res Function(_CaptchaResponseModel) _then; + +/// Create a copy of CaptchaResponseModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? captchaKey = freezed,Object? captchaImage = freezed,Object? imageType = freezed,Object? imageDecode = freezed,}) { + return _then(_CaptchaResponseModel( +captchaKey: freezed == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable +as String?,captchaImage: freezed == captchaImage ? _self.captchaImage : captchaImage // ignore: cast_nullable_to_non_nullable +as String?,imageType: freezed == imageType ? _self.imageType : imageType // ignore: cast_nullable_to_non_nullable +as String?,imageDecode: freezed == imageDecode ? _self.imageDecode : imageDecode // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/packages/livestock/lib/data/model/response/captcha/captcha_response_model.g.dart b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.g.dart new file mode 100644 index 0000000..8d69248 --- /dev/null +++ b/packages/livestock/lib/data/model/response/captcha/captcha_response_model.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'captcha_response_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_CaptchaResponseModel _$CaptchaResponseModelFromJson( + Map json, +) => _CaptchaResponseModel( + captchaKey: json['captcha_key'] as String?, + captchaImage: json['captcha_image'] as String?, + imageType: json['image_type'] as String?, + imageDecode: json['image_decode'] as String?, +); + +Map _$CaptchaResponseModelToJson( + _CaptchaResponseModel instance, +) => { + 'captcha_key': instance.captchaKey, + 'captcha_image': instance.captchaImage, + 'image_type': instance.imageType, + 'image_decode': instance.imageDecode, +}; diff --git a/packages/livestock/lib/data/model/response/live_tmp/livestock_model.dart b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.dart new file mode 100644 index 0000000..2f44488 --- /dev/null +++ b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.dart @@ -0,0 +1,50 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'livestock_model.freezed.dart'; +part 'livestock_model.g.dart'; + +@freezed +abstract class LivestockData with _$LivestockData { + const factory LivestockData({Rancher? rancher, Herd? herd, List? livestock}) = + _LivestockData; + + factory LivestockData.fromJson(Map json) => _$LivestockDataFromJson(json); +} + +@freezed +abstract class Rancher with _$Rancher { + const factory Rancher({String? name, String? phone, String? image}) = _Rancher; + + factory Rancher.fromJson(Map json) => _$RancherFromJson(json); +} + +@freezed +abstract class Herd with _$Herd { + const factory Herd({Location? location, String? address, String? image}) = _Herd; + + factory Herd.fromJson(Map json) => _$HerdFromJson(json); +} + +@freezed +abstract class Location with _$Location { + const factory Location({double? lat, double? lng}) = _Location; + + factory Location.fromJson(Map json) => _$LocationFromJson(json); +} + +@freezed +abstract class Livestock with _$Livestock { + const factory Livestock({ + String? species, + String? breed, + String? dateOfBirth, + String? sex, + String? motherTag, + String? fatherTag, + String? tagNumber, + String? tagType, + String? image, + }) = _Livestock; + + factory Livestock.fromJson(Map json) => _$LivestockFromJson(json); +} diff --git a/packages/livestock/lib/data/model/response/live_tmp/livestock_model.freezed.dart b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.freezed.dart new file mode 100644 index 0000000..bc8da48 --- /dev/null +++ b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.freezed.dart @@ -0,0 +1,1454 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'livestock_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$LivestockData { + + Rancher? get rancher; Herd? get herd; List? get livestock; +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LivestockDataCopyWith get copyWith => _$LivestockDataCopyWithImpl(this as LivestockData, _$identity); + + /// Serializes this LivestockData to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is LivestockData&&(identical(other.rancher, rancher) || other.rancher == rancher)&&(identical(other.herd, herd) || other.herd == herd)&&const DeepCollectionEquality().equals(other.livestock, livestock)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,rancher,herd,const DeepCollectionEquality().hash(livestock)); + +@override +String toString() { + return 'LivestockData(rancher: $rancher, herd: $herd, livestock: $livestock)'; +} + + +} + +/// @nodoc +abstract mixin class $LivestockDataCopyWith<$Res> { + factory $LivestockDataCopyWith(LivestockData value, $Res Function(LivestockData) _then) = _$LivestockDataCopyWithImpl; +@useResult +$Res call({ + Rancher? rancher, Herd? herd, List? livestock +}); + + +$RancherCopyWith<$Res>? get rancher;$HerdCopyWith<$Res>? get herd; + +} +/// @nodoc +class _$LivestockDataCopyWithImpl<$Res> + implements $LivestockDataCopyWith<$Res> { + _$LivestockDataCopyWithImpl(this._self, this._then); + + final LivestockData _self; + final $Res Function(LivestockData) _then; + +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? rancher = freezed,Object? herd = freezed,Object? livestock = freezed,}) { + return _then(_self.copyWith( +rancher: freezed == rancher ? _self.rancher : rancher // ignore: cast_nullable_to_non_nullable +as Rancher?,herd: freezed == herd ? _self.herd : herd // ignore: cast_nullable_to_non_nullable +as Herd?,livestock: freezed == livestock ? _self.livestock : livestock // ignore: cast_nullable_to_non_nullable +as List?, + )); +} +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RancherCopyWith<$Res>? get rancher { + if (_self.rancher == null) { + return null; + } + + return $RancherCopyWith<$Res>(_self.rancher!, (value) { + return _then(_self.copyWith(rancher: value)); + }); +}/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HerdCopyWith<$Res>? get herd { + if (_self.herd == null) { + return null; + } + + return $HerdCopyWith<$Res>(_self.herd!, (value) { + return _then(_self.copyWith(herd: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [LivestockData]. +extension LivestockDataPatterns on LivestockData { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _LivestockData value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _LivestockData() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _LivestockData value) $default,){ +final _that = this; +switch (_that) { +case _LivestockData(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _LivestockData value)? $default,){ +final _that = this; +switch (_that) { +case _LivestockData() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( Rancher? rancher, Herd? herd, List? livestock)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _LivestockData() when $default != null: +return $default(_that.rancher,_that.herd,_that.livestock);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( Rancher? rancher, Herd? herd, List? livestock) $default,) {final _that = this; +switch (_that) { +case _LivestockData(): +return $default(_that.rancher,_that.herd,_that.livestock);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( Rancher? rancher, Herd? herd, List? livestock)? $default,) {final _that = this; +switch (_that) { +case _LivestockData() when $default != null: +return $default(_that.rancher,_that.herd,_that.livestock);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _LivestockData implements LivestockData { + const _LivestockData({this.rancher, this.herd, final List? livestock}): _livestock = livestock; + factory _LivestockData.fromJson(Map json) => _$LivestockDataFromJson(json); + +@override final Rancher? rancher; +@override final Herd? herd; + final List? _livestock; +@override List? get livestock { + final value = _livestock; + if (value == null) return null; + if (_livestock is EqualUnmodifiableListView) return _livestock; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); +} + + +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LivestockDataCopyWith<_LivestockData> get copyWith => __$LivestockDataCopyWithImpl<_LivestockData>(this, _$identity); + +@override +Map toJson() { + return _$LivestockDataToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _LivestockData&&(identical(other.rancher, rancher) || other.rancher == rancher)&&(identical(other.herd, herd) || other.herd == herd)&&const DeepCollectionEquality().equals(other._livestock, _livestock)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,rancher,herd,const DeepCollectionEquality().hash(_livestock)); + +@override +String toString() { + return 'LivestockData(rancher: $rancher, herd: $herd, livestock: $livestock)'; +} + + +} + +/// @nodoc +abstract mixin class _$LivestockDataCopyWith<$Res> implements $LivestockDataCopyWith<$Res> { + factory _$LivestockDataCopyWith(_LivestockData value, $Res Function(_LivestockData) _then) = __$LivestockDataCopyWithImpl; +@override @useResult +$Res call({ + Rancher? rancher, Herd? herd, List? livestock +}); + + +@override $RancherCopyWith<$Res>? get rancher;@override $HerdCopyWith<$Res>? get herd; + +} +/// @nodoc +class __$LivestockDataCopyWithImpl<$Res> + implements _$LivestockDataCopyWith<$Res> { + __$LivestockDataCopyWithImpl(this._self, this._then); + + final _LivestockData _self; + final $Res Function(_LivestockData) _then; + +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? rancher = freezed,Object? herd = freezed,Object? livestock = freezed,}) { + return _then(_LivestockData( +rancher: freezed == rancher ? _self.rancher : rancher // ignore: cast_nullable_to_non_nullable +as Rancher?,herd: freezed == herd ? _self.herd : herd // ignore: cast_nullable_to_non_nullable +as Herd?,livestock: freezed == livestock ? _self._livestock : livestock // ignore: cast_nullable_to_non_nullable +as List?, + )); +} + +/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RancherCopyWith<$Res>? get rancher { + if (_self.rancher == null) { + return null; + } + + return $RancherCopyWith<$Res>(_self.rancher!, (value) { + return _then(_self.copyWith(rancher: value)); + }); +}/// Create a copy of LivestockData +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$HerdCopyWith<$Res>? get herd { + if (_self.herd == null) { + return null; + } + + return $HerdCopyWith<$Res>(_self.herd!, (value) { + return _then(_self.copyWith(herd: value)); + }); +} +} + + +/// @nodoc +mixin _$Rancher { + + String? get name; String? get phone; String? get image; +/// Create a copy of Rancher +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RancherCopyWith get copyWith => _$RancherCopyWithImpl(this as Rancher, _$identity); + + /// Serializes this Rancher to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Rancher&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,name,phone,image); + +@override +String toString() { + return 'Rancher(name: $name, phone: $phone, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class $RancherCopyWith<$Res> { + factory $RancherCopyWith(Rancher value, $Res Function(Rancher) _then) = _$RancherCopyWithImpl; +@useResult +$Res call({ + String? name, String? phone, String? image +}); + + + + +} +/// @nodoc +class _$RancherCopyWithImpl<$Res> + implements $RancherCopyWith<$Res> { + _$RancherCopyWithImpl(this._self, this._then); + + final Rancher _self; + final $Res Function(Rancher) _then; + +/// Create a copy of Rancher +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? name = freezed,Object? phone = freezed,Object? image = freezed,}) { + return _then(_self.copyWith( +name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String?,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Rancher]. +extension RancherPatterns on Rancher { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Rancher value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Rancher() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Rancher value) $default,){ +final _that = this; +switch (_that) { +case _Rancher(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Rancher value)? $default,){ +final _that = this; +switch (_that) { +case _Rancher() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? name, String? phone, String? image)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Rancher() when $default != null: +return $default(_that.name,_that.phone,_that.image);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? name, String? phone, String? image) $default,) {final _that = this; +switch (_that) { +case _Rancher(): +return $default(_that.name,_that.phone,_that.image);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? name, String? phone, String? image)? $default,) {final _that = this; +switch (_that) { +case _Rancher() when $default != null: +return $default(_that.name,_that.phone,_that.image);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Rancher implements Rancher { + const _Rancher({this.name, this.phone, this.image}); + factory _Rancher.fromJson(Map json) => _$RancherFromJson(json); + +@override final String? name; +@override final String? phone; +@override final String? image; + +/// Create a copy of Rancher +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RancherCopyWith<_Rancher> get copyWith => __$RancherCopyWithImpl<_Rancher>(this, _$identity); + +@override +Map toJson() { + return _$RancherToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Rancher&&(identical(other.name, name) || other.name == name)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,name,phone,image); + +@override +String toString() { + return 'Rancher(name: $name, phone: $phone, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class _$RancherCopyWith<$Res> implements $RancherCopyWith<$Res> { + factory _$RancherCopyWith(_Rancher value, $Res Function(_Rancher) _then) = __$RancherCopyWithImpl; +@override @useResult +$Res call({ + String? name, String? phone, String? image +}); + + + + +} +/// @nodoc +class __$RancherCopyWithImpl<$Res> + implements _$RancherCopyWith<$Res> { + __$RancherCopyWithImpl(this._self, this._then); + + final _Rancher _self; + final $Res Function(_Rancher) _then; + +/// Create a copy of Rancher +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? name = freezed,Object? phone = freezed,Object? image = freezed,}) { + return _then(_Rancher( +name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String?,phone: freezed == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + + +/// @nodoc +mixin _$Herd { + + Location? get location; String? get address; String? get image; +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$HerdCopyWith get copyWith => _$HerdCopyWithImpl(this as Herd, _$identity); + + /// Serializes this Herd to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Herd&&(identical(other.location, location) || other.location == location)&&(identical(other.address, address) || other.address == address)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,location,address,image); + +@override +String toString() { + return 'Herd(location: $location, address: $address, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class $HerdCopyWith<$Res> { + factory $HerdCopyWith(Herd value, $Res Function(Herd) _then) = _$HerdCopyWithImpl; +@useResult +$Res call({ + Location? location, String? address, String? image +}); + + +$LocationCopyWith<$Res>? get location; + +} +/// @nodoc +class _$HerdCopyWithImpl<$Res> + implements $HerdCopyWith<$Res> { + _$HerdCopyWithImpl(this._self, this._then); + + final Herd _self; + final $Res Function(Herd) _then; + +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? location = freezed,Object? address = freezed,Object? image = freezed,}) { + return _then(_self.copyWith( +location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable +as Location?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$LocationCopyWith<$Res>? get location { + if (_self.location == null) { + return null; + } + + return $LocationCopyWith<$Res>(_self.location!, (value) { + return _then(_self.copyWith(location: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [Herd]. +extension HerdPatterns on Herd { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Herd value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Herd() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Herd value) $default,){ +final _that = this; +switch (_that) { +case _Herd(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Herd value)? $default,){ +final _that = this; +switch (_that) { +case _Herd() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( Location? location, String? address, String? image)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Herd() when $default != null: +return $default(_that.location,_that.address,_that.image);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( Location? location, String? address, String? image) $default,) {final _that = this; +switch (_that) { +case _Herd(): +return $default(_that.location,_that.address,_that.image);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( Location? location, String? address, String? image)? $default,) {final _that = this; +switch (_that) { +case _Herd() when $default != null: +return $default(_that.location,_that.address,_that.image);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Herd implements Herd { + const _Herd({this.location, this.address, this.image}); + factory _Herd.fromJson(Map json) => _$HerdFromJson(json); + +@override final Location? location; +@override final String? address; +@override final String? image; + +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$HerdCopyWith<_Herd> get copyWith => __$HerdCopyWithImpl<_Herd>(this, _$identity); + +@override +Map toJson() { + return _$HerdToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Herd&&(identical(other.location, location) || other.location == location)&&(identical(other.address, address) || other.address == address)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,location,address,image); + +@override +String toString() { + return 'Herd(location: $location, address: $address, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class _$HerdCopyWith<$Res> implements $HerdCopyWith<$Res> { + factory _$HerdCopyWith(_Herd value, $Res Function(_Herd) _then) = __$HerdCopyWithImpl; +@override @useResult +$Res call({ + Location? location, String? address, String? image +}); + + +@override $LocationCopyWith<$Res>? get location; + +} +/// @nodoc +class __$HerdCopyWithImpl<$Res> + implements _$HerdCopyWith<$Res> { + __$HerdCopyWithImpl(this._self, this._then); + + final _Herd _self; + final $Res Function(_Herd) _then; + +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? location = freezed,Object? address = freezed,Object? image = freezed,}) { + return _then(_Herd( +location: freezed == location ? _self.location : location // ignore: cast_nullable_to_non_nullable +as Location?,address: freezed == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +/// Create a copy of Herd +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$LocationCopyWith<$Res>? get location { + if (_self.location == null) { + return null; + } + + return $LocationCopyWith<$Res>(_self.location!, (value) { + return _then(_self.copyWith(location: value)); + }); +} +} + + +/// @nodoc +mixin _$Location { + + double? get lat; double? get lng; +/// Create a copy of Location +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LocationCopyWith get copyWith => _$LocationCopyWithImpl(this as Location, _$identity); + + /// Serializes this Location to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Location&&(identical(other.lat, lat) || other.lat == lat)&&(identical(other.lng, lng) || other.lng == lng)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,lat,lng); + +@override +String toString() { + return 'Location(lat: $lat, lng: $lng)'; +} + + +} + +/// @nodoc +abstract mixin class $LocationCopyWith<$Res> { + factory $LocationCopyWith(Location value, $Res Function(Location) _then) = _$LocationCopyWithImpl; +@useResult +$Res call({ + double? lat, double? lng +}); + + + + +} +/// @nodoc +class _$LocationCopyWithImpl<$Res> + implements $LocationCopyWith<$Res> { + _$LocationCopyWithImpl(this._self, this._then); + + final Location _self; + final $Res Function(Location) _then; + +/// Create a copy of Location +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? lat = freezed,Object? lng = freezed,}) { + return _then(_self.copyWith( +lat: freezed == lat ? _self.lat : lat // ignore: cast_nullable_to_non_nullable +as double?,lng: freezed == lng ? _self.lng : lng // ignore: cast_nullable_to_non_nullable +as double?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Location]. +extension LocationPatterns on Location { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Location value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Location() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Location value) $default,){ +final _that = this; +switch (_that) { +case _Location(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Location value)? $default,){ +final _that = this; +switch (_that) { +case _Location() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( double? lat, double? lng)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Location() when $default != null: +return $default(_that.lat,_that.lng);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( double? lat, double? lng) $default,) {final _that = this; +switch (_that) { +case _Location(): +return $default(_that.lat,_that.lng);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( double? lat, double? lng)? $default,) {final _that = this; +switch (_that) { +case _Location() when $default != null: +return $default(_that.lat,_that.lng);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Location implements Location { + const _Location({this.lat, this.lng}); + factory _Location.fromJson(Map json) => _$LocationFromJson(json); + +@override final double? lat; +@override final double? lng; + +/// Create a copy of Location +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LocationCopyWith<_Location> get copyWith => __$LocationCopyWithImpl<_Location>(this, _$identity); + +@override +Map toJson() { + return _$LocationToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Location&&(identical(other.lat, lat) || other.lat == lat)&&(identical(other.lng, lng) || other.lng == lng)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,lat,lng); + +@override +String toString() { + return 'Location(lat: $lat, lng: $lng)'; +} + + +} + +/// @nodoc +abstract mixin class _$LocationCopyWith<$Res> implements $LocationCopyWith<$Res> { + factory _$LocationCopyWith(_Location value, $Res Function(_Location) _then) = __$LocationCopyWithImpl; +@override @useResult +$Res call({ + double? lat, double? lng +}); + + + + +} +/// @nodoc +class __$LocationCopyWithImpl<$Res> + implements _$LocationCopyWith<$Res> { + __$LocationCopyWithImpl(this._self, this._then); + + final _Location _self; + final $Res Function(_Location) _then; + +/// Create a copy of Location +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? lat = freezed,Object? lng = freezed,}) { + return _then(_Location( +lat: freezed == lat ? _self.lat : lat // ignore: cast_nullable_to_non_nullable +as double?,lng: freezed == lng ? _self.lng : lng // ignore: cast_nullable_to_non_nullable +as double?, + )); +} + + +} + + +/// @nodoc +mixin _$Livestock { + + String? get species; String? get breed; String? get dateOfBirth; String? get sex; String? get motherTag; String? get fatherTag; String? get tagNumber; String? get tagType; String? get image; +/// Create a copy of Livestock +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$LivestockCopyWith get copyWith => _$LivestockCopyWithImpl(this as Livestock, _$identity); + + /// Serializes this Livestock to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Livestock&&(identical(other.species, species) || other.species == species)&&(identical(other.breed, breed) || other.breed == breed)&&(identical(other.dateOfBirth, dateOfBirth) || other.dateOfBirth == dateOfBirth)&&(identical(other.sex, sex) || other.sex == sex)&&(identical(other.motherTag, motherTag) || other.motherTag == motherTag)&&(identical(other.fatherTag, fatherTag) || other.fatherTag == fatherTag)&&(identical(other.tagNumber, tagNumber) || other.tagNumber == tagNumber)&&(identical(other.tagType, tagType) || other.tagType == tagType)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,species,breed,dateOfBirth,sex,motherTag,fatherTag,tagNumber,tagType,image); + +@override +String toString() { + return 'Livestock(species: $species, breed: $breed, dateOfBirth: $dateOfBirth, sex: $sex, motherTag: $motherTag, fatherTag: $fatherTag, tagNumber: $tagNumber, tagType: $tagType, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class $LivestockCopyWith<$Res> { + factory $LivestockCopyWith(Livestock value, $Res Function(Livestock) _then) = _$LivestockCopyWithImpl; +@useResult +$Res call({ + String? species, String? breed, String? dateOfBirth, String? sex, String? motherTag, String? fatherTag, String? tagNumber, String? tagType, String? image +}); + + + + +} +/// @nodoc +class _$LivestockCopyWithImpl<$Res> + implements $LivestockCopyWith<$Res> { + _$LivestockCopyWithImpl(this._self, this._then); + + final Livestock _self; + final $Res Function(Livestock) _then; + +/// Create a copy of Livestock +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? species = freezed,Object? breed = freezed,Object? dateOfBirth = freezed,Object? sex = freezed,Object? motherTag = freezed,Object? fatherTag = freezed,Object? tagNumber = freezed,Object? tagType = freezed,Object? image = freezed,}) { + return _then(_self.copyWith( +species: freezed == species ? _self.species : species // ignore: cast_nullable_to_non_nullable +as String?,breed: freezed == breed ? _self.breed : breed // ignore: cast_nullable_to_non_nullable +as String?,dateOfBirth: freezed == dateOfBirth ? _self.dateOfBirth : dateOfBirth // ignore: cast_nullable_to_non_nullable +as String?,sex: freezed == sex ? _self.sex : sex // ignore: cast_nullable_to_non_nullable +as String?,motherTag: freezed == motherTag ? _self.motherTag : motherTag // ignore: cast_nullable_to_non_nullable +as String?,fatherTag: freezed == fatherTag ? _self.fatherTag : fatherTag // ignore: cast_nullable_to_non_nullable +as String?,tagNumber: freezed == tagNumber ? _self.tagNumber : tagNumber // ignore: cast_nullable_to_non_nullable +as String?,tagType: freezed == tagType ? _self.tagType : tagType // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Livestock]. +extension LivestockPatterns on Livestock { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Livestock value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Livestock() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Livestock value) $default,){ +final _that = this; +switch (_that) { +case _Livestock(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Livestock value)? $default,){ +final _that = this; +switch (_that) { +case _Livestock() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? species, String? breed, String? dateOfBirth, String? sex, String? motherTag, String? fatherTag, String? tagNumber, String? tagType, String? image)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Livestock() when $default != null: +return $default(_that.species,_that.breed,_that.dateOfBirth,_that.sex,_that.motherTag,_that.fatherTag,_that.tagNumber,_that.tagType,_that.image);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? species, String? breed, String? dateOfBirth, String? sex, String? motherTag, String? fatherTag, String? tagNumber, String? tagType, String? image) $default,) {final _that = this; +switch (_that) { +case _Livestock(): +return $default(_that.species,_that.breed,_that.dateOfBirth,_that.sex,_that.motherTag,_that.fatherTag,_that.tagNumber,_that.tagType,_that.image);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? species, String? breed, String? dateOfBirth, String? sex, String? motherTag, String? fatherTag, String? tagNumber, String? tagType, String? image)? $default,) {final _that = this; +switch (_that) { +case _Livestock() when $default != null: +return $default(_that.species,_that.breed,_that.dateOfBirth,_that.sex,_that.motherTag,_that.fatherTag,_that.tagNumber,_that.tagType,_that.image);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Livestock implements Livestock { + const _Livestock({this.species, this.breed, this.dateOfBirth, this.sex, this.motherTag, this.fatherTag, this.tagNumber, this.tagType, this.image}); + factory _Livestock.fromJson(Map json) => _$LivestockFromJson(json); + +@override final String? species; +@override final String? breed; +@override final String? dateOfBirth; +@override final String? sex; +@override final String? motherTag; +@override final String? fatherTag; +@override final String? tagNumber; +@override final String? tagType; +@override final String? image; + +/// Create a copy of Livestock +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$LivestockCopyWith<_Livestock> get copyWith => __$LivestockCopyWithImpl<_Livestock>(this, _$identity); + +@override +Map toJson() { + return _$LivestockToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Livestock&&(identical(other.species, species) || other.species == species)&&(identical(other.breed, breed) || other.breed == breed)&&(identical(other.dateOfBirth, dateOfBirth) || other.dateOfBirth == dateOfBirth)&&(identical(other.sex, sex) || other.sex == sex)&&(identical(other.motherTag, motherTag) || other.motherTag == motherTag)&&(identical(other.fatherTag, fatherTag) || other.fatherTag == fatherTag)&&(identical(other.tagNumber, tagNumber) || other.tagNumber == tagNumber)&&(identical(other.tagType, tagType) || other.tagType == tagType)&&(identical(other.image, image) || other.image == image)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,species,breed,dateOfBirth,sex,motherTag,fatherTag,tagNumber,tagType,image); + +@override +String toString() { + return 'Livestock(species: $species, breed: $breed, dateOfBirth: $dateOfBirth, sex: $sex, motherTag: $motherTag, fatherTag: $fatherTag, tagNumber: $tagNumber, tagType: $tagType, image: $image)'; +} + + +} + +/// @nodoc +abstract mixin class _$LivestockCopyWith<$Res> implements $LivestockCopyWith<$Res> { + factory _$LivestockCopyWith(_Livestock value, $Res Function(_Livestock) _then) = __$LivestockCopyWithImpl; +@override @useResult +$Res call({ + String? species, String? breed, String? dateOfBirth, String? sex, String? motherTag, String? fatherTag, String? tagNumber, String? tagType, String? image +}); + + + + +} +/// @nodoc +class __$LivestockCopyWithImpl<$Res> + implements _$LivestockCopyWith<$Res> { + __$LivestockCopyWithImpl(this._self, this._then); + + final _Livestock _self; + final $Res Function(_Livestock) _then; + +/// Create a copy of Livestock +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? species = freezed,Object? breed = freezed,Object? dateOfBirth = freezed,Object? sex = freezed,Object? motherTag = freezed,Object? fatherTag = freezed,Object? tagNumber = freezed,Object? tagType = freezed,Object? image = freezed,}) { + return _then(_Livestock( +species: freezed == species ? _self.species : species // ignore: cast_nullable_to_non_nullable +as String?,breed: freezed == breed ? _self.breed : breed // ignore: cast_nullable_to_non_nullable +as String?,dateOfBirth: freezed == dateOfBirth ? _self.dateOfBirth : dateOfBirth // ignore: cast_nullable_to_non_nullable +as String?,sex: freezed == sex ? _self.sex : sex // ignore: cast_nullable_to_non_nullable +as String?,motherTag: freezed == motherTag ? _self.motherTag : motherTag // ignore: cast_nullable_to_non_nullable +as String?,fatherTag: freezed == fatherTag ? _self.fatherTag : fatherTag // ignore: cast_nullable_to_non_nullable +as String?,tagNumber: freezed == tagNumber ? _self.tagNumber : tagNumber // ignore: cast_nullable_to_non_nullable +as String?,tagType: freezed == tagType ? _self.tagType : tagType // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable +as String?, + )); +} + + +} + +// dart format on diff --git a/packages/livestock/lib/data/model/response/live_tmp/livestock_model.g.dart b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.g.dart new file mode 100644 index 0000000..e011449 --- /dev/null +++ b/packages/livestock/lib/data/model/response/live_tmp/livestock_model.g.dart @@ -0,0 +1,88 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'livestock_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_LivestockData _$LivestockDataFromJson(Map json) => + _LivestockData( + rancher: json['rancher'] == null + ? null + : Rancher.fromJson(json['rancher'] as Map), + herd: json['herd'] == null + ? null + : Herd.fromJson(json['herd'] as Map), + livestock: (json['livestock'] as List?) + ?.map((e) => Livestock.fromJson(e as Map)) + .toList(), + ); + +Map _$LivestockDataToJson(_LivestockData instance) => + { + 'rancher': instance.rancher, + 'herd': instance.herd, + 'livestock': instance.livestock, + }; + +_Rancher _$RancherFromJson(Map json) => _Rancher( + name: json['name'] as String?, + phone: json['phone'] as String?, + image: json['image'] as String?, +); + +Map _$RancherToJson(_Rancher instance) => { + 'name': instance.name, + 'phone': instance.phone, + 'image': instance.image, +}; + +_Herd _$HerdFromJson(Map json) => _Herd( + location: json['location'] == null + ? null + : Location.fromJson(json['location'] as Map), + address: json['address'] as String?, + image: json['image'] as String?, +); + +Map _$HerdToJson(_Herd instance) => { + 'location': instance.location, + 'address': instance.address, + 'image': instance.image, +}; + +_Location _$LocationFromJson(Map json) => _Location( + lat: (json['lat'] as num?)?.toDouble(), + lng: (json['lng'] as num?)?.toDouble(), +); + +Map _$LocationToJson(_Location instance) => { + 'lat': instance.lat, + 'lng': instance.lng, +}; + +_Livestock _$LivestockFromJson(Map json) => _Livestock( + species: json['species'] as String?, + breed: json['breed'] as String?, + dateOfBirth: json['date_of_birth'] as String?, + sex: json['sex'] as String?, + motherTag: json['mother_tag'] as String?, + fatherTag: json['father_tag'] as String?, + tagNumber: json['tag_number'] as String?, + tagType: json['tag_type'] as String?, + image: json['image'] as String?, +); + +Map _$LivestockToJson(_Livestock instance) => + { + 'species': instance.species, + 'breed': instance.breed, + 'date_of_birth': instance.dateOfBirth, + 'sex': instance.sex, + 'mother_tag': instance.motherTag, + 'father_tag': instance.fatherTag, + 'tag_number': instance.tagNumber, + 'tag_type': instance.tagType, + 'image': instance.image, + }; diff --git a/packages/livestock/lib/data/model/response/user_profile/user_profile_model.dart b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.dart new file mode 100644 index 0000000..a9dea06 --- /dev/null +++ b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.dart @@ -0,0 +1,73 @@ +import 'package:rasadyar_core/core.dart'; + +part 'user_profile_model.freezed.dart'; + +part 'user_profile_model.g.dart'; + +@freezed +abstract class UserProfileModel with _$UserProfileModel { + const factory UserProfileModel({ + required User user, + required Role role, + required List permissions, + }) = _UserProfileModel; + + factory UserProfileModel.fromJson(Map json) => _$UserProfileModelFromJson(json); +} + +@freezed +abstract class User with _$User { + const factory User({ + required int id, + required String username, + required String password, + required String firstName, + required String lastName, + required bool isActive, + required String mobile, + required String phone, + required String nationalCode, + required DateTime birthdate, + required String nationality, + required String ownership, + required String address, + required String photo, + required int province, + required int city, + required bool otpStatus, + required String cityName, + required String provinceName, + }) = _User; + + + + factory User.fromJson(Map json) => _$UserFromJson(json); +} + +@freezed +abstract class Role with _$Role { + const factory Role({ + required int id, + required String roleName, + required String description, + required RoleType type, + required List permissions, + }) = _Role; + + factory Role.fromJson(Map json) => _$RoleFromJson(json); +} + +@freezed +abstract class RoleType with _$RoleType { + const factory RoleType({String? key, required String name}) = _RoleType; + + factory RoleType.fromJson(Map json) => _$RoleTypeFromJson(json); +} + +@freezed +abstract class Permission with _$Permission { + const factory Permission({required String pageName, required List pageAccess}) = + _Permission; + + factory Permission.fromJson(Map json) => _$PermissionFromJson(json); +} diff --git a/packages/livestock/lib/data/model/response/user_profile/user_profile_model.freezed.dart b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.freezed.dart new file mode 100644 index 0000000..2e3865e --- /dev/null +++ b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.freezed.dart @@ -0,0 +1,1479 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'user_profile_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; + +/// @nodoc +mixin _$UserProfileModel { + + User get user; Role get role; List get permissions; +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$UserProfileModelCopyWith get copyWith => _$UserProfileModelCopyWithImpl(this as UserProfileModel, _$identity); + + /// Serializes this UserProfileModel to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is UserProfileModel&&(identical(other.user, user) || other.user == user)&&(identical(other.role, role) || other.role == role)&&const DeepCollectionEquality().equals(other.permissions, permissions)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,user,role,const DeepCollectionEquality().hash(permissions)); + +@override +String toString() { + return 'UserProfileModel(user: $user, role: $role, permissions: $permissions)'; +} + + +} + +/// @nodoc +abstract mixin class $UserProfileModelCopyWith<$Res> { + factory $UserProfileModelCopyWith(UserProfileModel value, $Res Function(UserProfileModel) _then) = _$UserProfileModelCopyWithImpl; +@useResult +$Res call({ + User user, Role role, List permissions +}); + + +$UserCopyWith<$Res> get user;$RoleCopyWith<$Res> get role; + +} +/// @nodoc +class _$UserProfileModelCopyWithImpl<$Res> + implements $UserProfileModelCopyWith<$Res> { + _$UserProfileModelCopyWithImpl(this._self, this._then); + + final UserProfileModel _self; + final $Res Function(UserProfileModel) _then; + +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? user = null,Object? role = null,Object? permissions = null,}) { + return _then(_self.copyWith( +user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable +as User,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as Role,permissions: null == permissions ? _self.permissions : permissions // ignore: cast_nullable_to_non_nullable +as List, + )); +} +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$UserCopyWith<$Res> get user { + + return $UserCopyWith<$Res>(_self.user, (value) { + return _then(_self.copyWith(user: value)); + }); +}/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RoleCopyWith<$Res> get role { + + return $RoleCopyWith<$Res>(_self.role, (value) { + return _then(_self.copyWith(role: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [UserProfileModel]. +extension UserProfileModelPatterns on UserProfileModel { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _UserProfileModel value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _UserProfileModel() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _UserProfileModel value) $default,){ +final _that = this; +switch (_that) { +case _UserProfileModel(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _UserProfileModel value)? $default,){ +final _that = this; +switch (_that) { +case _UserProfileModel() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( User user, Role role, List permissions)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _UserProfileModel() when $default != null: +return $default(_that.user,_that.role,_that.permissions);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( User user, Role role, List permissions) $default,) {final _that = this; +switch (_that) { +case _UserProfileModel(): +return $default(_that.user,_that.role,_that.permissions);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( User user, Role role, List permissions)? $default,) {final _that = this; +switch (_that) { +case _UserProfileModel() when $default != null: +return $default(_that.user,_that.role,_that.permissions);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _UserProfileModel implements UserProfileModel { + const _UserProfileModel({required this.user, required this.role, required final List permissions}): _permissions = permissions; + factory _UserProfileModel.fromJson(Map json) => _$UserProfileModelFromJson(json); + +@override final User user; +@override final Role role; + final List _permissions; +@override List get permissions { + if (_permissions is EqualUnmodifiableListView) return _permissions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_permissions); +} + + +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$UserProfileModelCopyWith<_UserProfileModel> get copyWith => __$UserProfileModelCopyWithImpl<_UserProfileModel>(this, _$identity); + +@override +Map toJson() { + return _$UserProfileModelToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _UserProfileModel&&(identical(other.user, user) || other.user == user)&&(identical(other.role, role) || other.role == role)&&const DeepCollectionEquality().equals(other._permissions, _permissions)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,user,role,const DeepCollectionEquality().hash(_permissions)); + +@override +String toString() { + return 'UserProfileModel(user: $user, role: $role, permissions: $permissions)'; +} + + +} + +/// @nodoc +abstract mixin class _$UserProfileModelCopyWith<$Res> implements $UserProfileModelCopyWith<$Res> { + factory _$UserProfileModelCopyWith(_UserProfileModel value, $Res Function(_UserProfileModel) _then) = __$UserProfileModelCopyWithImpl; +@override @useResult +$Res call({ + User user, Role role, List permissions +}); + + +@override $UserCopyWith<$Res> get user;@override $RoleCopyWith<$Res> get role; + +} +/// @nodoc +class __$UserProfileModelCopyWithImpl<$Res> + implements _$UserProfileModelCopyWith<$Res> { + __$UserProfileModelCopyWithImpl(this._self, this._then); + + final _UserProfileModel _self; + final $Res Function(_UserProfileModel) _then; + +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? user = null,Object? role = null,Object? permissions = null,}) { + return _then(_UserProfileModel( +user: null == user ? _self.user : user // ignore: cast_nullable_to_non_nullable +as User,role: null == role ? _self.role : role // ignore: cast_nullable_to_non_nullable +as Role,permissions: null == permissions ? _self._permissions : permissions // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$UserCopyWith<$Res> get user { + + return $UserCopyWith<$Res>(_self.user, (value) { + return _then(_self.copyWith(user: value)); + }); +}/// Create a copy of UserProfileModel +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RoleCopyWith<$Res> get role { + + return $RoleCopyWith<$Res>(_self.role, (value) { + return _then(_self.copyWith(role: value)); + }); +} +} + + +/// @nodoc +mixin _$User { + + int get id; String get username; String get password; String get firstName; String get lastName; bool get isActive; String get mobile; String get phone; String get nationalCode; DateTime get birthdate; String get nationality; String get ownership; String get address; String get photo; int get province; int get city; bool get otpStatus; String get cityName; String get provinceName; +/// Create a copy of User +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$UserCopyWith get copyWith => _$UserCopyWithImpl(this as User, _$identity); + + /// Serializes this User to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is User&&(identical(other.id, id) || other.id == id)&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.isActive, isActive) || other.isActive == isActive)&&(identical(other.mobile, mobile) || other.mobile == mobile)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.nationalCode, nationalCode) || other.nationalCode == nationalCode)&&(identical(other.birthdate, birthdate) || other.birthdate == birthdate)&&(identical(other.nationality, nationality) || other.nationality == nationality)&&(identical(other.ownership, ownership) || other.ownership == ownership)&&(identical(other.address, address) || other.address == address)&&(identical(other.photo, photo) || other.photo == photo)&&(identical(other.province, province) || other.province == province)&&(identical(other.city, city) || other.city == city)&&(identical(other.otpStatus, otpStatus) || other.otpStatus == otpStatus)&&(identical(other.cityName, cityName) || other.cityName == cityName)&&(identical(other.provinceName, provinceName) || other.provinceName == provinceName)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hashAll([runtimeType,id,username,password,firstName,lastName,isActive,mobile,phone,nationalCode,birthdate,nationality,ownership,address,photo,province,city,otpStatus,cityName,provinceName]); + +@override +String toString() { + return 'User(id: $id, username: $username, password: $password, firstName: $firstName, lastName: $lastName, isActive: $isActive, mobile: $mobile, phone: $phone, nationalCode: $nationalCode, birthdate: $birthdate, nationality: $nationality, ownership: $ownership, address: $address, photo: $photo, province: $province, city: $city, otpStatus: $otpStatus, cityName: $cityName, provinceName: $provinceName)'; +} + + +} + +/// @nodoc +abstract mixin class $UserCopyWith<$Res> { + factory $UserCopyWith(User value, $Res Function(User) _then) = _$UserCopyWithImpl; +@useResult +$Res call({ + int id, String username, String password, String firstName, String lastName, bool isActive, String mobile, String phone, String nationalCode, DateTime birthdate, String nationality, String ownership, String address, String photo, int province, int city, bool otpStatus, String cityName, String provinceName +}); + + + + +} +/// @nodoc +class _$UserCopyWithImpl<$Res> + implements $UserCopyWith<$Res> { + _$UserCopyWithImpl(this._self, this._then); + + final User _self; + final $Res Function(User) _then; + +/// Create a copy of User +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? username = null,Object? password = null,Object? firstName = null,Object? lastName = null,Object? isActive = null,Object? mobile = null,Object? phone = null,Object? nationalCode = null,Object? birthdate = null,Object? nationality = null,Object? ownership = null,Object? address = null,Object? photo = null,Object? province = null,Object? city = null,Object? otpStatus = null,Object? cityName = null,Object? provinceName = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as int,username: null == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable +as bool,mobile: null == mobile ? _self.mobile : mobile // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String,nationalCode: null == nationalCode ? _self.nationalCode : nationalCode // ignore: cast_nullable_to_non_nullable +as String,birthdate: null == birthdate ? _self.birthdate : birthdate // ignore: cast_nullable_to_non_nullable +as DateTime,nationality: null == nationality ? _self.nationality : nationality // ignore: cast_nullable_to_non_nullable +as String,ownership: null == ownership ? _self.ownership : ownership // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,photo: null == photo ? _self.photo : photo // ignore: cast_nullable_to_non_nullable +as String,province: null == province ? _self.province : province // ignore: cast_nullable_to_non_nullable +as int,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable +as int,otpStatus: null == otpStatus ? _self.otpStatus : otpStatus // ignore: cast_nullable_to_non_nullable +as bool,cityName: null == cityName ? _self.cityName : cityName // ignore: cast_nullable_to_non_nullable +as String,provinceName: null == provinceName ? _self.provinceName : provinceName // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [User]. +extension UserPatterns on User { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _User value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _User() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _User value) $default,){ +final _that = this; +switch (_that) { +case _User(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _User value)? $default,){ +final _that = this; +switch (_that) { +case _User() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( int id, String username, String password, String firstName, String lastName, bool isActive, String mobile, String phone, String nationalCode, DateTime birthdate, String nationality, String ownership, String address, String photo, int province, int city, bool otpStatus, String cityName, String provinceName)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _User() when $default != null: +return $default(_that.id,_that.username,_that.password,_that.firstName,_that.lastName,_that.isActive,_that.mobile,_that.phone,_that.nationalCode,_that.birthdate,_that.nationality,_that.ownership,_that.address,_that.photo,_that.province,_that.city,_that.otpStatus,_that.cityName,_that.provinceName);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( int id, String username, String password, String firstName, String lastName, bool isActive, String mobile, String phone, String nationalCode, DateTime birthdate, String nationality, String ownership, String address, String photo, int province, int city, bool otpStatus, String cityName, String provinceName) $default,) {final _that = this; +switch (_that) { +case _User(): +return $default(_that.id,_that.username,_that.password,_that.firstName,_that.lastName,_that.isActive,_that.mobile,_that.phone,_that.nationalCode,_that.birthdate,_that.nationality,_that.ownership,_that.address,_that.photo,_that.province,_that.city,_that.otpStatus,_that.cityName,_that.provinceName);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( int id, String username, String password, String firstName, String lastName, bool isActive, String mobile, String phone, String nationalCode, DateTime birthdate, String nationality, String ownership, String address, String photo, int province, int city, bool otpStatus, String cityName, String provinceName)? $default,) {final _that = this; +switch (_that) { +case _User() when $default != null: +return $default(_that.id,_that.username,_that.password,_that.firstName,_that.lastName,_that.isActive,_that.mobile,_that.phone,_that.nationalCode,_that.birthdate,_that.nationality,_that.ownership,_that.address,_that.photo,_that.province,_that.city,_that.otpStatus,_that.cityName,_that.provinceName);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _User implements User { + const _User({required this.id, required this.username, required this.password, required this.firstName, required this.lastName, required this.isActive, required this.mobile, required this.phone, required this.nationalCode, required this.birthdate, required this.nationality, required this.ownership, required this.address, required this.photo, required this.province, required this.city, required this.otpStatus, required this.cityName, required this.provinceName}); + factory _User.fromJson(Map json) => _$UserFromJson(json); + +@override final int id; +@override final String username; +@override final String password; +@override final String firstName; +@override final String lastName; +@override final bool isActive; +@override final String mobile; +@override final String phone; +@override final String nationalCode; +@override final DateTime birthdate; +@override final String nationality; +@override final String ownership; +@override final String address; +@override final String photo; +@override final int province; +@override final int city; +@override final bool otpStatus; +@override final String cityName; +@override final String provinceName; + +/// Create a copy of User +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$UserCopyWith<_User> get copyWith => __$UserCopyWithImpl<_User>(this, _$identity); + +@override +Map toJson() { + return _$UserToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _User&&(identical(other.id, id) || other.id == id)&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.firstName, firstName) || other.firstName == firstName)&&(identical(other.lastName, lastName) || other.lastName == lastName)&&(identical(other.isActive, isActive) || other.isActive == isActive)&&(identical(other.mobile, mobile) || other.mobile == mobile)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.nationalCode, nationalCode) || other.nationalCode == nationalCode)&&(identical(other.birthdate, birthdate) || other.birthdate == birthdate)&&(identical(other.nationality, nationality) || other.nationality == nationality)&&(identical(other.ownership, ownership) || other.ownership == ownership)&&(identical(other.address, address) || other.address == address)&&(identical(other.photo, photo) || other.photo == photo)&&(identical(other.province, province) || other.province == province)&&(identical(other.city, city) || other.city == city)&&(identical(other.otpStatus, otpStatus) || other.otpStatus == otpStatus)&&(identical(other.cityName, cityName) || other.cityName == cityName)&&(identical(other.provinceName, provinceName) || other.provinceName == provinceName)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hashAll([runtimeType,id,username,password,firstName,lastName,isActive,mobile,phone,nationalCode,birthdate,nationality,ownership,address,photo,province,city,otpStatus,cityName,provinceName]); + +@override +String toString() { + return 'User(id: $id, username: $username, password: $password, firstName: $firstName, lastName: $lastName, isActive: $isActive, mobile: $mobile, phone: $phone, nationalCode: $nationalCode, birthdate: $birthdate, nationality: $nationality, ownership: $ownership, address: $address, photo: $photo, province: $province, city: $city, otpStatus: $otpStatus, cityName: $cityName, provinceName: $provinceName)'; +} + + +} + +/// @nodoc +abstract mixin class _$UserCopyWith<$Res> implements $UserCopyWith<$Res> { + factory _$UserCopyWith(_User value, $Res Function(_User) _then) = __$UserCopyWithImpl; +@override @useResult +$Res call({ + int id, String username, String password, String firstName, String lastName, bool isActive, String mobile, String phone, String nationalCode, DateTime birthdate, String nationality, String ownership, String address, String photo, int province, int city, bool otpStatus, String cityName, String provinceName +}); + + + + +} +/// @nodoc +class __$UserCopyWithImpl<$Res> + implements _$UserCopyWith<$Res> { + __$UserCopyWithImpl(this._self, this._then); + + final _User _self; + final $Res Function(_User) _then; + +/// Create a copy of User +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? username = null,Object? password = null,Object? firstName = null,Object? lastName = null,Object? isActive = null,Object? mobile = null,Object? phone = null,Object? nationalCode = null,Object? birthdate = null,Object? nationality = null,Object? ownership = null,Object? address = null,Object? photo = null,Object? province = null,Object? city = null,Object? otpStatus = null,Object? cityName = null,Object? provinceName = null,}) { + return _then(_User( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as int,username: null == username ? _self.username : username // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String,firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable +as String,lastName: null == lastName ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable +as String,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable +as bool,mobile: null == mobile ? _self.mobile : mobile // ignore: cast_nullable_to_non_nullable +as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +as String,nationalCode: null == nationalCode ? _self.nationalCode : nationalCode // ignore: cast_nullable_to_non_nullable +as String,birthdate: null == birthdate ? _self.birthdate : birthdate // ignore: cast_nullable_to_non_nullable +as DateTime,nationality: null == nationality ? _self.nationality : nationality // ignore: cast_nullable_to_non_nullable +as String,ownership: null == ownership ? _self.ownership : ownership // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String,photo: null == photo ? _self.photo : photo // ignore: cast_nullable_to_non_nullable +as String,province: null == province ? _self.province : province // ignore: cast_nullable_to_non_nullable +as int,city: null == city ? _self.city : city // ignore: cast_nullable_to_non_nullable +as int,otpStatus: null == otpStatus ? _self.otpStatus : otpStatus // ignore: cast_nullable_to_non_nullable +as bool,cityName: null == cityName ? _self.cityName : cityName // ignore: cast_nullable_to_non_nullable +as String,provinceName: null == provinceName ? _self.provinceName : provinceName // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + + +/// @nodoc +mixin _$Role { + + int get id; String get roleName; String get description; RoleType get type; List get permissions; +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RoleCopyWith get copyWith => _$RoleCopyWithImpl(this as Role, _$identity); + + /// Serializes this Role to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Role&&(identical(other.id, id) || other.id == id)&&(identical(other.roleName, roleName) || other.roleName == roleName)&&(identical(other.description, description) || other.description == description)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other.permissions, permissions)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,roleName,description,type,const DeepCollectionEquality().hash(permissions)); + +@override +String toString() { + return 'Role(id: $id, roleName: $roleName, description: $description, type: $type, permissions: $permissions)'; +} + + +} + +/// @nodoc +abstract mixin class $RoleCopyWith<$Res> { + factory $RoleCopyWith(Role value, $Res Function(Role) _then) = _$RoleCopyWithImpl; +@useResult +$Res call({ + int id, String roleName, String description, RoleType type, List permissions +}); + + +$RoleTypeCopyWith<$Res> get type; + +} +/// @nodoc +class _$RoleCopyWithImpl<$Res> + implements $RoleCopyWith<$Res> { + _$RoleCopyWithImpl(this._self, this._then); + + final Role _self; + final $Res Function(Role) _then; + +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? roleName = null,Object? description = null,Object? type = null,Object? permissions = null,}) { + return _then(_self.copyWith( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as int,roleName: null == roleName ? _self.roleName : roleName // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as RoleType,permissions: null == permissions ? _self.permissions : permissions // ignore: cast_nullable_to_non_nullable +as List, + )); +} +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RoleTypeCopyWith<$Res> get type { + + return $RoleTypeCopyWith<$Res>(_self.type, (value) { + return _then(_self.copyWith(type: value)); + }); +} +} + + +/// Adds pattern-matching-related methods to [Role]. +extension RolePatterns on Role { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Role value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Role() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Role value) $default,){ +final _that = this; +switch (_that) { +case _Role(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Role value)? $default,){ +final _that = this; +switch (_that) { +case _Role() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( int id, String roleName, String description, RoleType type, List permissions)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Role() when $default != null: +return $default(_that.id,_that.roleName,_that.description,_that.type,_that.permissions);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( int id, String roleName, String description, RoleType type, List permissions) $default,) {final _that = this; +switch (_that) { +case _Role(): +return $default(_that.id,_that.roleName,_that.description,_that.type,_that.permissions);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( int id, String roleName, String description, RoleType type, List permissions)? $default,) {final _that = this; +switch (_that) { +case _Role() when $default != null: +return $default(_that.id,_that.roleName,_that.description,_that.type,_that.permissions);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Role implements Role { + const _Role({required this.id, required this.roleName, required this.description, required this.type, required final List permissions}): _permissions = permissions; + factory _Role.fromJson(Map json) => _$RoleFromJson(json); + +@override final int id; +@override final String roleName; +@override final String description; +@override final RoleType type; + final List _permissions; +@override List get permissions { + if (_permissions is EqualUnmodifiableListView) return _permissions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_permissions); +} + + +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RoleCopyWith<_Role> get copyWith => __$RoleCopyWithImpl<_Role>(this, _$identity); + +@override +Map toJson() { + return _$RoleToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Role&&(identical(other.id, id) || other.id == id)&&(identical(other.roleName, roleName) || other.roleName == roleName)&&(identical(other.description, description) || other.description == description)&&(identical(other.type, type) || other.type == type)&&const DeepCollectionEquality().equals(other._permissions, _permissions)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,id,roleName,description,type,const DeepCollectionEquality().hash(_permissions)); + +@override +String toString() { + return 'Role(id: $id, roleName: $roleName, description: $description, type: $type, permissions: $permissions)'; +} + + +} + +/// @nodoc +abstract mixin class _$RoleCopyWith<$Res> implements $RoleCopyWith<$Res> { + factory _$RoleCopyWith(_Role value, $Res Function(_Role) _then) = __$RoleCopyWithImpl; +@override @useResult +$Res call({ + int id, String roleName, String description, RoleType type, List permissions +}); + + +@override $RoleTypeCopyWith<$Res> get type; + +} +/// @nodoc +class __$RoleCopyWithImpl<$Res> + implements _$RoleCopyWith<$Res> { + __$RoleCopyWithImpl(this._self, this._then); + + final _Role _self; + final $Res Function(_Role) _then; + +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? roleName = null,Object? description = null,Object? type = null,Object? permissions = null,}) { + return _then(_Role( +id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable +as int,roleName: null == roleName ? _self.roleName : roleName // ignore: cast_nullable_to_non_nullable +as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable +as String,type: null == type ? _self.type : type // ignore: cast_nullable_to_non_nullable +as RoleType,permissions: null == permissions ? _self._permissions : permissions // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +/// Create a copy of Role +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$RoleTypeCopyWith<$Res> get type { + + return $RoleTypeCopyWith<$Res>(_self.type, (value) { + return _then(_self.copyWith(type: value)); + }); +} +} + + +/// @nodoc +mixin _$RoleType { + + String? get key; String get name; +/// Create a copy of RoleType +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$RoleTypeCopyWith get copyWith => _$RoleTypeCopyWithImpl(this as RoleType, _$identity); + + /// Serializes this RoleType to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is RoleType&&(identical(other.key, key) || other.key == key)&&(identical(other.name, name) || other.name == name)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,key,name); + +@override +String toString() { + return 'RoleType(key: $key, name: $name)'; +} + + +} + +/// @nodoc +abstract mixin class $RoleTypeCopyWith<$Res> { + factory $RoleTypeCopyWith(RoleType value, $Res Function(RoleType) _then) = _$RoleTypeCopyWithImpl; +@useResult +$Res call({ + String? key, String name +}); + + + + +} +/// @nodoc +class _$RoleTypeCopyWithImpl<$Res> + implements $RoleTypeCopyWith<$Res> { + _$RoleTypeCopyWithImpl(this._self, this._then); + + final RoleType _self; + final $Res Function(RoleType) _then; + +/// Create a copy of RoleType +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? name = null,}) { + return _then(_self.copyWith( +key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable +as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [RoleType]. +extension RoleTypePatterns on RoleType { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _RoleType value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _RoleType() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _RoleType value) $default,){ +final _that = this; +switch (_that) { +case _RoleType(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _RoleType value)? $default,){ +final _that = this; +switch (_that) { +case _RoleType() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String? key, String name)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _RoleType() when $default != null: +return $default(_that.key,_that.name);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String? key, String name) $default,) {final _that = this; +switch (_that) { +case _RoleType(): +return $default(_that.key,_that.name);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String? key, String name)? $default,) {final _that = this; +switch (_that) { +case _RoleType() when $default != null: +return $default(_that.key,_that.name);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _RoleType implements RoleType { + const _RoleType({this.key, required this.name}); + factory _RoleType.fromJson(Map json) => _$RoleTypeFromJson(json); + +@override final String? key; +@override final String name; + +/// Create a copy of RoleType +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$RoleTypeCopyWith<_RoleType> get copyWith => __$RoleTypeCopyWithImpl<_RoleType>(this, _$identity); + +@override +Map toJson() { + return _$RoleTypeToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _RoleType&&(identical(other.key, key) || other.key == key)&&(identical(other.name, name) || other.name == name)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,key,name); + +@override +String toString() { + return 'RoleType(key: $key, name: $name)'; +} + + +} + +/// @nodoc +abstract mixin class _$RoleTypeCopyWith<$Res> implements $RoleTypeCopyWith<$Res> { + factory _$RoleTypeCopyWith(_RoleType value, $Res Function(_RoleType) _then) = __$RoleTypeCopyWithImpl; +@override @useResult +$Res call({ + String? key, String name +}); + + + + +} +/// @nodoc +class __$RoleTypeCopyWithImpl<$Res> + implements _$RoleTypeCopyWith<$Res> { + __$RoleTypeCopyWithImpl(this._self, this._then); + + final _RoleType _self; + final $Res Function(_RoleType) _then; + +/// Create a copy of RoleType +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? name = null,}) { + return _then(_RoleType( +key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable +as String?,name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + + +/// @nodoc +mixin _$Permission { + + String get pageName; List get pageAccess; +/// Create a copy of Permission +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$PermissionCopyWith get copyWith => _$PermissionCopyWithImpl(this as Permission, _$identity); + + /// Serializes this Permission to a JSON map. + Map toJson(); + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is Permission&&(identical(other.pageName, pageName) || other.pageName == pageName)&&const DeepCollectionEquality().equals(other.pageAccess, pageAccess)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,pageName,const DeepCollectionEquality().hash(pageAccess)); + +@override +String toString() { + return 'Permission(pageName: $pageName, pageAccess: $pageAccess)'; +} + + +} + +/// @nodoc +abstract mixin class $PermissionCopyWith<$Res> { + factory $PermissionCopyWith(Permission value, $Res Function(Permission) _then) = _$PermissionCopyWithImpl; +@useResult +$Res call({ + String pageName, List pageAccess +}); + + + + +} +/// @nodoc +class _$PermissionCopyWithImpl<$Res> + implements $PermissionCopyWith<$Res> { + _$PermissionCopyWithImpl(this._self, this._then); + + final Permission _self; + final $Res Function(Permission) _then; + +/// Create a copy of Permission +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? pageName = null,Object? pageAccess = null,}) { + return _then(_self.copyWith( +pageName: null == pageName ? _self.pageName : pageName // ignore: cast_nullable_to_non_nullable +as String,pageAccess: null == pageAccess ? _self.pageAccess : pageAccess // ignore: cast_nullable_to_non_nullable +as List, + )); +} + +} + + +/// Adds pattern-matching-related methods to [Permission]. +extension PermissionPatterns on Permission { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _Permission value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _Permission() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _Permission value) $default,){ +final _that = this; +switch (_that) { +case _Permission(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _Permission value)? $default,){ +final _that = this; +switch (_that) { +case _Permission() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String pageName, List pageAccess)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _Permission() when $default != null: +return $default(_that.pageName,_that.pageAccess);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String pageName, List pageAccess) $default,) {final _that = this; +switch (_that) { +case _Permission(): +return $default(_that.pageName,_that.pageAccess);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String pageName, List pageAccess)? $default,) {final _that = this; +switch (_that) { +case _Permission() when $default != null: +return $default(_that.pageName,_that.pageAccess);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _Permission implements Permission { + const _Permission({required this.pageName, required final List pageAccess}): _pageAccess = pageAccess; + factory _Permission.fromJson(Map json) => _$PermissionFromJson(json); + +@override final String pageName; + final List _pageAccess; +@override List get pageAccess { + if (_pageAccess is EqualUnmodifiableListView) return _pageAccess; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_pageAccess); +} + + +/// Create a copy of Permission +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$PermissionCopyWith<_Permission> get copyWith => __$PermissionCopyWithImpl<_Permission>(this, _$identity); + +@override +Map toJson() { + return _$PermissionToJson(this, ); +} + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Permission&&(identical(other.pageName, pageName) || other.pageName == pageName)&&const DeepCollectionEquality().equals(other._pageAccess, _pageAccess)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,pageName,const DeepCollectionEquality().hash(_pageAccess)); + +@override +String toString() { + return 'Permission(pageName: $pageName, pageAccess: $pageAccess)'; +} + + +} + +/// @nodoc +abstract mixin class _$PermissionCopyWith<$Res> implements $PermissionCopyWith<$Res> { + factory _$PermissionCopyWith(_Permission value, $Res Function(_Permission) _then) = __$PermissionCopyWithImpl; +@override @useResult +$Res call({ + String pageName, List pageAccess +}); + + + + +} +/// @nodoc +class __$PermissionCopyWithImpl<$Res> + implements _$PermissionCopyWith<$Res> { + __$PermissionCopyWithImpl(this._self, this._then); + + final _Permission _self; + final $Res Function(_Permission) _then; + +/// Create a copy of Permission +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? pageName = null,Object? pageAccess = null,}) { + return _then(_Permission( +pageName: null == pageName ? _self.pageName : pageName // ignore: cast_nullable_to_non_nullable +as String,pageAccess: null == pageAccess ? _self._pageAccess : pageAccess // ignore: cast_nullable_to_non_nullable +as List, + )); +} + + +} + +// dart format on diff --git a/packages/livestock/lib/data/model/response/user_profile/user_profile_model.g.dart b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.g.dart new file mode 100644 index 0000000..7bf5323 --- /dev/null +++ b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.g.dart @@ -0,0 +1,104 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_profile_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_UserProfileModel _$UserProfileModelFromJson(Map json) => + _UserProfileModel( + user: User.fromJson(json['user'] as Map), + role: Role.fromJson(json['role'] as Map), + permissions: (json['permissions'] as List) + .map((e) => Permission.fromJson(e as Map)) + .toList(), + ); + +Map _$UserProfileModelToJson(_UserProfileModel instance) => + { + 'user': instance.user, + 'role': instance.role, + 'permissions': instance.permissions, + }; + +_User _$UserFromJson(Map json) => _User( + id: (json['id'] as num).toInt(), + username: json['username'] as String, + password: json['password'] as String, + firstName: json['first_name'] as String, + lastName: json['last_name'] as String, + isActive: json['is_active'] as bool, + mobile: json['mobile'] as String, + phone: json['phone'] as String, + nationalCode: json['national_code'] as String, + birthdate: DateTime.parse(json['birthdate'] as String), + nationality: json['nationality'] as String, + ownership: json['ownership'] as String, + address: json['address'] as String, + photo: json['photo'] as String, + province: (json['province'] as num).toInt(), + city: (json['city'] as num).toInt(), + otpStatus: json['otp_status'] as bool, + cityName: json['city_name'] as String, + provinceName: json['province_name'] as String, +); + +Map _$UserToJson(_User instance) => { + 'id': instance.id, + 'username': instance.username, + 'password': instance.password, + 'first_name': instance.firstName, + 'last_name': instance.lastName, + 'is_active': instance.isActive, + 'mobile': instance.mobile, + 'phone': instance.phone, + 'national_code': instance.nationalCode, + 'birthdate': instance.birthdate.toIso8601String(), + 'nationality': instance.nationality, + 'ownership': instance.ownership, + 'address': instance.address, + 'photo': instance.photo, + 'province': instance.province, + 'city': instance.city, + 'otp_status': instance.otpStatus, + 'city_name': instance.cityName, + 'province_name': instance.provinceName, +}; + +_Role _$RoleFromJson(Map json) => _Role( + id: (json['id'] as num).toInt(), + roleName: json['role_name'] as String, + description: json['description'] as String, + type: RoleType.fromJson(json['type'] as Map), + permissions: json['permissions'] as List, +); + +Map _$RoleToJson(_Role instance) => { + 'id': instance.id, + 'role_name': instance.roleName, + 'description': instance.description, + 'type': instance.type, + 'permissions': instance.permissions, +}; + +_RoleType _$RoleTypeFromJson(Map json) => + _RoleType(key: json['key'] as String?, name: json['name'] as String); + +Map _$RoleTypeToJson(_RoleType instance) => { + 'key': instance.key, + 'name': instance.name, +}; + +_Permission _$PermissionFromJson(Map json) => _Permission( + pageName: json['page_name'] as String, + pageAccess: (json['page_access'] as List) + .map((e) => e as String) + .toList(), +); + +Map _$PermissionToJson(_Permission instance) => + { + 'page_name': instance.pageName, + 'page_access': instance.pageAccess, + }; diff --git a/packages/livestock/lib/data/repository/auth/auth_repository.dart b/packages/livestock/lib/data/repository/auth/auth_repository.dart new file mode 100644 index 0000000..52fa9d5 --- /dev/null +++ b/packages/livestock/lib/data/repository/auth/auth_repository.dart @@ -0,0 +1,17 @@ +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; +import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; + +abstract class AuthRepository { + Future login({required Map authRequest}); + + Future captcha(); + + Future logout(); + + Future hasAuthenticated(); + + Future loginWithRefreshToken({required Map authRequest}); + + +} diff --git a/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart b/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart new file mode 100644 index 0000000..11a7c60 --- /dev/null +++ b/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart @@ -0,0 +1,42 @@ +import 'package:rasadyar_livestock/data/data_source/remote/auth/auth_remote.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; +import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; + +import 'auth_repository.dart'; + +class AuthRepositoryImp implements AuthRepository { + final AuthRemoteDataSource authRemote; + + + AuthRepositoryImp({required this.authRemote}); + + @override + Future login({required Map authRequest}) async => + await authRemote.login(authRequest: authRequest); + + @override + Future captcha() async { + return await authRemote.captcha(); + } + + @override + Future loginWithRefreshToken({ + required Map authRequest, + }) async { + return await authRemote.loginWithRefreshToken(authRequest: authRequest); + } + + @override + Future logout() async { + await authRemote.logout(); + } + + @override + Future hasAuthenticated() async { + return await authRemote.hasAuthenticated(); + } + + +} diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart new file mode 100644 index 0000000..2bd095b --- /dev/null +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -0,0 +1,15 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; + +abstract class LivestockRepository { + Future getLocationDetails({ + required double latitude, + required double longitude, + }); + + Future createTaggingLiveStock({required LivestockData data}); + + Future> getLocations(); + Future addLocations(List latList); +} diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart new file mode 100644 index 0000000..80fb768 --- /dev/null +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -0,0 +1,63 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; +import 'package:rasadyar_livestock/data/data_source/local/tmp/tmp_local_data-source.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; + +import 'livestock_repository.dart'; + +class LivestockRepositoryImp implements LivestockRepository { + final LivestockRemoteDataSource livestockRemote; + final TmpLocalDataSource tmpLocalDataSource; + + LivestockRepositoryImp({required this.livestockRemote,required this.tmpLocalDataSource}); + + @override + Future getLocationDetails({ + required double latitude, + required double longitude, + }) async { + return await livestockRemote.getLocationDetailsByLatLng( + latitude: latitude, + longitude: longitude, + ); + } + + @override + Future createTaggingLiveStock({required LivestockData data}) async { + return await livestockRemote.createTaggingLiveStock(data: data); + } + + @override + Future> getLocations() async { + if (NetworkStatus().isConnected.value) { + return [ + LatLng(35.824891, 50.948025), + LatLng(35.825000, 50.949000), + LatLng(35.823000, 50.947000), + LatLng(35.826000, 50.950000), + LatLng(35.827000, 50.951000), + LatLng(35.828000, 50.952000), + LatLng(35.829000, 50.953000), + LatLng(35.830000, 50.954000), + LatLng(35.831000, 50.955000), + LatLng(35.832000, 50.956000), + LatLng(35.832000, 50.956055), + ]; + } else { + var res = await tmpLocalDataSource.getLocations(); + + return res.map((e) => LatLng(e.lat ?? 0.0, e.long ?? 0.0)).toList(); + } + } + + @override + Future addLocations(List latList) async { + await tmpLocalDataSource.addLocations( + latList.map((e) => TmpLocations(lat: e.latitude, long: e.longitude)).toList(), + ); + iLog("it is done"); + } +} diff --git a/packages/livestock/lib/data/service/live_stock_storage_service.dart b/packages/livestock/lib/data/service/live_stock_storage_service.dart new file mode 100644 index 0000000..35b5a3e --- /dev/null +++ b/packages/livestock/lib/data/service/live_stock_storage_service.dart @@ -0,0 +1,39 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/local/live_tmp/livestock_local_model.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; +import 'package:rasadyar_livestock/data/utils/mapper.dart'; + +class LiveStockStorageService extends GetxService { + final String _liveStockBoxName = 'LiveStockBox'; + late IsolatedBox _LiveStockbox; + + + @override + void onInit() { + super.onInit(); + wLog('LiveStockStorageService onInit'); + IsolatedHive.openBox(_liveStockBoxName).then((value) { + _LiveStockbox = value; + }); + } + + Future saveLiveStockData(LivestockData livestockData) async { + LivestockLocalModel tmp = livestockData.toLocal(); + await _LiveStockbox.add(tmp); + } + + Future saveBulkLiveStockData(Iterable livesList) async { + var tmp = livesList.map((e) => e.toLocal()).toList(); + await _LiveStockbox.addAll(tmp); + } + + Future> getLiveStockData() async { + var liveLocationList = await _LiveStockbox.values; + var res = liveLocationList.map((e) => e.toData()).toList(); + return res; + } + + Future deleteLiveBox() async { + return await _LiveStockbox.clear(); + } +} diff --git a/packages/livestock/lib/data/utils/mapper.dart b/packages/livestock/lib/data/utils/mapper.dart new file mode 100644 index 0000000..6a6a34a --- /dev/null +++ b/packages/livestock/lib/data/utils/mapper.dart @@ -0,0 +1,106 @@ +import '../model/local/live_tmp/livestock_local_model.dart'; +import '../model/response/live_tmp/livestock_model.dart'; + +// Extension for LivestockData to convert to LivestockLocalModel +extension LivestockDataX on LivestockData { + LivestockLocalModel toLocal() { + return LivestockLocalModel() + ..rancher = rancher?.toLocal() + ..herd = herd?.toLocal() + ..livestock = livestock?.map((e) => e.toLocal()).toList(); + } +} + +// Extension for LivestockLocalModel to convert to LivestockData +extension LivestockLocalModelX on LivestockLocalModel { + LivestockData toData() { + return LivestockData( + rancher: rancher?.toData(), + herd: herd?.toData(), + livestock: livestock?.map((e) => e.toData()).toList(), + ); + } +} + +// Extension for Rancher to convert to RancherLocal +extension RancherX on Rancher { + RancherLocal toLocal() { + return RancherLocal() + ..name = name + ..phone = phone + ..image = image; + } +} + +// Extension for RancherLocal to convert to Rancher +extension RancherLocalX on RancherLocal { + Rancher toData() { + return Rancher(name: name, phone: phone, image: image); + } +} + +// Extension for Herd to convert to HerdLocal +extension HerdX on Herd { + HerdLocal toLocal() { + return HerdLocal() + ..location = location?.toLocal() + ..address = address + ..image = image; + } +} + +// Extension for HerdLocal to convert to Herd +extension HerdLocalX on HerdLocal { + Herd toData() { + return Herd(location: location?.toData(), address: address, image: image); + } +} + +// Extension for Location to convert to LocationLocal +extension LocationX on Location { + LocationLocal toLocal() { + return LocationLocal() + ..lat = lat + ..lng = lng; + } +} + +// Extension for LocationLocal to convert to Location +extension LocationLocalX on LocationLocal { + Location toData() { + return Location(lat: lat, lng: lng); + } +} + +// Extension for Livestock to convert to LivestockLocal +extension LivestockX on Livestock { + LivestockLocal toLocal() { + return LivestockLocal() + ..species = species + ..breed = breed + ..dateOfBirth = dateOfBirth + ..sex = sex + ..motherTag = motherTag + ..fatherTag = fatherTag + ..tagNumber = tagNumber + ..tagType = tagType + ..image = image; + } +} + +// Extension for LivestockLocal to convert to Livestock +extension LivestockLocalX on LivestockLocal { + Livestock toData() { + return Livestock( + species: species, + breed: breed, + dateOfBirth: dateOfBirth, + sex: sex, + motherTag: motherTag, + fatherTag: fatherTag, + tagNumber: tagNumber, + tagType: tagType, + image: image, + ); + } +} diff --git a/packages/livestock/lib/hive_registrar.g.dart b/packages/livestock/lib/hive_registrar.g.dart new file mode 100644 index 0000000..a9f8f96 --- /dev/null +++ b/packages/livestock/lib/hive_registrar.g.dart @@ -0,0 +1,29 @@ +// Generated by Hive CE +// Do not modify +// Check in to version control + +import 'package:hive_ce/hive.dart'; +import 'package:rasadyar_livestock/data/model/local/live_tmp/livestock_local_model.dart'; +import 'package:rasadyar_livestock/data/model/local/location/tmp_locations.dart'; + +extension HiveRegistrar on HiveInterface { + void registerAdapters() { + registerAdapter(HerdLocalAdapter()); + registerAdapter(LivestockLocalAdapter()); + registerAdapter(LivestockLocalModelAdapter()); + registerAdapter(LocationLocalAdapter()); + registerAdapter(RancherLocalAdapter()); + registerAdapter(TmpLocationsAdapter()); + } +} + +extension IsolatedHiveRegistrar on IsolatedHiveInterface { + void registerAdapters() { + registerAdapter(HerdLocalAdapter()); + registerAdapter(LivestockLocalAdapter()); + registerAdapter(LivestockLocalModelAdapter()); + registerAdapter(LocationLocalAdapter()); + registerAdapter(RancherLocalAdapter()); + registerAdapter(TmpLocationsAdapter()); + } +} diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart new file mode 100644 index 0000000..8530104 --- /dev/null +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -0,0 +1,125 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/common/constant.dart'; +import 'package:rasadyar_livestock/data/common/dio_exception_handeler.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/auth/auth_remote.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/auth/auth_remote_imp.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote_imp.dart'; +import 'package:rasadyar_livestock/data/repository/auth/auth_repository.dart'; +import 'package:rasadyar_livestock/data/repository/auth/auth_repository_imp.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository_imp.dart'; +import 'package:rasadyar_livestock/hive_registrar.g.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; + +import '../data/data_source/local/tmp/tmp_local_data-source.dart'; + +GetIt get diLiveStock => GetIt.instance; + +Future setupLiveStockDI() async { + diLiveStock.registerSingleton(DioErrorHandler()); + await IsolatedHive.initFlutter(); + IsolatedHive.registerAdapters(); + final tokenService = Get.find(); + + if (tokenService.baseurl.value == null) { + await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); + } + + // First register AppInterceptor with lazy callbacks + diLiveStock.registerLazySingleton( + () => AppInterceptor( + refreshTokenCallback: () async { + // Use lazy access to avoid circular dependency + final authRepository = diLiveStock.get(); + final hasAuthenticated = await authRepository.hasAuthenticated(); + if (hasAuthenticated) { + final newToken = await authRepository.loginWithRefreshToken( + authRequest: {'refresh': tokenService.refreshToken.value}, + ); + return newToken?.access; + } + return null; + }, + saveTokenCallback: (String newToken) async { + await tokenService.saveAccessToken(newToken); + }, + clearTokenCallback: () async { + await tokenService.deleteTokens(); + Get.offAllNamed(LiveStockRoutes.auth, arguments: Module.liveStocks); + }, + authArguments: Module.liveStocks, + ), + ); + + // Register DioRemote with the interceptor + diLiveStock.registerLazySingleton( + () => DioRemote( + baseUrl: tokenService.baseurl.value, + // interceptors: diLiveStock.get(), + ), + ); + + // Initialize DioRemote + await diLiveStock.get().init(); + + // Now register the data source and repository + + //region Auth + diLiveStock.registerLazySingleton( + () => AuthRemoteDataSourceImp(diLiveStock.get()), + ); + + diLiveStock.registerLazySingleton( + () => AuthRepositoryImp(authRemote: diLiveStock.get()), + ); + //endregion + + //region Livestock + diLiveStock.registerLazySingleton( + () => LivestockRemoteDataSourceImp(), + ); + + diLiveStock.registerLazySingleton(() => TmpLocalDataSource()); + + diLiveStock.registerLazySingleton( + () => LivestockRepositoryImp( + livestockRemote: diLiveStock.get(), + tmpLocalDataSource: diLiveStock.get(), + ), + ); + //endregion + + diLiveStock.registerLazySingleton(() => ImagePicker()); + await diLiveStock.allReady(); +} + +Future removeLiveStockDI() async { + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } + if (diLiveStock.isRegistered()) { + diLiveStock.unregister(); + } +} diff --git a/packages/livestock/lib/presentation/page/auth/logic.dart b/packages/livestock/lib/presentation/page/auth/logic.dart new file mode 100644 index 0000000..a7a1eff --- /dev/null +++ b/packages/livestock/lib/presentation/page/auth/logic.dart @@ -0,0 +1,199 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/common/dio_exception_handeler.dart'; +import 'package:rasadyar_livestock/data/model/request/login_request/login_request_model.dart'; +import 'package:rasadyar_livestock/data/model/response/auth/auth_response_model.dart'; +import 'package:rasadyar_livestock/data/repository/auth/auth_repository.dart' show AuthRepository; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; +import 'package:rasadyar_livestock/presentation/widgets/captcha/logic.dart'; + +enum AuthType { useAndPass, otp } + +enum AuthStatus { init } + +enum OtpStatus { init, sent, verified, reSend } + +class AuthLogic extends GetxController with GetTickerProviderStateMixin { + GlobalKey formKey = GlobalKey(); + + late AnimationController _textAnimationController; + late Animation textAnimation; + RxBool showCard = false.obs; + RxBool rememberMe = false.obs; + + Rx> formKeyOtp = GlobalKey().obs; + Rx> formKeySentOtp = GlobalKey().obs; + Rx usernameController = TextEditingController().obs; + Rx passwordController = TextEditingController().obs; + Rx phoneOtpNumberController = TextEditingController().obs; + Rx otpCodeController = TextEditingController().obs; + + var captchaController = Get.find(); + + RxnString phoneNumber = RxnString(null); + RxBool isLoading = false.obs; + RxBool isDisabled = true.obs; + TokenStorageService tokenStorageService = Get.find(); + + Rx authType = AuthType.useAndPass.obs; + Rx authStatus = AuthStatus.init.obs; + Rx otpStatus = OtpStatus.init.obs; + + RxInt secondsRemaining = 120.obs; + Timer? _timer; + + AuthRepository authRepository = diLiveStock.get(); + + final Module _module = Get.arguments; + + @override + void onInit() { + super.onInit(); + + _textAnimationController = + AnimationController(vsync: this, duration: const Duration(milliseconds: 1200)) + ..repeat(reverse: true, count: 2).whenComplete(() { + showCard.value = true; + }); + + textAnimation = CurvedAnimation(parent: _textAnimationController, curve: Curves.easeInOut); + } + + @override + void onReady() { + super.onReady(); + //_textAnimationController.forward(); + } + + @override + void onClose() { + _timer?.cancel(); + super.onClose(); + } + + void startTimer() { + _timer?.cancel(); + secondsRemaining.value = 120; + + _timer = Timer.periodic(const Duration(seconds: 1), (timer) { + if (secondsRemaining.value > 0) { + secondsRemaining.value--; + } else { + timer.cancel(); + } + }); + } + + void stopTimer() { + _timer?.cancel(); + } + + String get timeFormatted { + final minutes = secondsRemaining.value ~/ 60; + final seconds = secondsRemaining.value % 60; + return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; + } + + bool _isFormValid() { + final isCaptchaValid = captchaController.formKey.currentState?.validate() ?? false; + final isFormValid = formKey.currentState?.validate() ?? false; + return isCaptchaValid && isFormValid; + } + + LoginRequestModel _buildLoginRequest() { + final phone = usernameController.value.text; + final pass = passwordController.value.text; + final code = captchaController.textController.value.text; + final key = captchaController.captchaKey.value; + + return LoginRequestModel.createWithCaptcha( + username: phone, + password: pass, + captchaCode: code, + captchaKey: key!, + ); + } + + Future submitLoginForm() async { + if (!_isFormValid()) return; + + final loginRequestModel = _buildLoginRequest(); + isLoading.value = true; + await safeCall( + call: () async => await authRepository.login(authRequest: loginRequestModel.toJson()), + onSuccess: (result) async { + await tokenStorageService.saveModule(_module); + await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); + await tokenStorageService.saveAccessToken(result?.access ?? ''); + if (rememberMe.value) { + await tokenStorageService.saveUserPass( + UserLocalModel( + username: usernameController.value.text, + password: passwordController.value.text, + module: _module, + ), + ); + } + + Get.offAllNamed(LiveStockRoutes.init); + }, + onError: (error, stackTrace) { + if (error is DioException) { + diLiveStock.get().handle(error); + } + captchaController.getCaptcha(); + }, + ); + isLoading.value = false; + } + + Future submitLoginForm2() async { + if (!_isFormValid()) return; + //AuthRepositoryImpl authTmp = diAuth.get(instanceName: 'newUrl'); + isLoading.value = true; + /* await safeCall( + call: () => authTmp.login( + authRequest: { + "username": usernameController.value.text, + "password": passwordController.value.text, + }, + ), + onSuccess: (result) async { + await tokenStorageService.saveModule(_module); + await tokenStorageService.saveAccessToken(result?.accessToken ?? ''); + await tokenStorageService.saveRefreshToken(result?.accessToken ?? ''); + }, + onError: (error, stackTrace) { + if (error is DioException) { + // diAuth.get().handle(error); + } + captchaController.getCaptcha(); + }, + );*/ + isLoading.value = false; + } + + Future getUserInfo(String value) async { + isLoading.value = true; + /*await safeCall( + call: () async => await authRepository.getUserInfo(value), + onSuccess: (result) async { + if (result != null) { + //await newSetupAuthDI(result.backend ?? ''); + await tokenStorageService.saveApiKey(result.apiKey ?? ''); + await tokenStorageService.saveBaseUrl(result.backend ?? ''); + } + }, + onError: (error, stackTrace) { + if (error is DioException) { + // diAuth.get().handle(error); + } + captchaController.getCaptcha(); + }, + );*/ + isLoading.value = false; + } +} diff --git a/packages/livestock/lib/presentation/page/auth/view.dart b/packages/livestock/lib/presentation/page/auth/view.dart new file mode 100644 index 0000000..ea6f953 --- /dev/null +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -0,0 +1,569 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/widgets/captcha/view.dart'; + +import 'logic.dart'; + +class AuthPage extends GetView { + const AuthPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + alignment: Alignment.center, + fit: StackFit.expand, + children: [ + Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill), + + Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: FadeTransition( + opacity: controller.textAnimation, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 12, + children: [ + Text( + 'به سامانه رصدیار خوش آمدید!', + textAlign: TextAlign.right, + style: AppFonts.yekan25Bold.copyWith(color: Colors.white), + ), + Text( + 'سامانه رصد و پایش زنجیره تامین، تولید و توزیع کالا های اساسی', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith(color: Colors.white), + ), + ], + ), + ), + ), + ), + + Obx(() { + final screenHeight = MediaQuery.of(context).size.height; + final targetTop = (screenHeight - 676) / 2; + + return AnimatedPositioned( + duration: const Duration(milliseconds: 1200), + curve: Curves.linear, + top: controller.showCard.value ? targetTop : screenHeight, + left: 10.r, + right: 10.r, + child: Container( + width: 381.w, + height: 676.h, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(40), + ), + child: Column( + children: [ + SizedBox(height: 50.h), + LogoWidget(), + SizedBox(height: 20.h), + useAndPassFrom(), + SizedBox(height: 24.h), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'مطالعه بیانیه ', + style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyDark), + ), + TextSpan( + recognizer: TapGestureRecognizer() + ..onTap = () { + Get.bottomSheet( + privacyPolicyWidget(), + isScrollControlled: true, + enableDrag: true, + ignoreSafeArea: false, + ); + }, + text: 'حریم خصوصی', + style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal), + ), + ], + ), + ), + ], + ), + ), + ); + }), + ], + ), + ); + } + + Widget useAndPassFrom() { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 30.r), + child: Form( + key: controller.formKey, + child: AutofillGroup( + child: Column( + children: [ + RTextField( + label: 'نام کاربری', + maxLength: 11, + maxLines: 1, + controller: controller.usernameController.value, + keyboardType: TextInputType.number, + initText: controller.usernameController.value.text, + autofillHints: [AutofillHints.username], + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: AppColor.textColor, width: 1), + ), + onChanged: (value) async { + controller.usernameController.value.text = value; + controller.usernameController.refresh(); + }, + prefixIcon: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 6, 8), + child: Assets.vec.callSvg.svg(width: 12, height: 12), + ), + suffixIcon: controller.usernameController.value.text.trim().isNotEmpty + ? clearButton(() { + controller.usernameController.value.clear(); + controller.usernameController.refresh(); + }) + : null, + validator: (value) { + /* if (value == null || value.isEmpty) { + return '⚠️ شماره موبایل را وارد کنید'; + } else if (value.length < 10) { + return '⚠️ شماره موبایل باید 11 رقم باشد'; + }*/ + return null; + }, + style: AppFonts.yekan13, + errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal), + labelStyle: AppFonts.yekan13, + boxConstraints: const BoxConstraints( + maxHeight: 40, + minHeight: 40, + maxWidth: 40, + minWidth: 40, + ), + ), + const SizedBox(height: 26), + ObxValue( + (passwordController) => RTextField( + label: 'رمز عبور', + filled: false, + obscure: true, + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: AppColor.textColor, width: 1), + ), + controller: passwordController.value, + autofillHints: [AutofillHints.password], + variant: RTextFieldVariant.password, + initText: passwordController.value.text, + onChanged: (value) { + passwordController.refresh(); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return '⚠️ رمز عبور را وارد کنید'; + } + return null; + }, + style: AppFonts.yekan13, + errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal), + labelStyle: AppFonts.yekan13, + prefixIcon: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), + child: Assets.vec.keySvg.svg(width: 12, height: 12), + ), + boxConstraints: const BoxConstraints( + maxHeight: 34, + minHeight: 34, + maxWidth: 34, + minWidth: 34, + ), + ), + controller.passwordController, + ), + SizedBox(height: 26), + CaptchaWidget(), + GestureDetector( + onTap: () { + controller.rememberMe.value = !controller.rememberMe.value; + }, + child: Row( + children: [ + ObxValue((data) { + return Checkbox( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + visualDensity: VisualDensity(horizontal: -4, vertical: 4), + tristate: true, + value: data.value, + onChanged: (value) { + data.value = value ?? false; + }, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + activeColor: AppColor.blueNormal, + ); + }, controller.rememberMe), + Text( + 'مرا به خاطر بسپار', + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), + + + Obx(() { + return RElevated( + text: 'ورود', + isLoading: controller.isLoading.value, + onPressed: controller.isDisabled.value + ? null + : () async { + await controller.submitLoginForm(); + }, + width: Get.width, + height: 48, + ); + }), + ], + ), + ), + ), + ); + } + + Widget privacyPolicyWidget() { + return BaseBottomSheet( + child: Column( + spacing: 5, + children: [ + Container( + padding: EdgeInsets.all(8.w), + + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight, width: 1), + ), + child: Column( + spacing: 3, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'بيانيه حريم خصوصی', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + Text( + 'اطلاعات مربوط به هر شخص، حریم خصوصی وی محسوب می‌شود. حفاظت و حراست از اطلاعات شخصی در سامانه رصد یار، نه تنها موجب حفظ امنیت کاربران می‌شود، بلکه باعث اعتماد بیشتر و مشارکت آنها در فعالیت‌های جاری می‌گردد. هدف از این بیانیه، آگاه ساختن شما درباره ی نوع و نحوه ی استفاده از اطلاعاتی است که در هنگام استفاده از سامانه رصد یار ، از جانب شما دریافت می‌گردد. شرکت هوشمند سازان خود را ملزم به رعایت حریم خصوصی همه شهروندان و کاربران سامانه دانسته و آن دسته از اطلاعات کاربران را که فقط به منظور ارائه خدمات کفایت می‌کند، دریافت کرده و از انتشار آن یا در اختیار قرار دادن آن به دیگران خودداری مینماید.', + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8), + ), + ], + ), + ), + Container( + padding: EdgeInsets.all(8.w), + + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight, width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + 'چگونگی جمع آوری و استفاده از اطلاعات کاربران', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + Text( + '''الف: اطلاعاتی که شما خود در اختيار این سامانه قرار می‌دهيد، شامل موارد زيرهستند: +اقلام اطلاعاتی شامل شماره تلفن همراه، تاریخ تولد، کد پستی و کد ملی کاربران را دریافت مینماییم که از این اقلام، صرفا جهت احراز هویت کاربران استفاده خواهد شد. +ب: برخی اطلاعات ديگر که به صورت خودکار از شما دريافت میشود شامل موارد زير می‌باشد: +⦁ دستگاهی که از طریق آن سامانه رصد یار را مشاهده می‌نمایید( تلفن همراه، تبلت، رایانه). +⦁ نام و نسخه سیستم عامل و browser کامپیوتر شما. +⦁ اطلاعات صفحات بازدید شده. +⦁ تعداد بازدیدهای روزانه در درگاه. +⦁ هدف ما از دریافت این اطلاعات استفاده از آنها در تحلیل عملکرد کاربران درگاه می باشد تا بتوانیم در خدمت رسانی بهتر عمل کنیم. +''', + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8), + ), + ], + ), + ), + Container( + padding: EdgeInsets.all(8.w), + + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight, width: 1), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 4, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + 'امنیت اطلاعات', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + Text( + 'متعهدیم که امنیت اطلاعات شما را تضمین نماییم و برای جلوگیری از هر نوع دسترسی غیرمجاز و افشای اطلاعات شما از همه شیوه‌‌های لازم استفاده می‌کنیم تا امنیت اطلاعاتی را که به صورت آنلاین گردآوری می‌کنیم، حفظ شود. لازم به ذکر است در سامانه ما، ممکن است به سایت های دیگری لینک شوید، وقتی که شما از طریق این لینک‌ها از سامانه ما خارج می‌شوید، توجه داشته باشید که ما بر دیگر سایت ها کنترل نداریم و سازمان تعهدی بر حفظ حریم شخصی آنان در سایت مقصد نخواهد داشت و مراجعه کنندگان میبایست به بیانیه حریم شخصی آن سایت ها مراجعه نمایند.', + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark, height: 1.8), + ), + ], + ), + ), + ], + ), + ); + } + + /* + Widget sendCodeForm() { + return ObxValue((data) { + return Form( + key: data.value, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50), + child: Column( + children: [ + SizedBox(height: 26), + ObxValue((phoneController) { + return TextFormField( + controller: phoneController.value, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + gapPadding: 11, + ), + labelText: 'شماره موبایل', + labelStyle: AppFonts.yekan13, + errorStyle: AppFonts.yekan13.copyWith( + color: AppColor.redNormal, + ), + prefixIconConstraints: BoxConstraints( + maxHeight: 40, + minHeight: 40, + maxWidth: 40, + minWidth: 40, + ), + prefixIcon: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 6, 8), + child: vecWidget(Assets.vecCallSvg), + ), + suffix: + phoneController.value.text.trim().isNotEmpty + ? clearButton(() { + phoneController.value.clear(); + phoneController.refresh(); + }) + : null, + counterText: '', + ), + keyboardType: TextInputType.numberWithOptions( + decimal: false, + signed: false, + ), + maxLines: 1, + maxLength: 11, + onChanged: (value) { + if (controller.isOnError.value) { + controller.isOnError.value = !controller.isOnError.value; + data.value.currentState?.reset(); + data.refresh(); + phoneController.value.text = value; + } + phoneController.refresh(); + }, + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null) { + return '⚠️ شماره موبایل را وارد کنید'; + } else if (value.length < 11) { + return '⚠️ شماره موبایل باید 11 رقم باشد'; + } + return null; + }, + style: AppFonts.yekan13, + ); + }, controller.phoneOtpNumberController), + + SizedBox(height: 26), + + CaptchaWidget(), + + SizedBox(height: 23), + RElevated( + text: 'ارسال رمز یکبار مصرف', + onPressed: () { + if (data.value.currentState?.validate() == true) { + controller.otpStatus.value = OtpStatus.sent; + controller.startTimer(); + } + }, + width: Get.width, + height: 48, + ), + ], + ), + ), + ); + }, controller.formKeyOtp); + } + + Widget confirmCodeForm() { + return ObxValue((data) { + return Form( + key: data.value, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50), + child: Column( + children: [ + SizedBox(height: 26), + + ObxValue((passwordController) { + return TextFormField( + controller: passwordController.value, + obscureText: controller.hidePassword.value, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + gapPadding: 11, + ), + labelText: 'رمز عبور', + labelStyle: AppFonts.yekan13, + errorStyle: AppFonts.yekan13.copyWith( + color: AppColor.redNormal, + ), + + prefixIconConstraints: BoxConstraints( + maxHeight: 34, + minHeight: 34, + maxWidth: 34, + minWidth: 34, + ), + prefixIcon: Padding( + padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), + child: vecWidget(Assets.vecKeySvg), + ), + suffix: + passwordController.value.text.trim().isNotEmpty + ? GestureDetector( + onTap: () { + controller.hidePassword.value = + !controller.hidePassword.value; + }, + child: Icon( + controller.hidePassword.value + ? CupertinoIcons.eye + : CupertinoIcons.eye_slash, + ), + ) + : null, + counterText: '', + ), + textInputAction: TextInputAction.done, + keyboardType: TextInputType.visiblePassword, + maxLines: 1, + onChanged: (value) { + if (controller.isOnError.value) { + controller.isOnError.value = !controller.isOnError.value; + data.value.currentState?.reset(); + passwordController.value.text = value; + } + passwordController.refresh(); + }, + validator: (value) { + if (value == null || value.isEmpty) { + return '⚠️ رمز عبور را وارد کنید'; // "Please enter the password" + } + return null; + }, + style: AppFonts.yekan13, + ); + }, controller.passwordController), + + SizedBox(height: 23), + + ObxValue((timer) { + if (timer.value == 0) { + return TextButton( + onPressed: () { + controller.otpStatus.value = OtpStatus.reSend; + controller.startTimer(); + }, + child: Text( + style: AppFonts.yekan13.copyWith( + color: AppColor.blueNormal, + ), + 'ارسال مجدد کد یکبار مصرف', + ), + ); + } else { + return Text( + 'اعتبار رمز ارسال شده ${controller.timeFormatted}', + style: AppFonts.yekan13, + ); + } + }, controller.secondsRemaining), + + RichText( + text: TextSpan( + children: [ + TextSpan( + text: ' کد ارسال شده به شماره ', + style: AppFonts.yekan14.copyWith( + color: AppColor.darkGreyDark, + ), + ), + TextSpan( + text: controller.phoneOtpNumberController.value.text, + style: AppFonts.yekan13Bold.copyWith( + color: AppColor.darkGreyDark, + ), + ), + TextSpan( + recognizer: + TapGestureRecognizer() + ..onTap = () { + controller.otpStatus.value = OtpStatus.init; + }, + text: ' ویرایش', + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + + SizedBox(height: 23), + RElevated( + text: 'ورود', + onPressed: () { + if (controller.formKeyOtp.value.currentState?.validate() == + true) {} + }, + width: Get.width, + height: 48, + ), + ], + ), + ), + ); + }, controller.formKeySentOtp); + }*/ +} diff --git a/packages/livestock/lib/presentation/page/map/logic.dart b/packages/livestock/lib/presentation/page/map/logic.dart index 04370f3..f68b238 100644 --- a/packages/livestock/lib/presentation/page/map/logic.dart +++ b/packages/livestock/lib/presentation/page/map/logic.dart @@ -1,8 +1,7 @@ import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; class MapLogic extends GetxController { - var ss = Get.find(); - - + BaseLogic baseLogic = Get.find(); } diff --git a/packages/livestock/lib/presentation/page/map/view.dart b/packages/livestock/lib/presentation/page/map/view.dart index 6935217..670308d 100644 --- a/packages/livestock/lib/presentation/page/map/view.dart +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/presentation/widget/map/view.dart'; +import 'package:rasadyar_livestock/presentation/page/map/widget/map_widget/view.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/view.dart'; + import 'logic.dart'; class MapPage extends GetView { @@ -8,23 +10,158 @@ class MapPage extends GetView { @override Widget build(BuildContext context) { - return Scaffold( - body: Stack( + return BasePage( + hasSearch: true, + hasFilter: true, + hasBack: false, + defaultSearch: false, + filteringWidget: filterWidget(showIndex: 3.obs, filterIndex: 5.obs), + widgets: [MapWidget()], + ); + } + + Widget filterWidget({required RxInt filterIndex, required RxInt showIndex}) { + return BaseBottomSheet( + height: Get.height * 0.5, + child: Container(color: Colors.red), + ); + } + + BaseBottomSheet searchWidget() { + return BaseBottomSheet( + height: Get.height * 0.85, + rootChild: Column( + spacing: 8, children: [ - MapWidget( - markerWidget: Icon(Icons.pin_drop_rounded), - initOnTap: () { - - }, - initMarkerWidget: Assets.vec.mapMarkerSvg.svg( - width: 30, - height: 30, - ), + Row( + spacing: 12, + children: [ + Expanded( + child: RTextField( + height: 40, + borderColor: AppColor.blackLight, + suffixIcon: ObxValue( + (data) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: (data.value == null) + ? Assets.vec.searchSvg.svg( + width: 10, + height: 10, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ) + : IconButton( + onPressed: () { + controller.baseLogic.searchTextController.clear(); + controller.baseLogic.searchValue.value = null; + controller.baseLogic.isSearchSelected.value = false; + //controller.mapLogic.hasFilterOrSearch.value = false; + //controller.searchedPoultryLocation.value = Resource.initial(); + }, + enableFeedback: true, + padding: EdgeInsets.zero, + iconSize: 24, + splashRadius: 50, + icon: Assets.vec.closeCircleSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + ), + controller.baseLogic.searchValue, + ), + hintText: 'جستجو کنید ...', + hintStyle: AppFonts.yekan16.copyWith(color: AppColor.blueNormal), + filledColor: Colors.white, + filled: true, + controller: controller.baseLogic.searchTextController, + onChanged: (val) => controller.baseLogic.searchValue.value = val, + ), + ), + GestureDetector( + onTap: () { + Get.back(); + }, + child: Assets.vec.mapSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + ], ), + /* Expanded( + child: ObxValue((rxData) { + final resource = rxData.value; + final status = resource.status; + final items = resource.data; + final message = resource.message ?? 'خطا در بارگذاری'; + if (status == ResourceStatus.initial) { + return Center(child: Text('ابتدا جستجو کنید')); + } + + if (status == ResourceStatus.loading) { + return const Center(child: CircularProgressIndicator()); + } + + if (status == ResourceStatus.error) { + return Center(child: Text(message)); + } + + if (items == null || items.isEmpty) { + return Center(child: EmptyWidget()); + } + + return ListView.separated( + itemCount: items.length, + separatorBuilder: (context, index) => SizedBox(height: 8), + itemBuilder: (context, index) { + final item = items[index]; // اگر item استفاده نمیشه، می‌تونه حذف بشه + return ListItem2( + index: index, + labelColor: AppColor.blueLight, + labelIcon: Assets.vec.cowSvg.path, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + item.unitName ?? 'N/A', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + item.user?.fullname ?? '', + style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyDarkHover), + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'جوجه ریزی فعال', + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + Text( + (item.hatching != null && item.hatching!.isNotEmpty) + ? 'دارد' + : 'ندراد', + style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyDarkHover), + ), + ], + ), + ], + ), + ); + }, + ); + }, controller.searchedPoultryLocation), + ),*/ ], ), ); } } - diff --git a/packages/core/lib/presentation/widget/map/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart similarity index 64% rename from packages/core/lib/presentation/widget/map/logic.dart rename to packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index 78ab225..3b02375 100644 --- a/packages/core/lib/presentation/widget/map/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -1,23 +1,20 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; -import 'package:flutter_map/flutter_map.dart'; -import 'package:flutter_map_animations/flutter_map_animations.dart'; -import 'package:geolocator/geolocator.dart'; -import 'package:get/get.dart'; -import 'package:latlong2/latlong.dart'; -import 'package:rasadyar_core/utils/logger_utils.dart'; - -import 'custom_marker.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/common/constant.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; enum ErrorLocationType { serviceDisabled, permissionDenied, none } class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Rx currentLocation = LatLng(35.824891, 50.948025).obs; String tileType = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; + RxDouble currentZoom = 15.0.obs; - - RxList markers = [].obs; RxList allMarkers = [].obs; Rx mapController = MapController().obs; RxList errorLocationType = RxList(); @@ -25,6 +22,14 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; +/* FMTCTileProvider tileProvider = FMTCTileProvider( + stores: {mapStoreKey: BrowseStoreStrategy.readUpdateCreate}, + );*/ + + RxList markerLocations = RxList(); + RootLogic rootLogic = Get.find(); + LivestockRepository repository = diLiveStock.get(); + @override void onInit() { super.onInit(); @@ -53,12 +58,15 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { errorLocationType.remove(ErrorLocationType.serviceDisabled); } }); + + repository.addLocations(generateRandomLocations(currentLocation.value, 10, 100)); } @override void onReady() { super.onReady(); determineCurrentPosition(); + getLoc(); } @override @@ -89,8 +97,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { switch (permission) { case LocationPermission.denied: - final LocationPermission requestResult = - await Geolocator.requestPermission(); + final LocationPermission requestResult = await Geolocator.requestPermission(); return requestResult != LocationPermission.denied && requestResult != LocationPermission.deniedForever; @@ -117,9 +124,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { final latLng = LatLng(position.latitude, position.longitude); currentLocation.value = latLng; - markers.add( - CustomMarker(id: -1, point: latLng, ), - ); + animatedMapController.animateTo( dest: latLng, zoom: 18, @@ -138,7 +143,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { 'radius': 1000.0, }); - // markers.addAll(filtered); + // markers.addAll(filtered); }); } @@ -150,21 +155,45 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { final center = LatLng(centerLat, centerLng); final distance = Distance(); - return rawMarkers - .where((marker) => distance(center, marker) <= radiusInMeters) - .toList(); + return rawMarkers.where((marker) => distance(center, marker) <= radiusInMeters).toList(); } - void addMarker(CustomMarker marker) { - markers.add(marker); + Future getLoc() async { + await Future.delayed(Duration(seconds: 3)); + await safeCall( + call: () async => repository.getLocations(), + onSuccess: (result) { + iLog("OOOpssss => ${result.length}"); + markerLocations.addAll(result); + }, + onError: (error, stackTrace) {}, + ); } - void setMarkers(List newMarkers) { - markers.value = newMarkers; - } + List generateRandomLocations(LatLng currentPosition, double radiusInKm, int count) { + final random = Random(); + final locations = []; - void clearMarkers() { - markers.clear(); - } + for (int i = 0; i < count; i++) { + // فاصله تصادفی (۰ تا radius) + final distance = random.nextDouble() * radiusInKm * 1000; // متر + // زاویه تصادفی (۰ تا ۲π) + final angle = random.nextDouble() * 2 * pi; + // فاصله به درجه + final dx = distance * cos(angle); + final dy = distance * sin(angle); + + // 1 درجه lat ≈ 111km + final newLat = currentPosition.latitude + (dy / 111000.0); + + // 1 درجه lon ≈ 111km * cos(lat) + final newLng = + currentPosition.longitude + (dx / (111000.0 * cos(currentPosition.latitude * pi / 180))); + + locations.add(LatLng(newLat, newLng)); + } + + return locations; + } } diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart new file mode 100644 index 0000000..c260bd0 --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -0,0 +1,227 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/data/services/network_status.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; + +import 'logic.dart'; + +class MapWidget extends GetView { + const MapWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Expanded( + child: Stack( + fit: StackFit.expand, + children: [ + + + ObxValue((errorType) { + if (errorType.isNotEmpty) { + if (errorType.contains(ErrorLocationType.serviceDisabled)) { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text('سرویس مکان‌یابی غیرفعال است'), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + var service = await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove(ErrorLocationType.serviceDisabled); + Get.back(); + } + // Don't call Get.back() if service is still disabled + }, + ), + confirm: RElevated( + text: 'روشن کردن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await Geolocator.openLocationSettings(); + if (res) { + var service = await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove(ErrorLocationType.serviceDisabled); + Get.back(); + } + } + }, + ), + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } else { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text(' دسترسی به سرویس مکان‌یابی غیرفعال است'), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + await controller.checkPermission(); + }, + ), + confirm: RElevated( + text: 'اجازه دادن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await controller.checkPermission(request: true); + if (res) { + controller.errorLocationType.remove(ErrorLocationType.permissionDenied); + Get.back(); + } + }, + ), + + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } + } + return const SizedBox.shrink(); + }, controller.errorLocationType), + + ObxValue((currentLocation) { + return FlutterMap( + mapController: controller.animatedMapController.mapController, + options: MapOptions( + initialCenter: currentLocation.value, + interactionOptions: const InteractionOptions( + flags: InteractiveFlag.all & ~InteractiveFlag.rotate, + ), + initialZoom: 15, + onPositionChanged: (camera, hasGesture) { + controller.currentZoom.value = camera.zoom; + /* controller.debouncedUpdateVisibleMarkers( + center: camera.center, + zoom: camera.zoom, + );*/ + }, + ), + + children: [ + TileLayer( + urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + userAgentPackageName: 'ir.mnpc.rasadyar', + // tileProvider: controller.tileProvider, + ), + + ObxValue((markers) { + return MarkerClusterLayerWidget( + options: MarkerClusterLayerOptions( + maxClusterRadius: 80, + size: const Size(40, 40), + alignment: Alignment.center, + padding: const EdgeInsets.all(50), + maxZoom: 18, + markers: buildMarkers(markers), + builder: (context, clusterMarkers) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Colors.blue, + ), + child: Center( + child: Text( + clusterMarkers.length.toString(), + style: const TextStyle(color: Colors.white), + ), + ), + ); + }, + ), + ); + }, controller.markerLocations), + ], + ); + }, controller.currentLocation), + + Positioned( + top: 15, + left: 20, + child: ObxValue((status) { + return Text("Connection: ${status.value}", style: TextStyle(fontSize: 20)); + }, NetworkStatus().isConnected), + ), + + // Uncomment the following lines to enable the search widget + /* Positioned( + top: 10, + left: 20, + right: 20, + child: ObxValue((data) { + if (data.value) { + return SearchWidget( + onSearchChanged: (data) { + controller.baseLogic.searchValue.value = data; + }, + ); + } else { + return SizedBox.shrink(); + } + }, controller.baseLogic.isSearchSelected), + ),*/ + ], + ), + ); + } + + List buildMarkers(RxList latLng) => + latLng + .map( + (element) => + Marker( + point: element, + child: IconButton( + onPressed: () { + Get.bottomSheet( + detailsBottomSheet(), + isScrollControlled: true, + isDismissible: true, + ignoreSafeArea: false, + ); + }, + icon: Icon(CupertinoIcons.location_solid, color: AppColor.error), + ), + ), + ) + .toList(); + + Widget detailsBottomSheet() { + return BaseBottomSheet( + height: 250.h, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 20, + children: [ + Text('مشخصات محل', style: AppFonts.yekan16Bold), + // Add more details here + RElevated( + text: 'ایجاد بازرسی', + width: Get.width, + height: 40.h, + onPressed: () { + Get.toNamed(LiveStockRoutes.requestTagging); + }, + ), + ], + ), + ); + } +} diff --git a/packages/livestock/lib/presentation/page/profile/logic.dart b/packages/livestock/lib/presentation/page/profile/logic.dart index 811d534..bf982cb 100644 --- a/packages/livestock/lib/presentation/page/profile/logic.dart +++ b/packages/livestock/lib/presentation/page/profile/logic.dart @@ -1,5 +1,148 @@ +import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; class ProfileLogic extends GetxController { + RootLogic rootLogic = Get.find(); + RxInt selectedInformationType = 0.obs; + Rxn birthDate = Rxn(); + + + TextEditingController nameController = TextEditingController(); + TextEditingController lastNameController = TextEditingController(); + TextEditingController nationalCodeController = TextEditingController(); + TextEditingController nationalIdController = TextEditingController(); + TextEditingController birthdayController = TextEditingController(); + + TextEditingController oldPasswordController = TextEditingController(); + TextEditingController newPasswordController = TextEditingController(); + TextEditingController retryNewPasswordController = TextEditingController(); + +/* + RxList cites = [].obs; + Rxn selectedProvince = Rxn(); + Rxn selectedCity = Rxn(); +*/ + + GlobalKey formKey = GlobalKey(); + ImagePicker imagePicker = ImagePicker(); + Rxn selectedImage = Rxn(); + RxnString _base64Image = RxnString(); + RxBool isOnLoading = false.obs; + + @override + void onInit() { + super.onInit(); + ever(selectedImage, (data) async { + if (data?.path != null) { + _base64Image.value = await convertImageToBase64(data!.path); + } + }); + } + + @override + void onReady() { + super.onReady(); + getUserProfile(); + /*selectedProvince.listen((p0) => getCites()); + userProfile.listen((data) { + nameController.text = data.data?.firstName ?? ''; + lastNameController.text = data.data?.lastName ?? ''; + nationalCodeController.text = data.data?.nationalCode ?? ''; + nationalIdController.text = data.data?.nationalId ?? ''; + birthdayController.text = data.data?.birthday?.toJalali.formatCompactDate() ?? ''; + birthDate.value = data.data?.birthday?.toJalali; + selectedProvince.value = IranProvinceCityModel( + name: data.data?.province ?? '', + id: data.data?.provinceNumber ?? 0, + ); + + selectedCity.value = IranProvinceCityModel( + name: data.data?.city ?? '', + id: data.data?.cityNumber ?? 0, + ); + });*/ + } + + @override + void onClose() { + super.onClose(); + } + + Future getUserProfile() async { + /*userProfile.value = Resource.loading(); + await safeCall( + call: () async => await rootLogic.chickenRepository.getUserProfile( + token: rootLogic.tokenService.accessToken.value!, + ), + onSuccess: (result) { + if (result != null) { + userProfile.value = Resource.success(result); + } + }, + onError: (error, stackTrace) {}, + );*/ + } + + Future getCites() async { + /*await safeCall( + call: () => + rootLogic.chickenRepository.getCity(provinceName: selectedProvince.value?.name ?? ''), + onSuccess: (result) { + if (result != null && result.isNotEmpty) { + cites.value = result; + } + }, + );*/ + } + + Future updateUserProfile() async { + /* UserProfile userProfile = UserProfile( + firstName: nameController.text, + lastName: lastNameController.text, + nationalCode: nationalCodeController.text, + nationalId: nationalIdController.text, + birthday: birthDate.value?.toDateTime().formattedDashedGregorian.toString(), + image: _base64Image.value, + personType: 'self', + type: 'self_profile', + ); + isOnLoading.value = true; + await safeCall( + call: () async => await rootLogic.chickenRepository.updateUserProfile( + token: rootLogic.tokenService.accessToken.value!, + userProfile: userProfile, + ), + onSuccess: (result) { + isOnLoading.value = false; + }, + onError: (error, stackTrace) { + isOnLoading.value = false; + }, + );*/ + } + + Future updatePassword() async { + /* if (formKey.currentState?.validate() ?? false) { + ChangePasswordRequestModel model = ChangePasswordRequestModel( + username: userProfile.value.data?.mobile, + password: newPasswordController.text, + ); + + await safeCall( + call: () async => await rootLogic.chickenRepository.updatePassword( + token: rootLogic.tokenService.accessToken.value!, + model: model, + ), + ); + }*/ + } + + void clearPasswordForm() { + oldPasswordController.clear(); + newPasswordController.clear(); + retryNewPasswordController.clear(); + } } + diff --git a/packages/livestock/lib/presentation/page/profile/view.dart b/packages/livestock/lib/presentation/page/profile/view.dart index 1819ff5..691088a 100644 --- a/packages/livestock/lib/presentation/page/profile/view.dart +++ b/packages/livestock/lib/presentation/page/profile/view.dart @@ -1,5 +1,8 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; import 'logic.dart'; @@ -8,6 +11,698 @@ class ProfilePage extends GetView { @override Widget build(BuildContext context) { - return Container(); + return Column( + spacing: 30, + children: [ + Expanded( + flex: 1, + child: Container( + color: AppColor.blueNormal, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row(), + Container( + width: 128.w, + height: 128.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.blueLightActive, + ), + child: Center( + child: CircleAvatar( + radius: 64.w, + backgroundImage: Assets.images.chicken.provider(), + ), + ), + ), + /* ObxValue((data) { + final status = data.value.status; + + if (status == ResourceStatus.loading) { + return Container( + width: 128.w, + height: 128.h, + child: Center(child: CupertinoActivityIndicator(color: AppColor.greenNormal)), + ); + } + + if (status == ResourceStatus.error) { + return Container( + width: 128.w, + height: 128.h, + child: Center(child: Text('خطا در دریافت اطلاعات')), + ); + } + + // Default UI + return Container( + width: 128.w, + height: 128.h, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColor.blueLightActive, + ), + child: Center( + child: CircleAvatar( + radius: 64.w, + backgroundImage: NetworkImage(data.value.data!.image!), + ), + ), + ); + }, controller.userProfile),*/ + ], + ), + ), + ), + Expanded( + flex: 3, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 16, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 10), + child: userProfileInformation(), + ), + ), + + Center( + child: Wrap( + alignment: WrapAlignment.center, + spacing: 20, + runSpacing: 10, + children: [ + cardActionWidget( + title: 'تغییر رمز عبور', + selected: true, + onPressed: () { + Get.bottomSheet(changePasswordBottomSheet(), isScrollControlled: true); + }, + icon: Assets.vec.lockSvg.path, + ), + cardActionWidget( + title: 'خروج', + selected: true, + color: ColorFilter.mode(Colors.redAccent, BlendMode.srcIn), + cardColor: Color(0xFFEFEFEF), + textColor: AppColor.redDarkerText, + onPressed: () { + Get.bottomSheet(exitBottomSheet(), isScrollControlled: true); + }, + icon: Assets.vec.logoutSvg.path, + ), + ], + ), + ), + + SizedBox(height: 100), + ], + ), + ), + ], + ); + } + + Container invoiceIssuanceInformation() => Container(); + + Widget bankInformationWidget() => Column( + spacing: 16, + children: [ + itemList(title: 'نام بانک', content: 'سامان'), + itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'), + itemList(title: 'شماره کارت ', content: '54154545415'), + itemList(title: 'شماره حساب', content: '62565263263652'), + itemList(title: 'شماره شبا', content: '62565263263652'), + ], + ); + + Widget userProfileInformation() { + return Column( + spacing: 6, + children: [ + buildRowOnTapped( + onTap: () { + Get.bottomSheet( + userInformationBottomSheet(), + isScrollControlled: true, + ignoreSafeArea: false, + ); + }, + titleWidget: Column( + spacing: 3, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'اطلاعات هویتی', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + Container(width: 37.w, height: 1.h, color: AppColor.greenNormal), + ], + ), + valueWidget: Assets.vec.editSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + itemList( + title: 'نام و نام خانوادگی', + content: /*item.fullname ??*/ 'نامشخص', + icon: Assets.vec.userSvg.path, + hasColoredBox: true, + ), + itemList( + title: 'موبایل', + content: /* item.mobile ??*/ 'نامشخص', + icon: Assets.vec.callSvg.path, + ), + itemList( + title: 'کدملی', + content: /* item.nationalId ?? */ 'نامشخص', + icon: Assets.vec.tagUserSvg.path, + ), + itemList( + title: 'شماره شناسنامه', + content: /* item.nationalCode ??*/ 'نامشخص', + icon: Assets.vec.userSquareSvg.path, + ), + itemList( + title: 'تاریخ تولد', + content: /*item.birthday?.toJalali.formatCompactDate() ??*/ 'نامشخص', + icon: Assets.vec.calendarSvg.path, + ), + itemList( + title: 'استان', + content: /*item.province ??*/ 'نامشخص', + icon: Assets.vec.pictureFrameSvg.path, + ), + itemList(title: 'شهر', content: /* item.city ?? */ 'نامشخص', icon: Assets.vec.mapSvg.path), + ], + ); + /* return ObxValue((data) { + if (data.value.status == ResourceStatus.loading) { + return LoadingWidget(); + } else if (data.value.status == ResourceStatus.error) { + return ErrorWidget('خطا در دریافت اطلاعات کاربر'); + } else if (data.value.status == ResourceStatus.success) { + UserProfile item = data.value.data!; + return Column( + spacing: 6, + children: [ + buildRowOnTapped( + onTap: () { + Get.bottomSheet( + userInformationBottomSheet(), + isScrollControlled: true, + ignoreSafeArea: false, + ); + }, + titleWidget: Column( + spacing: 3, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'اطلاعات هویتی', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + Container(width: 37.w, height: 1.h, color: AppColor.greenNormal), + ], + ), + valueWidget: Assets.vec.editSvg.svg( + width: 24.w, + height: 24.h, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + itemList( + title: 'نام و نام خانوادگی', + content: */ /*item.fullname ??*/ /* 'نامشخص', + icon: Assets.vec.userSvg.path, + hasColoredBox: true, + ), + itemList( + title: 'موبایل', + content:*/ /* item.mobile ??*/ /* 'نامشخص', + icon: Assets.vec.callSvg.path, + ), + itemList( + title: 'کدملی', + content:*/ /* item.nationalId ?? */ /*'نامشخص', + icon: Assets.vec.tagUserSvg.path, + ), + itemList( + title: 'شماره شناسنامه', + content:*/ /* item.nationalCode ??*/ /* 'نامشخص', + icon: Assets.vec.userSquareSvg.path, + ), + itemList( + title: 'تاریخ تولد', + content: */ /*item.birthday?.toJalali.formatCompactDate() ??*/ /* 'نامشخص', + icon: Assets.vec.calendarSvg.path, + ), + itemList( + title: 'استان', + content: item.province ?? 'نامشخص', + icon: Assets.vec.pictureFrameSvg.path, + ), + itemList(title: 'شهر', content: item.city ?? 'نامشخص', icon: Assets.vec.mapSvg.path), + ], + ); + } else { + return SizedBox.shrink(); + } + }, controller.userProfile);*/ + } + + Widget itemList({ + required String title, + required String content, + String? icon, + bool hasColoredBox = false, + }) => Container( + padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h), + decoration: BoxDecoration( + color: hasColoredBox ? AppColor.greenLight : Colors.transparent, + borderRadius: BorderRadius.circular(8), + border: hasColoredBox + ? Border.all(width: 0.25, color: AppColor.bgDark) + : Border.all(width: 0, color: Colors.transparent), + ), + child: Row( + spacing: 4, + children: [ + if (icon != null) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: SvgGenImage.vec(icon).svg( + width: 20.w, + height: 20.h, + colorFilter: ColorFilter.mode(AppColor.mediumGreyNormalActive, BlendMode.srcIn), + ), + ), + Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.mediumGreyNormalActive)), + Spacer(), + Text(content, style: AppFonts.yekan13.copyWith(color: AppColor.mediumGreyNormalHover)), + ], + ), + ); + + Widget cardActionWidget({ + required String title, + required VoidCallback onPressed, + required String icon, + bool selected = false, + ColorFilter? color, + Color? cardColor, + Color? textColor, + }) { + return GestureDetector( + onTap: onPressed, + child: Column( + spacing: 4, + children: [ + Container( + width: 52, + height: 52, + padding: EdgeInsets.all(8), + decoration: ShapeDecoration( + color: cardColor ?? AppColor.blueLight, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: SvgGenImage.vec(icon).svg( + width: 40, + height: 40, + colorFilter: + color ?? + ColorFilter.mode( + selected ? AppColor.blueNormal : AppColor.whiteLight, + BlendMode.srcIn, + ), + ), + ), + SizedBox(height: 2), + Text( + title, + style: AppFonts.yekan10.copyWith( + color: textColor ?? (selected ? AppColor.blueNormal : AppColor.blueLightActive), + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + Widget userInformationBottomSheet() { + return BaseBottomSheet( + height: 750.h, + child: SingleChildScrollView( + child: Column( + spacing: 8, + children: [ + Text( + 'ویرایش اطلاعات هویتی', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover), + ), + + Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight, width: 1), + ), + child: Column( + spacing: 12, + children: [ + RTextField( + controller: controller.nameController, + label: 'نام', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + ), + RTextField( + controller: controller.lastNameController, + label: 'نام خانوادگی', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + ), + RTextField( + controller: controller.nationalCodeController, + label: 'شماره شناسنامه', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + ), + RTextField( + controller: controller.nationalIdController, + label: 'کد ملی', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + ), + + ObxValue((data) { + return RTextField( + controller: controller.birthdayController, + label: 'تاریخ تولد', + initText: data.value?.formatCompactDate() ?? '', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + onTap: () {}, + ); + }, controller.birthDate), + + SizedBox(), + ], + ), + ), + SizedBox(), + + Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight, width: 1), + ), + child: Column( + spacing: 8, + children: [ + Text( + 'عکس پروفایل', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal), + ), + ObxValue((data) { + return Container( + width: Get.width, + height: 270, + decoration: BoxDecoration( + color: AppColor.lightGreyNormal, + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 1, color: AppColor.blackLight), + ), + child: Center( + child: data.value == null + ? Padding( + padding: const EdgeInsets.fromLTRB(30, 10, 10, 30), + child: Image.network(''), + ) + : Image.file(File(data.value!.path), fit: BoxFit.cover), + ), + ); + }, controller.selectedImage), + + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RElevated( + text: 'گالری', + width: 150.w, + height: 40.h, + textStyle: AppFonts.yekan20.copyWith(color: Colors.white), + onPressed: () async { + controller.selectedImage.value = await controller.imagePicker.pickImage( + source: ImageSource.gallery, + imageQuality: 60, + maxWidth: 1080, + maxHeight: 720, + ); + }, + ), + SizedBox(width: 16), + ROutlinedElevated( + text: 'دوربین', + width: 150.w, + height: 40.h, + textStyle: AppFonts.yekan20.copyWith(color: AppColor.blueNormal), + onPressed: () async { + controller.selectedImage.value = await controller.imagePicker.pickImage( + source: ImageSource.camera, + imageQuality: 60, + maxWidth: 1080, + maxHeight: 720, + ); + }, + ), + ], + ), + ], + ), + ), + Row( + spacing: 16, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ObxValue((data) { + return RElevated( + height: 40.h, + text: 'ویرایش', + isLoading: data.value, + onPressed: () async { + await controller.updateUserProfile(); + controller.getUserProfile(); + Get.back(); + }, + ); + }, controller.isOnLoading), + ROutlinedElevated( + height: 40.h, + text: 'انصراف', + borderColor: AppColor.blueNormal, + onPressed: () { + Get.back(); + }, + ), + ], + ), + ], + ), + ), + ); + } + + /* Widget _provinceWidget() { + return Obx(() { + return OverlayDropdownWidget( + items: controller.rootLogic.provinces, + onChanged: (value) { + controller.selectedProvince.value = value; + }, + selectedItem: controller.selectedProvince.value, + itemBuilder: (item) => Text(item.name ?? 'بدون نام'), + labelBuilder: (item) => Text(item?.name ?? 'انتخاب استان'), + ); + }); + } + + Widget _cityWidget() { + return ObxValue((data) { + return OverlayDropdownWidget( + items: data, + onChanged: (value) { + controller.selectedCity.value = value; + }, + selectedItem: controller.selectedCity.value, + itemBuilder: (item) => Text(item.name ?? 'بدون نام'), + labelBuilder: (item) => Text(item?.name ?? 'انتخاب شهر'), + ); + }, controller.cites); + }*/ + + Widget changePasswordBottomSheet() { + return BaseBottomSheet( + height: 400.h, + child: SingleChildScrollView( + child: Form( + key: controller.formKey, + child: Column( + spacing: 8, + children: [ + Text( + 'تغییر رمز عبور', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover), + ), + SizedBox(), + RTextField( + controller: controller.oldPasswordController, + hintText: 'رمز عبور قبلی', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + validator: (value) { + /* if (value == null || value.isEmpty) { + return 'رمز عبور را وارد کنید'; + } else if (controller.userProfile.value.data?.password != value) { + return 'رمز عبور صحیح نیست'; + }*/ + return null; + }, + ), + RTextField( + controller: controller.newPasswordController, + hintText: 'رمز عبور جدید', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'رمز عبور را وارد کنید'; + } else if (value.length < 6) { + return 'رمز عبور باید بیش از 6 کارکتر باشد.'; + } + return null; + }, + ), + RTextField( + controller: controller.retryNewPasswordController, + hintText: 'تکرار رمز عبور جدید', + borderColor: AppColor.darkGreyLight, + filledColor: AppColor.bgLight, + filled: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'رمز عبور را وارد کنید'; + } else if (value.length < 6) { + return 'رمز عبور باید بیش از 6 کارکتر باشد.'; + } else if (controller.newPasswordController.text != value) { + return 'رمز عبور جدید یکسان نیست'; + } + return null; + }, + ), + + SizedBox(), + + Row( + spacing: 16, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RElevated( + height: 40.h, + text: 'ویرایش', + onPressed: () async { + if (controller.formKey.currentState?.validate() != true) { + return; + } + await controller.updatePassword(); + controller.getUserProfile(); + controller.clearPasswordForm(); + Get.back(); + }, + ), + ROutlinedElevated( + height: 40.h, + text: 'انصراف', + borderColor: AppColor.blueNormal, + onPressed: () { + Get.back(); + }, + ), + ], + ), + ], + ), + ), + ), + ); + } + + Widget exitBottomSheet() { + return BaseBottomSheet( + height: 220.h, + child: SingleChildScrollView( + child: Form( + key: controller.formKey, + child: Column( + spacing: 8, + children: [ + Text('خروج', style: AppFonts.yekan16Bold.copyWith(color: AppColor.error)), + SizedBox(), + Text( + 'آیا مطمئن هستید که می‌خواهید از حساب کاربری خود خارج شوید؟', + textAlign: TextAlign.center, + style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor), + ), + + SizedBox(), + + Row( + spacing: 16, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + RElevated( + height: 40.h, + text: 'خروج', + backgroundColor: AppColor.error, + onPressed: () async { + await controller.rootLogic.tokenService.deleteTokens().then((value) { + Get.back(); + Get.offAllNamed(LiveStockRoutes.auth, arguments: Module.chicken); + }); + }, + ), + ROutlinedElevated( + height: 40.h, + text: 'انصراف', + borderColor: AppColor.blueNormal, + onPressed: () { + Get.back(); + }, + ), + ], + ), + ], + ), + ), + ), + ); } } diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index de94cdb..0625a2c 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,17 +1,345 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; +import 'package:rasadyar_livestock/data/service/live_stock_storage_service.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; class RequestTaggingLogic extends GetxController { + LiveStockStorageService liveStockStorageService = Get.find(); + RxInt currentIndex = 0.obs; + final int maxStep = 2; + + RxBool nextButtonEnabled = true.obs; + + LivestockRepository livestockRepository = diLiveStock.get(); + LivestockData? liveStockTmp; + + //region First Step + final TextEditingController phoneController = TextEditingController(); + final TextEditingController fullNameController = TextEditingController(); + final TextEditingController addressController = TextEditingController(); + ImagePicker imagePicker = diLiveStock.get(); + Rxn rancherImage = Rxn(null); + + //endregion + + //region Second Step + Rxn herdImage = Rxn(null); + Rx> addressDetails = Rx>(Resource.loading()); + RxnString addressDetailsValue = RxnString(null); + Rxn addressLocationValue = Rxn(); + + RxInt selectedSegment = 0.obs; + RxBool searchIsSelected = false.obs; + RxBool filterIsSelected = false.obs; + RxList filterSelected = [].obs; + RxList isExpandedList = [].obs; + + RxBool tst1 = false.obs; + + //endregion + + //region Third Step + RxnString species = RxnString(null); + RxnString breed = RxnString(null); + Rx dateOfBirth = Rx(Jalali.now()); + RxInt selectedSex = 0.obs; + TextEditingController motherTagNumberController = TextEditingController(); + TextEditingController fatherTagNumberController = TextEditingController(); + TextEditingController herdTagController = TextEditingController(); + RxnString tagType = RxnString(); + Rxn taggingImage = Rxn(null); + + Rxn rancher = Rxn(null); + Rxn herd = Rxn(null); + RxList livestockList = [].obs; + + RxBool isLoading = false.obs; + + //endregion + + @override + void onInit() { + super.onInit(); + setUpTextControllerListeners(); + setUpNextButtonListeners(); + ever(rancherImage, (callback) { + setUpNextButtonListeners(); + }); + + determineCurrentPosition(); + } -final TextEditingController phoneController = TextEditingController(); @override void onReady() { super.onReady(); + + rancher.value = Rancher( + name: 'حسن حسنی', + phone: '09121234567', + image: '/9j/4nd9KcTTcWUsuoF0cSwuZSjYX', + ); + + herd.value = Herd( + location: Location(lat: 35.825081, lng: 50.948177), + address: 'استان البرز, بخش مرکزی کرج, کرج, منطقه ۵, دهقان ویلا, بلوار سرداران', + image: '/9j/4QL6RXhpZgAATU0AKgAA', + ); + + var s = List.generate( + 10_000, + (index) => Livestock( + sex: index % 2 == 0 ? 'نر' : 'ماده', + tagNumber: index.toString(), + fatherTag: (index * 2).toString(), + motherTag: (index * 3).toString(), + species: 'نوع $index', + breed: index % 2 == 0 ? 'گوسفند ماده' : 'گاو ماده', + tagType: index % 2 == 0 ? 'نوع 1' : 'نوع 2', + dateOfBirth: "23/10/2023", + image: '/9j/4QLmRXhpZgAATU', + ), + ); + livestockList.addAll(s); } @override void onClose() { super.onClose(); } + + void onNext() async { + if (currentIndex.value < maxStep) { + if (currentIndex.value == 0) { + liveStockTmp = LivestockData( + rancher: Rancher( + name: fullNameController.text, + phone: phoneController.text, + image: await convertToBase64(rancherImage), + ), + ); + } else if (currentIndex.value == 1) { + liveStockTmp = liveStockTmp?.copyWith( + herd: Herd( + location: Location( + lat: addressLocationValue.value?.latitude, + lng: addressLocationValue.value?.longitude, + ), + address: addressDetailsValue.value, + image: await convertToBase64(herdImage), + ), + ); + } + currentIndex.value++; + } else { + createTaggingLiveStock(); + } + } + + void onPrevious() { + if (currentIndex.value > 0) { + currentIndex.value--; + } + } + + void setUpNextButtonListeners() { + if (currentIndex.value == 0) { + /* nextButtonEnabled.value = + phoneController.text.isNotEmpty && + fullNameController.text.isNotEmpty && + addressController.text.isNotEmpty && + rancherImage.value != null;*/ + + return; + } + } + + void setUpTextControllerListeners() { + phoneController.addListener(setUpNextButtonListeners); + fullNameController.addListener(setUpNextButtonListeners); + addressController.addListener(setUpNextButtonListeners); + } + + Future pickImage(Rxn file) async { + file.value = await imagePicker.pickImage( + source: ImageSource.camera, + imageQuality: 60, + maxWidth: 1080, + maxHeight: 720, + ); + + getFileSizeInKB(file.value?.path ?? '', tag: 'Picked'); + } + + Future cropImage() async { + if (rancherImage.value == null) return; + + final CroppedFile? cropped = await ImageCropper().cropImage( + sourcePath: rancherImage.value!.path, + maxWidth: 1080, + maxHeight: 720, + compressQuality: 60, + ); + if (cropped == null) return; + rancherImage.value = XFile(cropped.path); + + getFileSizeInKB(rancherImage.value?.path ?? '', tag: 'Cropped'); + } + + Future convertToBase64(Rxn fromFile) async { + if (fromFile.value == null) return null; + + final bytes = await fromFile.value!.readAsBytes(); + final base64String = base64Encode(bytes); + + return base64String; + } + + Future convertBase64ToImage(RxnString fromFile, Rxn toFile) async { + if (fromFile.value == null) return; + + // Decode Base64 → bytes + Uint8List imageBytes = base64Decode(fromFile.value!); + + // Save bytes to a temp file + final tempDir = await getTemporaryDirectory(); + final filePath = '${tempDir.path}/temp_image.png'; + await File(filePath).writeAsBytes(imageBytes); + + // Create XFile from that temp file + toFile.value = XFile(filePath); + } + + Future determineCurrentPosition() async { + final position = await Geolocator.getCurrentPosition( + locationSettings: AndroidSettings(accuracy: LocationAccuracy.best), + ); + + getLocationDetails(position.latitude, position.longitude); + } + + Future getLocationDetails(double latitude, double longitude) async { + safeCall( + call: () => livestockRepository.getLocationDetails(latitude: latitude, longitude: longitude), + onSuccess: (result) { + if (result != null) { + addressDetails.value = Resource.success(result); + buildAddressDetails(result); + addressLocationValue.value = LatLng(latitude, longitude); + } else { + addressDetails.value = Resource.error('Failed to fetch address'); + } + }, + onError: (error, stackTrace) { + addressDetails.value = Resource.error('Error fetching address: ${error.toString()}'); + }, + ); + } + + void buildAddressDetails(LocationDetails result) { + final address = result.address; + if (address != null) { + final addressParts = [ + address.state, + address.county, + address.district, + address.city, + address.suburb, + address.neighbourhood, + address.road, + ].where((part) => part != null && part.isNotEmpty).join(', '); + addressDetailsValue.value = addressParts; + } else { + addressDetailsValue.value = 'Address not found'; + } + } + + void clearForms() { + phoneController.clear(); + fullNameController.clear(); + addressController.clear(); + rancherImage.value = null; + herdImage.value = null; + addressDetails.value = Resource.loading(); + addressDetailsValue.value = null; + addressLocationValue.value = null; + species.value = null; + breed.value = null; + selectedSex.value = 0; + motherTagNumberController.clear(); + fatherTagNumberController.clear(); + herdTagController.clear(); + tagType.value = null; + taggingImage.value = null; + } + + Future createTaggingLiveStock() async { + // isLoading.value = true; + if (livestockList.isEmpty) { + Get.snackbar('Error', 'Please fill all required fields'); + return; + } + + var batches = chunkedList( + livestockList, + 500, + ).map((e) => LivestockData(rancher: rancher.value, herd: herd.value, livestock: e)); + + await liveStockStorageService.saveBulkLiveStockData(batches); + + var tmpData = await liveStockStorageService.getLiveStockData(); + + for (int i = 0; i < tmpData.length; i++) { + await safeCall( + call: () => livestockRepository.createTaggingLiveStock(data: tmpData[i]), + onSuccess: (result) async { + if (i == tmpData.length - 1) { + Get.snackbar('Success', 'All livestock tagged successfully'); + await liveStockStorageService.deleteLiveBox(); + var ss = await liveStockStorageService.getLiveStockData(); + iLog('tagged livestock: ${ss.length}'); + } + }, + onError: (error, stackTrace) {}, + ); + } + + isLoading.value = false; + } + + List> chunkedList(List list, int chunkSize) { + List> batches = []; + + for (int i = 0; i < livestockList.length; i += chunkSize) { + batches.add(livestockList.sublist(i, min(i + chunkSize, livestockList.length))); + } + return batches; + } + + void addLiveStock() async { + livestockList.add( + Livestock( + species: species.value, + dateOfBirth: dateOfBirth.value.formatCompactDate(), + breed: breed.value, + sex: selectedSegment.value == 0 ? 'نر' : 'ماده', + motherTag: motherTagNumberController.text, + fatherTag: fatherTagNumberController.text, + tagNumber: herdTagController.text, + tagType: tagType.value, + image: await convertToBase64(taggingImage), + ), + ); + + clearForms(); + + iLog(livestockList); + } } diff --git a/packages/livestock/lib/presentation/page/request_tagging/view.dart b/packages/livestock/lib/presentation/page/request_tagging/view.dart index 0ff57ed..b72d4bf 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/view.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -1,7 +1,9 @@ +import 'dart:io'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/view.dart'; import 'logic.dart'; @@ -10,100 +12,1130 @@ class RequestTaggingPage extends GetView { @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.white, - appBar: RAppBar( - title: 'درخواست پلاک کوبی', - leadingWidth: 40, - leading: Assets.vec.messageAddSvg.svg(width: 12, height: 12), - ), - body: Padding( - padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15), - child: Column( - children: [ - RTextField( - controller: controller.phoneController, - label: 'تلفن دامدار', - ), + return BasePage( + title: 'درخواست پلاک کوبی', + hasSearch: false, + hasFilter: false, + hasBack: true, + avoidBottomInset: false, + widgets: [ + ObxValue((index) { + return Expanded( + child: Padding(padding: const EdgeInsets.all(8.0), child: _buildStep(index.value)), + ); + }, controller.currentIndex), - SizedBox( - width: Get.width, - height: 356, - child: Card( - color: Colors.white, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Expanded( - child: Container( - width: Get.width, + nextOrPreviousWidget(), + SizedBox(height: 10.h), + ], + ); + } - decoration: BoxDecoration( - color: AppColor.lightGreyNormal, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Assets.images.placeHolder.image( - height: 150, - width: 200, - ), - ), - ), - ), - SizedBox(height: 15), - Container( - width: Get.width, - height: 40, - clipBehavior: Clip.antiAlias, - decoration: ShapeDecoration( - color: AppColor.blueNormal, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: Padding( - padding: const EdgeInsets.all(10.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - ' تصویر گله', - style: AppFonts.yekan14.copyWith( - color: Colors.white, - ), - ), - Icon( - CupertinoIcons.arrow_up_doc, - color: Colors.white, - ), - ], - ), - ), - ), - ], - ), - ), + Widget nextOrPreviousWidget() { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + spacing: 10, + children: [ + ObxValue( + (data) => Expanded( + flex: 2, + child: RElevated( + height: 40.h, + enabled: data.value, + onPressed: controller.onNext, + isLoading: controller.isLoading.value, + child: Text(controller.currentIndex.value == 2 ? 'ثبت' : 'بعدی'), + backgroundColor: AppColor.blueNormal, ), ), + controller.nextButtonEnabled, + ), + Expanded( + child: ObxValue((data) { + return ROutlinedElevated( + enabled: data.value > 0, + onPressed: controller.onPrevious, + child: Text('قبلی'), + borderColor: AppColor.error, + ); + }, controller.currentIndex), + ), + ], + ), + ); + } - Spacer(), + Widget _buildStep(int index) { + switch (index) { + case 0: + return firstStepWidget(); + case 1: + return secondStepWidget(); + case 2: + return thirdStepWidget(); + default: + return Center( + child: Text( + 'مرحله $index در دست توسعه است', + style: AppFonts.yekan16.copyWith(color: AppColor.redNormal), + textDirection: TextDirection.rtl, + ), + ); + } + } + //TODO + Future showCropDialog() async { + await Get.dialog( + Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + 'آیا نیازی به برش تصویر دارید؟', + style: AppFonts.yekan16Bold, + textAlign: TextAlign.center, + ), + const SizedBox(height: 24), - RElevated( - text: 'ارسال تصویر گله', - onPressed: () { - Get.toNamed(LiveStockRoutes.tagging); - }, - height: 40, - isFullWidth: true, - backgroundColor: AppColor.greenNormal, - textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + Row( + spacing: 12.w, + children: [ + RElevated( + width: 150.w, + height: 40.h, + onPressed: () async { + Get.back(); + await controller.cropImage(); + }, + child: const Text('بله'), + ), + ROutlinedElevated( + width: 150.w, + onPressed: () => Get.back(), + child: const Text('خیر'), + borderColor: AppColor.error, + ), + ], ), ], ), ), ); } + + //region First Step Widget + Widget firstStepWidget() { + return Form( + child: Column( + spacing: 16, + children: [ + Container( + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + border: Border.all(color: AppColor.lightGreyNormal, width: 1), + borderRadius: BorderRadius.circular(8), + ), + child: Column( + spacing: 10, + children: [ + Row(children: [Text('اطلاعات دامدار', style: AppFonts.yekan16Bold)]), + RTextField(controller: controller.fullNameController, label: 'نام ونام خانوادگی'), + RTextField(controller: controller.phoneController, label: 'تلفن'), + RTextField(controller: controller.addressController, label: 'ادرس'), + ], + ), + ), + + SizedBox( + width: Get.width, + height: 356.h, + child: Container( + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + border: Border.all(color: AppColor.lightGreyNormal, width: 1.w), + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + spacing: 8, + children: [ + Row(children: [Text('تصویر دامدار', style: AppFonts.yekan16Bold)]), + Expanded( + child: Container( + width: Get.width, + decoration: BoxDecoration( + color: AppColor.lightGreyNormal, + borderRadius: BorderRadius.circular(8.r), + ), + child: Center( + child: ObxValue((tmpImage) { + if (tmpImage.value == null) { + return Assets.vec.placeHolderSvg.svg(height: 150.h, width: 200.w); + } else { + return Image.file(File(tmpImage.value!.path), fit: BoxFit.cover); + } + }, controller.rancherImage), + ), + ), + ), + GestureDetector( + onTap: () async { + await controller.pickImage(controller.rancherImage); + await showCropDialog(); + }, + child: Container( + width: Get.width, + height: 40.h, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: AppColor.blueNormal, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: Padding( + padding: EdgeInsets.all(10.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(' دوربین', style: AppFonts.yekan14.copyWith(color: Colors.white)), + Icon(CupertinoIcons.arrow_up_doc, color: Colors.white), + ], + ), + ), + ), + ), + ], + ), + ), + ), + + /* RElevated( + text: 'ارسال تصویر گله', + onPressed: () { + Get.toNamed(LiveStockRoutes.tagging); + }, + height: 40, + isFullWidth: true, + backgroundColor: AppColor.greenNormal, + textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + ),*/ + ], + ), + ); + } + + //endregion + + //region Second Step Widget + Widget secondStepWidget() { + return Column( + spacing: 12.h, + children: [ + SizedBox(height: 20), + + Container( + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + border: Border.all(color: AppColor.borderColor, width: 1.w), + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + spacing: 12.h, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row(children: [Text('مشخصات موقعیت', style: AppFonts.yekan16Bold)]), + ObxValue((data) { + if (data.value.status == ResourceStatus.loading || + data.value.status == ResourceStatus.initial) { + return Center(child: CupertinoActivityIndicator()); + } else if (data.value.status == ResourceStatus.error) { + return Center( + child: Column( + children: [ + Text( + 'خطا در دریافت اطلاعات', + style: AppFonts.yekan16.copyWith(color: AppColor.redNormal), + ), + ROutlinedElevated( + onPressed: () async { + await controller.determineCurrentPosition(); + }, + child: Text('تلاش مجدد'), + borderColor: AppColor.error, + ), + ], + ), + ); + } else if (data.value.status == ResourceStatus.success) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8.h, + children: [ + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'موقعیت مکانی: ', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor), + ), + TextSpan( + text: + '${controller.addressLocationValue.value?.latitude} , ${controller.addressLocationValue.value?.longitude}', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + ], + ), + ), + Text( + controller.addressDetailsValue.string ?? 'N/A', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + ], + ); + } else { + return SizedBox.shrink(); + } + }, controller.addressDetails), + ], + ), + ), + + SizedBox( + width: Get.width, + height: 356.h, + child: Container( + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + border: Border.all(color: AppColor.borderColor, width: 1.w), + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + spacing: 12.h, + children: [ + Row(children: [Text('تصویر گله', style: AppFonts.yekan16Bold)]), + Expanded( + child: Container( + width: Get.width, + decoration: BoxDecoration( + color: AppColor.lightGreyNormal, + borderRadius: BorderRadius.circular(8.r), + ), + child: Center( + child: ObxValue((tmpImage) { + if (tmpImage.value == null) { + return Assets.vec.placeHolderSvg.svg(height: 150.h, width: 200.w); + } else { + return Image.file(File(tmpImage.value!.path), fit: BoxFit.cover); + } + }, controller.herdImage), + ), + ), + ), + GestureDetector( + onTap: () async { + await controller.pickImage(controller.herdImage); + await showCropDialog(); + }, + child: Container( + width: Get.width, + height: 40.h, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: AppColor.blueNormal, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: Padding( + padding: EdgeInsets.all(10.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(' دوربین', style: AppFonts.yekan14.copyWith(color: Colors.white)), + Icon(CupertinoIcons.arrow_up_doc, color: Colors.white), + ], + ), + ), + ), + ), + ], + ), + ), + ), + + Spacer(), + + RElevated( + text: 'ارسال تصویر گله', + onPressed: () {}, + height: 40, + isFullWidth: true, + backgroundColor: AppColor.greenNormal, + textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + ), + ], + ); + } + + //endregion + + //region Third Step Widget + + Widget thirdStepWidget() { + return Stack( + children: [ + Column( + children: [ + _buildFilterWidget(), + _buildSearchWidget(), + _buildInfoDetails(), + _buildListContent(), + ], + ), + Positioned( + right: 10, + bottom: 5, + child: RFab.add( + onPressed: () { + Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); + }, + ), + ), + ], + ); + } + + Container _buildInfoDetails() { + return Container( + height: 40.h, + margin: EdgeInsets.symmetric(vertical: 8.h), + decoration: BoxDecoration( + color: AppColor.greenLightHover, + borderRadius: BorderRadius.circular(8.r), + border: Border.all(color: AppColor.darkGreyLight), + ), + alignment: Alignment.center, + child: Text('پلاک شده : سبک 5 و سنگین 8 راس'), + ); + } + + Expanded _buildListContent() { + return Expanded( + child: ObxValue((data) { + return RListView.separated( + itemCount: data.length, + padding: EdgeInsets.symmetric(horizontal: 8.w), + itemBuilder: (BuildContext context, int index) { + return ObxValue((val) { + return ExpandableListItem2( + isTag: true, + selected: val.contains(index), + onTap: () => controller.isExpandedList.toggle(index), + index: index, + child: itemListWidget(index), + secondChild: itemListExpandedWidget(index), + labelColor: AppColor.blueLight, + labelIcon: Assets.vec.virtualSvg.path, + ); + }, controller.isExpandedList); + }, + resource: Resource.success(List.generate(data.length, (i) => i)), + separatorBuilder: (BuildContext context, int index) => SizedBox(height: 8.h), + ); + }, controller.livestockList), + ); + } + + Stack _buildItemList(int index) { + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + right: -12, + top: 0, + bottom: 0, + child: Container( + width: 30, + height: 30, + child: Stack( + alignment: Alignment.center, + children: [ + Assets.vec.tagLabelSvg.svg(width: 30, height: 30), + Positioned( + bottom: 25, + right: 2, + left: 2, + child: Text( + (index > 10 ? index * 1000 : index + 1).toString(), + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + fontSize: ((index > 10 ? index * 1000 : index + 1).toString()).length > 3 + ? 6 + : 8, + color: AppColor.blueDarkActive, + ), + textScaler: TextScaler.linear(1.5), + ), + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildBottomSheet() { + return BaseBottomSheet( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 8, + children: [ + _buildLiveStockSpecies(), + _buildLivestockBirthday(), + _buildLivestockGender(), + + _buildLivestockBreed(), + + _buildMotherTagNumber(), + _buildFatherTagNumber(), + _buildTagNumber(), + _buildTagType(), + + _buildLiveStockImage(), + + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: RElevated( + text: 'افزودن دام به گله', + textStyle: AppFonts.yekan18.copyWith(color: Colors.white), + width: Get.width, + backgroundColor: AppColor.greenNormal, + height: 40, + onPressed: () { + controller.addLiveStock(); + Get.back(); + }, + ), + ), + ], + ), + ); + } + + Widget _buildInfoBottomSheet() { + return BaseBottomSheet( + height: Get.height * 0.5, + bgColor: const Color(0xFFF5F5F5), + child: Card( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 15, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + Text('محمد احمدی', style: AppFonts.yekan14), + + GestureDetector( + onTap: () { + _buildDeleteDialog(onConfirm: () {}); + }, + child: Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), + ), + ), + ], + ), + Container( + height: 32, + padding: EdgeInsets.all(8), + decoration: BoxDecoration(color: AppColor.blueLightHover), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'تاریخ ثبت', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '1404/2/2', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شماره پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '123456789012346', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'جنسیت ', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'افشاری', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع گله', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'روستایی', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شهر', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'کرج', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'سن', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ], + ), + ), + ), + ); + } + + void _buildDeleteDialog({required VoidCallback onConfirm}) { + Get.defaultDialog( + title: 'حذف دام', + middleText: 'آیا از حذف این دام مطمئن هستید؟', + confirm: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: AppColor.error, + foregroundColor: Colors.white, + ), + onPressed: onConfirm, + child: Text('بله'), + ), + cancel: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('خیر'), + ), + ); + } + + SizedBox _buildLiveStockImage() { + return SizedBox( + width: Get.width, + height: 356.h, + child: Container( + padding: EdgeInsets.all(8.r), + decoration: BoxDecoration( + border: Border.all(color: AppColor.lightGreyNormal, width: 1.w), + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + spacing: 8, + children: [ + Row(children: [Text('تصویر دام', style: AppFonts.yekan16Bold)]), + Expanded( + child: Container( + width: Get.width, + decoration: BoxDecoration( + color: AppColor.lightGreyNormal, + borderRadius: BorderRadius.circular(8.r), + ), + child: Center( + child: ObxValue((tmpImage) { + if (tmpImage.value == null) { + return Assets.vec.placeHolderSvg.svg(height: 150.h, width: 200.w); + } else { + return Image.file(File(tmpImage.value!.path), fit: BoxFit.cover); + } + }, controller.taggingImage), + ), + ), + ), + GestureDetector( + onTap: () async { + await controller.pickImage(controller.taggingImage); + await showCropDialog(); + }, + child: Container( + width: Get.width, + height: 40.h, + clipBehavior: Clip.antiAlias, + decoration: ShapeDecoration( + color: AppColor.blueNormal, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: Padding( + padding: EdgeInsets.all(10.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(' دوربین', style: AppFonts.yekan14.copyWith(color: Colors.white)), + Icon(CupertinoIcons.arrow_up_doc, color: Colors.white), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + OverlayDropdownWidget _buildTagType() { + return OverlayDropdownWidget( + items: ['نوع پلاک 1', 'نوع پلاک 2', 'نوع پلاک 3'], + onChanged: (value) { + controller.tagType.value = value; + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'نوع پلاک'), + ); + } + + TextFiledFixedHint _buildTagNumber() { + return TextFiledFixedHint( + controller: controller.herdTagController, + inputType: InputType.number, + hintText: 'پلاک دام', + onChanged: (String value) { + eLog('father Tag: $value'); + }, + ); + } + + TextFiledFixedHint _buildFatherTagNumber() { + return TextFiledFixedHint( + controller: controller.fatherTagNumberController, + inputType: InputType.number, + hintText: 'پلاک پدر ', + onChanged: (String value) {}, + ); + } + + TextFiledFixedHint _buildMotherTagNumber() { + return TextFiledFixedHint( + controller: controller.motherTagNumberController, + inputType: InputType.number, + hintText: 'پلاک مادر ', + onChanged: (value) {}, + ); + } + + OverlayDropdownWidget _buildLivestockBreed() { + return OverlayDropdownWidget( + items: ['نوع نژاد 1', 'نوع نژاد 2', 'نوع نژاد 3'], + onChanged: (value) { + controller.breed.value = value; + eLog('Selected Breed: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'نژاد'), + ); + } + + ObxValue _buildLivestockGender() { + return ObxValue( + (data) => CupertinoSlidingSegmentedControl( + children: { + 0: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text( + 'نر', + style: AppFonts.yekan14.copyWith( + color: data.value == 0 ? AppColor.whiteGreyLight : AppColor.darkGreyNormalActive, + ), + ), + ), + 1: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Text( + 'ماده', + style: AppFonts.yekan14.copyWith( + color: data.value == 1 ? AppColor.whiteGreyLight : AppColor.darkGreyNormalActive, + ), + ), + ), + }, + onValueChanged: (int? value) { + if (value != null) { + controller.selectedSegment.value = value; + } + }, + + proportionalWidth: true, + groupValue: data.value, + thumbColor: AppColor.blueNormal, + backgroundColor: CupertinoColors.systemGrey6, + ), + controller.selectedSegment, + ); + } + + Widget _buildLivestockBirthday() { + return GestureDetector( + onTap: () { + Get.bottomSheet( + modalDatePicker((value) { + controller.dateOfBirth.value = value; + }), + isScrollControlled: true, + isDismissible: true, + ignoreSafeArea: false, + ); + }, + child: Container( + height: 40, + width: Get.width, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + border: Border.all(color: AppColor.darkGreyLight), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'تاریخ تولد', + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive), + ), + Text( + '1404/5/5', + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive), + ), + ], + ), + ), + ); + } + + OverlayDropdownWidget _buildLiveStockSpecies() { + return OverlayDropdownWidget( + items: ['گوسفند ماده', 'گوسفند نر', 'بز ماده', 'بز نر', 'گوساله ماده', 'گوساله نر'], + onChanged: (value) { + controller.species.value = value; + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'گونه دام'), + ); + } + + ObxValue _buildFilterWidget() { + return ObxValue((data) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: EdgeInsets.only(top: 5), + curve: Curves.easeInOut, + height: data.value ? 50 : 0, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 12), + child: ObxValue((data) { + return Row( + spacing: 12, + children: [ + CustomChip( + title: 'انتخاب فیلتر', + index: 0, + isSelected: true, + selectedColor: AppColor.blueNormal, + onTap: (index) {}, + ), + + RFilterChips( + title: 'درخواست‌های من', + index: 1, + isSelected: data.contains(1), + selectedColor: AppColor.yellowNormal, + onTap: (index) { + if (data.contains(1)) { + data.remove(1); + } else { + data.add(1); + } + }, + ), + + RFilterChips( + title: 'در انتظار ثبت ', + index: 2, + selectedColor: AppColor.greenLightActive, + isSelected: data.contains(2), + onTap: (index) { + if (data.contains(2)) { + data.remove(2); + } else { + data.add(2); + } + }, + ), + + RFilterChips( + title: 'ارجاع به تعاونی', + index: 3, + selectedColor: AppColor.blueLightHover, + isSelected: data.contains(3), + onTap: (index) { + if (data.contains(3)) { + data.remove(3); + } else { + data.add(3); + } + }, + ), + ], + ); + }, controller.filterSelected), + ), + ); + }, controller.filterIsSelected); + } + + ObxValue _buildSearchWidget() { + return ObxValue((data) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: EdgeInsets.only(top: 5), + curve: Curves.easeInOut, + height: data.value ? 50 : 0, + child: Visibility( + visible: data.value, + child: Padding( + padding: const EdgeInsets.only(right: 8.0, left: 20.0), + child: RTextField( + suffixIcon: Padding( + padding: const EdgeInsets.all(12.0), + child: Assets.vec.searchSvg.svg( + width: 10, + height: 10, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + hintText: 'جستجو', + onChanged: (value) { + //controller.search(value); + }, + controller: TextEditingController(), + ), + ), + ), + ); + }, controller.searchIsSelected); + } + + Row itemListWidget(int index) { + return Row( + children: [ + SizedBox(width: 30), + Text('123456789012346', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal)), + Spacer(), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('گوسفند ماده', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal)), + SizedBox(height: 4), + Text('نوع نژاد', style: AppFonts.yekan14.copyWith(color: AppColor.bgDark)), + ], + ), + Spacer(), + Text('18 ماه', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)), + Spacer(), + Assets.vec.scanSvg.svg( + width: 32.w, + height: 32.h, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + SizedBox(width: 12), + ], + ); + } + + Container itemListExpandedWidget(int index) { + return Container( + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)), + child: Column( + spacing: 8, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + 'fullname' ?? 'N/A', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith(color: AppColor.greenDark), + ), + Spacer(), + Text( + 'در انتظار', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith(color: AppColor.darkGreyDark), + ), + SizedBox(width: 7), + Assets.vec.clockSvg.svg(width: 16.w, height: 16.h), + ], + ), + Container( + height: 32, + padding: EdgeInsets.symmetric(horizontal: 8), + decoration: ShapeDecoration( + color: AppColor.blueLight, + shape: RoundedRectangleBorder( + side: BorderSide(width: 1, color: AppColor.blueLightHover), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + spacing: 3, + children: [ + Text( + Jalali.now().formatter.wN ?? 'N/A', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + + Text( + '${Jalali.now().formatter.d} ${Jalali.now().formatter.mN ?? 'N/A'}', + style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), + ), + ], + ), + + Text( + '${Jalali.now().formatter.y}', + style: AppFonts.yekan20.copyWith(color: AppColor.textColor), + ), + + Text( + '${Jalali.now().formatter.tHH}:${Jalali.now().formatter.tMM ?? 'N/A'}', + style: AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + ], + ), + ), + + buildRow(title: 'مشخصات دام', value: 'مشخصات دام'), + + buildRow(title: 'نژاد', value: 'نژاد'), + buildRow(title: 'وزن خریداری شده', value: ' 10 کیلوگرم'), + buildRow(title: 'قیمت کل', value: '10000'), + Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 16.w, + children: [ + ObxValue((data) { + return RElevated( + text: 'تایید', + width: 150.w, + height: 40.h, + isLoading: data.value, + onPressed: () async {}, + textStyle: AppFonts.yekan20.copyWith(color: Colors.white), + backgroundColor: AppColor.greenNormal, + ); + }, controller.tst1), + ROutlinedElevated( + text: 'رد', + textStyle: AppFonts.yekan20.copyWith(color: AppColor.redNormal), + width: 150.w, + height: 40.h, + onPressed: () { + buildWarningDialog( + title: 'اخطار', + middleText: 'آیا از رد شدن این مورد اطمینان دارید؟', + onConfirm: () async {}, + onRefresh: () async {}, + ); + }, + borderColor: AppColor.redNormal, + ), + ], + ), + ], + ), + ); + } + + //endregion } diff --git a/packages/livestock/lib/presentation/page/requests/view.dart b/packages/livestock/lib/presentation/page/requests/view.dart index 2b73f22..7783a47 100644 --- a/packages/livestock/lib/presentation/page/requests/view.dart +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -38,7 +38,7 @@ class RequestsPage extends GetView { shrinkWrap: true, itemCount: 10, physics: BouncingScrollPhysics(), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 50), + padding: EdgeInsets.fromLTRB(20, 10, 20, 30), separatorBuilder: (context, index) => SizedBox(height: 6), itemBuilder: (context, index) { return GestureDetector( diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 0aed723..7d0443e 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_livestock/presentation/page/map/view.dart'; @@ -7,10 +9,21 @@ import 'package:rasadyar_livestock/presentation/page/requests/view.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class RootLogic extends GetxController { - List pages = [ + // Unique nested keys for each Navigator + final List> navigatorKeys = [ + ?Get.nestedKey(0), // Map + ?Get.nestedKey(1), // Requests / RequestTagging + ?Get.nestedKey(2), // Profile + ]; + + List get pages => [ Navigator( - key: Get.nestedKey(0), - initialRoute: LiveStockRoutes.requests, + key: navigatorKeys[0], + onGenerateRoute: (settings) => GetPageRoute(page: () => MapPage()), + ), + + Navigator( + key: navigatorKeys[1], onGenerateRoute: (settings) { switch (settings.name) { case LiveStockRoutes.requests: @@ -22,22 +35,38 @@ class RootLogic extends GetxController { } }, ), - MapPage(), - ProfilePage(), + + Navigator( + key: navigatorKeys[2], + onGenerateRoute: (settings) => GetPageRoute(page: () => ProfilePage()), + ), ]; - RxInt currentIndex = 1.obs; + + RxInt currentIndex = 0.obs; + TokenStorageService tokenService = Get.find(); + + @override + void onInit() { + super.onInit(); + } + @override void onReady() { - // TODO: implement onReady super.onReady(); } @override void onClose() { - // TODO: implement onClose super.onClose(); } - void changePage(int i) => currentIndex.value = i; + void changePage(int index) { + if (index == currentIndex.value) { + // Optional: pop to first route if the same tab is tapped + navigatorKeys[index].currentState?.popUntil((route) => route.isFirst); + } else { + currentIndex.value = index; + } + } } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 1951ca1..50d0863 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -1,70 +1,81 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:rasadyar_core/core.dart'; import 'logic.dart'; class RootPage extends GetView { - const RootPage({super.key}); + RootPage({super.key}); + + // Extracted back-press + Future _handleBackPress(BuildContext context) async { + final nestedKey = Get.nestedKey(controller.currentIndex.value); + final currentNavigator = nestedKey?.currentState; + if (currentNavigator?.canPop() ?? false) { + currentNavigator?.pop(); + return; + } + final now = DateTime.now(); + /*if (controller.lastBackPressed == null || + now.difference(controller.lastBackPressed!) > const Duration(seconds: 2)) { + controller.lastBackPressed = now; + Get.snackbar( + 'خروج از برنامه', + 'برای خروج دوباره بازگشت را بزنید', + snackPosition: SnackPosition.TOP, + duration: const Duration(seconds: 2), + backgroundColor: AppColor.warning, + ); + } else { + await SystemNavigator.pop(); + }*/ + } @override Widget build(BuildContext context) { return ObxValue((currentIndex) { - return PopScope( canPop: false, - onPopInvokedWithResult: (didPop, result) { - final navigatorKey = Get.nestedKey(currentIndex); - eLog('Pop invoked with result: $result, didPop: $didPop'); - navigatorKey?.currentState?.pop(); - - /*eLog('Pop invoked with result: $result, didPop: $didPop'); - iLog(Get.currentRoute); - iLog(Get.previousRoute); - - final navigatorKey = Get.nestedKey(currentIndex); - - if (currentIndex.value == 0 && - navigatorKey != null && - navigatorKey.currentState != null) { - if (navigatorKey.currentState!.canPop()) { - navigatorKey.currentState!.pop(); - return; - } - - if (!didPop) { - return; - } - }*/ + onPopInvokedWithResult: (didPop, result) async { + await _handleBackPress(context); }, - child: Scaffold( body: IndexedStack( - children: [...controller.pages], + children: controller.pages, index: currentIndex.value, sizing: StackFit.expand, ), - extendBody: true, bottomNavigationBar: RBottomNavigation( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, items: [ RBottomNavigationItem( - icon: Assets.vec.filterSvg.path, - label: 'درخواست‌ها', - isSelected: currentIndex.value == 0, - onTap: () => controller.changePage(0), - ), - - RBottomNavigationItem( - icon: Assets.vec.mapSvg.path, label: 'نقشه', - isSelected: currentIndex.value == 1, - onTap: () => controller.changePage(1), + icon: Assets.vec.mapSvg.path, + isSelected: currentIndex.value == 0, + onTap: () { + Get.nestedKey(1)?.currentState?.popUntil((route) => route.isFirst); + controller.changePage(0); + }, + ), + RBottomNavigationItem( + label: 'درخواست‌ها', + icon: Assets.vec.settingSvg.path, + isSelected: currentIndex.value == 1, + onTap: () { + Get.nestedKey(0)?.currentState?.popUntil((route) => route.isFirst); + controller.changePage(1); + }, ), - RBottomNavigationItem( - icon: Assets.vec.profileUserSvg.path, label: 'پروفایل', + icon: Assets.vec.profileCircleSvg.path, isSelected: currentIndex.value == 2, - onTap: () => controller.changePage(2), + onTap: () { + Get.nestedKey(1)?.currentState?.popUntil((route) => route.isFirst); + Get.nestedKey(0)?.currentState?.popUntil((route) => route.isFirst); + + controller.changePage(2); + }, ), ], ), diff --git a/packages/livestock/lib/presentation/page/tagging/logic.dart b/packages/livestock/lib/presentation/page/tagging/logic.dart index 30e8316..8c26f85 100644 --- a/packages/livestock/lib/presentation/page/tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/tagging/logic.dart @@ -15,6 +15,7 @@ class TaggingLogic extends GetxController { @override void onClose() { // TODO: implement onClose + super.onClose(); } } diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index d7840fd..7aa11b5 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,6 +1,8 @@ import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/presentation/widget/map/logic.dart'; +import 'package:rasadyar_livestock/presentation/page/auth/logic.dart'; +import 'package:rasadyar_livestock/presentation/page/auth/view.dart'; import 'package:rasadyar_livestock/presentation/page/map/logic.dart'; +import 'package:rasadyar_livestock/presentation/page/map/widget/map_widget/logic.dart'; import 'package:rasadyar_livestock/presentation/page/profile/logic.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/logic.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; @@ -9,6 +11,10 @@ import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; import 'package:rasadyar_livestock/presentation/page/root/view.dart'; import 'package:rasadyar_livestock/presentation/page/tagging/logic.dart'; import 'package:rasadyar_livestock/presentation/page/tagging/view.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; +import 'package:rasadyar_livestock/presentation/widgets/captcha/logic.dart'; + +import '../../injection/live_stock_di.dart'; part 'app_routes.dart'; @@ -16,6 +22,14 @@ sealed class LiveStockPages { LiveStockPages._(); static final pages = [ + GetPage( + name: LiveStockRoutes.auth, + page: () => AuthPage(), + binding: BindingsBuilder(() { + Get.lazyPut(() => AuthLogic()); + Get.lazyPut(() => CaptchaWidgetLogic()); + }), + ), GetPage( name: LiveStockRoutes.init, page: () => RootPage(), @@ -25,9 +39,8 @@ sealed class LiveStockPages { Get.lazyPut(() => RequestsLogic()); Get.lazyPut(() => MapLogic()); Get.lazyPut(() => ProfileLogic()); - Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); - Get.lazyPut(() => DraggableBottomSheetController()); + Get.lazyPut(() => BaseLogic()); }), children: [ /*GetPage( @@ -40,7 +53,6 @@ sealed class LiveStockPages { ),*/ ], ), - GetPage( name: LiveStockRoutes.requestTagging, page: () => RequestTaggingPage(), diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index 58e206f..823279b 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -6,9 +6,8 @@ sealed class LiveStockRoutes { static const auth = '/AuthLiveStock'; static const init = '/liveStock'; static const requests = '/requests'; + static const map = '/map'; static const profile = '/profile'; - - //static const requestTagging = '$init/tagging'; static const requestTagging = '$requests/tagging'; static const tagging = '/tagging'; } diff --git a/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart b/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart new file mode 100644 index 0000000..0960fe8 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; + +RAppBar2 liveStockAppBar({ + bool hasBack = true, + bool hasFilter = true, + bool hasSearch = true, + bool isBase = false, + VoidCallback? onBackPressed, + GestureTapCallback? onFilterTap, + GestureTapCallback? onSearchTap, + String? title, +}) { + return RAppBar2( + hasBack: isBase == true ? false : hasBack, + onBackPressed: onBackPressed, + leadingWidth: 180.w, + leading: Row( + mainAxisSize: MainAxisSize.min, + spacing: 6, + children: [ + Text(title ?? 'رصددام', style: AppFonts.yekan16Bold.copyWith(color: Colors.white)), + Assets.vec.appBarInspectionSvg.svg(width: 24, height: 24), + ], + ), + additionalActions: [ + if (!isBase && hasSearch) searchWidget(onSearchTap), + SizedBox(width: 8), + if (!isBase && hasFilter) filterWidget(onFilterTap), + SizedBox(width: 8), + ], + ); +} + +GestureDetector filterWidget(GestureTapCallback? onFilterTap) { + return GestureDetector( + onTap: onFilterTap, + child: Stack( + alignment: Alignment.topRight, + children: [ + Assets.vec.filterOutlineSvg.svg( + width: 20, + height: 20, + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + Obx(() { + final controller = Get.find(); + return Visibility( + visible: controller.isFilterSelected.value, + child: Container( + width: 8, + height: 8, + decoration: const BoxDecoration(color: Colors.red, shape: BoxShape.circle), + ), + ); + }), + ], + ), + ); +} + +GestureDetector searchWidget(GestureTapCallback? onSearchTap) { + return GestureDetector( + onTap: onSearchTap, + child: Stack( + alignment: Alignment.topRight, + children: [ + Assets.vec.searchSvg.svg( + width: 24, + height: 24, + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + Obx(() { + final controller = Get.find(); + return Visibility( + visible: controller.searchValue.value != null, + child: Container( + width: 8, + height: 8, + decoration: const BoxDecoration(color: Colors.red, shape: BoxShape.circle), + ), + ); + }), + ], + ), + ); +} diff --git a/packages/livestock/lib/presentation/widgets/base_page/logic.dart b/packages/livestock/lib/presentation/widgets/base_page/logic.dart new file mode 100644 index 0000000..79ac095 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/base_page/logic.dart @@ -0,0 +1,25 @@ +import 'package:flutter/cupertino.dart'; +import 'package:rasadyar_core/core.dart'; + +class BaseLogic extends GetxController { + final RxBool isFilterSelected = false.obs; + final RxBool isSearchSelected = false.obs; + final TextEditingController searchTextController = TextEditingController(); + final RxnString searchValue = RxnString(); + + void setSearchCallback(void Function(String)? onSearchChanged) { + debounce(searchValue, (val) { + if (val != null && val.trim().isNotEmpty) { + onSearchChanged?.call(val); + } + }, time: const Duration(milliseconds: 600)); + } + + void toggleFilter() { + isFilterSelected.value = !isFilterSelected.value; + } + + void toggleSearch() { + isSearchSelected.value = !isSearchSelected.value; + } +} diff --git a/packages/livestock/lib/presentation/widgets/base_page/view.dart b/packages/livestock/lib/presentation/widgets/base_page/view.dart new file mode 100644 index 0000000..e9e42dd --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/base_page/view.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/widgets/app_bar/i_app_bar.dart'; +import 'package:rasadyar_livestock/presentation/widgets/search.dart'; + +import 'logic.dart'; + +class BasePage extends StatefulWidget { + const BasePage({ + super.key, + this.routes, + required this.widgets, + this.routesWidget, + this.floatingActionButtonLocation, + this.floatingActionButton, + this.onSearchChanged, + this.hasBack = true, + this.hasFilter = true, + this.hasSearch = true, + this.isBase = false, + this.defaultSearch = true, + this.onBackPressed, + this.onFilterTap, + this.onSearchTap, + this.filteringWidget, + this.title, + this.padding, + this.avoidBottomInset = true, + }); + + final List? routes; + final Widget? routesWidget; + final bool defaultSearch; + final List widgets; + final FloatingActionButtonLocation? floatingActionButtonLocation; + final Widget? floatingActionButton; + final Widget? filteringWidget; + final void Function(String?)? onSearchChanged; + final bool hasBack; + final bool hasFilter; + final bool hasSearch; + final bool isBase; + final bool avoidBottomInset; + + final VoidCallback? onBackPressed; + final GestureTapCallback? onFilterTap; + final GestureTapCallback? onSearchTap; + final String? title; + final EdgeInsets? padding; + + @override + State createState() => _BasePageState(); +} + +class _BasePageState extends State { + BaseLogic get controller => Get.find(); + Worker? filterWorker; + bool _isBottomSheetOpen = false; + + @override + void initState() { + super.initState(); + /* filterWorker = ever(controller.isFilterSelected, (bool isSelected) { + if (!mounted) return; + + if (isSelected && widget.filteringWidget != null) { + // بررسی اینکه آیا bottomSheet از قبل باز است یا نه + if (_isBottomSheetOpen) { + controller.isFilterSelected.value = false; + return; + } + + // بررسی اینکه آیا route فعلی current است یا نه + if (ModalRoute.of(context)?.isCurrent != true) { + controller.isFilterSelected.value = false; + return; + } + + _isBottomSheetOpen = true; + Get.bottomSheet( + widget.filteringWidget!, + isScrollControlled: true, + isDismissible: true, + enableDrag: true, + ).then((_) { + // تنظیم مقدار به false بعد از بسته شدن bottomSheet + if (mounted) { + _isBottomSheetOpen = false; + controller.isFilterSelected.value = false; + } + }); + } + });*/ + } + + @override + void dispose() { + filterWorker?.dispose(); + super.dispose(); + } + + void _onFilterTap() { + if (widget.hasFilter && widget.filteringWidget != null) { + final currentRoute = ModalRoute.of(context); + if (currentRoute?.isCurrent != true) { + return; + } + + Get.bottomSheet( + widget.filteringWidget!, + isScrollControlled: true, + isDismissible: true, + enableDrag: true, + ); + } + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) => widget.onBackPressed, + child: Scaffold( + backgroundColor: AppColor.bgLight, + resizeToAvoidBottomInset: widget.avoidBottomInset, + appBar: liveStockAppBar( + title: widget.title, + hasBack: widget.isBase ? false : widget.hasBack, + onBackPressed: widget.onBackPressed, + hasFilter: widget.hasFilter, + hasSearch: widget.hasSearch, + isBase: widget.isBase, + onFilterTap: widget.hasFilter ? _onFilterTap : null, + onSearchTap: widget.hasSearch ? () => controller.toggleSearch() : null, + ), + body: Padding( + padding: widget.padding ?? const EdgeInsets.all(0.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + //widget.routesWidget != null ? widget.routesWidget! : buildPageRoute(widget.routes!), + if (!widget.isBase && widget.hasSearch && widget.defaultSearch) ...{ + SearchWidget(onSearchChanged: widget.onSearchChanged), + }, + ...widget.widgets, + ], + ), + ), + floatingActionButtonLocation: + widget.floatingActionButtonLocation ?? FloatingActionButtonLocation.startFloat, + floatingActionButton: widget.floatingActionButton, + ), + ); + } +} diff --git a/packages/livestock/lib/presentation/widgets/captcha/logic.dart b/packages/livestock/lib/presentation/widgets/captcha/logic.dart new file mode 100644 index 0000000..b35df6d --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/captcha/logic.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/response/captcha/captcha_response_model.dart'; +import 'package:rasadyar_livestock/data/repository/auth/auth_repository.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; + +class CaptchaWidgetLogic extends GetxController with StateMixin { + TextEditingController textController = TextEditingController(); + RxnString captchaKey = RxnString(); + GlobalKey formKey = GlobalKey(); + AuthRepository authRepository = diLiveStock.get(); + + @override + void onInit() { + super.onInit(); + + getCaptcha(); + } + + @override + void onClose() { + textController.clear(); + textController.dispose(); + super.onClose(); + } + + Future getCaptcha() async { + change(null, status: RxStatus.loading()); + textController.clear(); + formKey.currentState?.reset(); + await Future.delayed(Duration(milliseconds: 200)); + await safeCall( + call: () async => authRepository.captcha(), + onSuccess: (result) { + if (result == null) { + change(null, status: RxStatus.error('Failed to load captcha')); + return; + } + captchaKey.value = result.captchaKey; + change(result, status: RxStatus.success()); + }, + onError: (error, stackTrace) {}, + ); + + change(value, status: RxStatus.success()); + } +} diff --git a/packages/livestock/lib/presentation/widgets/captcha/view.dart b/packages/livestock/lib/presentation/widgets/captcha/view.dart new file mode 100644 index 0000000..fbc98f1 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/captcha/view.dart @@ -0,0 +1,105 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/auth/logic.dart'; + +import 'logic.dart'; + +class CaptchaWidget extends GetView { + const CaptchaWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: controller.getCaptcha, + child: Container( + width: 135, + height: 50, + clipBehavior: Clip.antiAliasWithSaveLayer, + decoration: BoxDecoration( + color: AppColor.whiteNormalHover, + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(8), + ), + child: controller.obx( + (state) => Image.memory(base64Decode(state?.captchaImage ?? ''), fit: BoxFit.cover), + onLoading: const Center( + child: CupertinoActivityIndicator(color: AppColor.blueNormal), + ), + onError: (error) { + return Center( + child: Text('خطا ', style: AppFonts.yekan13.copyWith(color: Colors.red)), + ); + }, + ), + ), + ), + + const SizedBox(width: 8), + Expanded( + child: Form( + key: controller.formKey, + autovalidateMode: AutovalidateMode.disabled, + child: RTextField( + label: 'کد امنیتی', + controller: controller.textController, + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide(color: AppColor.textColor, width: 1), + ), + keyboardType: TextInputType.numberWithOptions(decimal: false, signed: false), + maxLines: 1, + maxLength: 6, + suffixIcon: (controller.textController.text.trim().isNotEmpty ?? false) + ? clearButton(() => controller.textController.clear()) + : null, + + validator: (value) { + if (value == null || value.isEmpty) { + return 'کد امنیتی را وارد کنید'; + } + return null; + }, + onChanged: (pass) { + if (pass.length == 6) { + if (controller.formKey.currentState?.validate() ?? false) { + Get.find().isDisabled.value = false; + } + } + }, + style: AppFonts.yekan13, + ), + ), + ), + ], + ); + } +} + +class _CaptchaLinePainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final random = Random(); + final paint1 = Paint() + ..color = Colors.deepOrange + ..strokeWidth = 2; + final paint2 = Paint() + ..color = Colors.blue + ..strokeWidth = 2; + + // First line: top-left to bottom-right + canvas.drawLine(Offset(0, 0), Offset(size.width, size.height), paint1); + + // Second line: bottom-left to top-right + canvas.drawLine(Offset(0, size.height), Offset(size.width, 0), paint2); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} diff --git a/packages/livestock/lib/presentation/widgets/search.dart b/packages/livestock/lib/presentation/widgets/search.dart new file mode 100644 index 0000000..753e624 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/search.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'base_page/logic.dart'; + + +class SearchWidget extends StatefulWidget { + const SearchWidget({super.key, this.onSearchChanged}); + + final void Function(String?)? onSearchChanged; + + @override + State createState() => _SearchWidgetState(); +} + +class _SearchWidgetState extends State { + late final BaseLogic controller; + final TextEditingController textEditingController = TextEditingController(); + + @override + void initState() { + super.initState(); + controller = Get.find(); + controller.setSearchCallback(widget.onSearchChanged); + } + + @override + Widget build(BuildContext context) { + return ObxValue((data) { + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + height: data.value ? 40 : 0, + child: Visibility( + visible: data.value, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: RTextField( + height: 40, + borderColor: AppColor.blackLight, + suffixIcon: ObxValue( + (data) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: (data.value == null) + ? Assets.vec.searchSvg.svg( + width: 10, + height: 10, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ) + : IconButton( + onPressed: () { + textEditingController.clear(); + controller.searchValue.value = null; + controller.isSearchSelected.value = false; + widget.onSearchChanged?.call(null); + }, + enableFeedback: true, + padding: EdgeInsets.zero, + iconSize: 24, + splashRadius: 50, + icon: Assets.vec.closeCircleSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + ), + controller.searchValue, + ), + hintText: 'جستجو کنید ...', + hintStyle: AppFonts.yekan16.copyWith(color: AppColor.blueNormal), + filledColor: Colors.white, + filled: true, + controller: textEditingController, + onChanged: (val) => controller.searchValue.value = val, + ), + ), + ), + ); + }, controller.isSearchSelected); + } +} diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml index a15d59a..0bb2b2f 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -1,11 +1,11 @@ name: rasadyar_livestock description: A starting point for Dart libraries or applications. -version: 1.0.0 +version: 2.0.0 publish_to: 'none' # repository: https://github.com/my_org/my_repo environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: @@ -24,10 +24,10 @@ dev_dependencies: lints: ^6.0.0 test: ^1.25.15 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 - json_serializable: ^6.10.0 + json_serializable: ^6.11.0 ##test mocktail: ^1.0.4 diff --git a/pubspec.lock b/pubspec.lock index b93bb67..3f3cccd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: android_intent_plus - sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" url: "https://pub.dev" source: hosted - version: "5.3.0" + version: "5.3.1" animated_stack_widget: dependency: transitive description: @@ -77,18 +77,18 @@ packages: dependency: transitive description: name: build - sha256: "7d95cbbb1526ab5ae977df9b4cc660963b9b27f6d1075c0b34653868911385e4" + sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: @@ -101,26 +101,26 @@ packages: dependency: transitive description: name: build_resolvers - sha256: "38c9c339333a09b090a638849a4c56e70a404c6bdd3b511493addfbc113b60c2" + sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b971d4a1c789eba7be3e6fe6ce5e5b50fd3719e3cb485b3fad6d04358304351d + sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c04e612ca801cd0928ccdb891c263a2b1391cb27940a5ea5afcf9ba894de5d62 + sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 url: "https://pub.dev" source: hosted - version: "9.2.0" + version: "9.3.0" built_collection: dependency: transitive description: @@ -137,6 +137,30 @@ packages: url: "https://pub.dev" source: hosted version: "8.11.0" + cached_network_image: + dependency: transitive + description: + name: cached_network_image + sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" + url: "https://pub.dev" + source: hosted + version: "3.4.1" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" + url: "https://pub.dev" + source: hosted + version: "1.3.1" change_app_package_name: dependency: "direct dev" description: @@ -201,6 +225,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec + url: "https://pub.dev" + source: hosted + version: "6.1.5" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204" + url: "https://pub.dev" + source: hosted + version: "2.0.1" convert: dependency: transitive description: @@ -285,10 +325,10 @@ packages: dependency: transitive description: name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9 url: "https://pub.dev" source: hosted - version: "5.8.0+1" + version: "5.9.0" dio_web_adapter: dependency: transitive description: @@ -369,11 +409,27 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flat_buffers: + dependency: transitive + description: + name: flat_buffers + sha256: "380bdcba5664a718bfd4ea20a45d39e13684f5318fcd8883066a55e21f37f4c3" + url: "https://pub.dev" + source: hosted + version: "23.5.26" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_gen_core: dependency: transitive description: @@ -443,6 +499,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + flutter_map_tile_caching: + dependency: transitive + description: + name: flutter_map_tile_caching + sha256: "1839c6157cf9b444083a626b30f3ba9f6db802ac8bb5292440e1628882faa392" + url: "https://pub.dev" + source: hosted + version: "10.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -519,10 +583,10 @@ packages: dependency: transitive description: name: flutter_slidable - sha256: ab7dbb16f783307c9d7762ede2593ce32c220ba2ba0fd540a3db8e9a3acba71a + sha256: e6bd17290cf0d011f9ed66c74d4159b8fe3b3050afedac0f11fab1ba8687e710 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" flutter_svg: dependency: transitive description: @@ -541,14 +605,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: transitive - description: - name: font_awesome_flutter - sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a - url: "https://pub.dev" - source: hosted - version: "10.8.0" freezed: dependency: "direct dev" description: @@ -649,10 +705,10 @@ packages: dependency: transitive description: name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 + sha256: a4292e7cf67193f8e7c1258203104eb2a51ec8b3a04baa14695f4064c144297b url: "https://pub.dev" source: hosted - version: "8.0.3" + version: "8.2.0" get_test: dependency: "direct dev" description: @@ -749,70 +805,94 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + image_cropper: + dependency: transitive + description: + name: image_cropper + sha256: "4e9c96c029eb5a23798da1b6af39787f964da6ffc78fd8447c140542a9f7c6fc" + url: "https://pub.dev" + source: hosted + version: "9.1.0" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + sha256: fd81ebe36f636576094377aab32673c4e5d1609b32dec16fad98d2b71f1250a9 + url: "https://pub.dev" + source: hosted + version: "6.1.0" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + sha256: "6ca6b81769abff9a4dcc3bbd3d75f5dfa9de6b870ae9613c8cd237333a4283af" + url: "https://pub.dev" + source: hosted + version: "7.1.0" image_picker: dependency: transitive description: name: image_picker - sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "6fae381e6af2bbe0365a5e4ce1db3959462fa0c4d234facf070746024bb80c8d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.12+24" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.12+2" + version: "0.8.13" image_picker_linux: dependency: transitive description: name: image_picker_linux - sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_macos: dependency: transitive description: name: image_picker_macos - sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.1+2" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.10.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae url: "https://pub.dev" source: hosted - version: "0.2.1+1" + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -865,10 +945,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: ce2cf974ccdee13be2a510832d7fba0b94b364e0b0395dee42abaa51b855be27 + sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd" url: "https://pub.dev" source: hosted - version: "6.10.0" + version: "6.11.0" latlong2: dependency: transitive description: @@ -881,26 +961,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.1" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -1005,6 +1085,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + objectbox: + dependency: transitive + description: + name: objectbox + sha256: "25c2e24b417d938decb5598682dc831bc6a21856eaae65affbc57cfad326808d" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + objectbox_flutter_libs: + dependency: transitive + description: + name: objectbox_flutter_libs + sha256: "574b0233ba79a7159fca9049c67974f790a2180b6141d4951112b20bd146016a" + url: "https://pub.dev" + source: hosted + version: "4.3.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" package_config: dependency: transitive description: @@ -1017,18 +1129,18 @@ packages: dependency: transitive description: name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "8.3.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" path: dependency: transitive description: @@ -1145,10 +1257,10 @@ packages: dependency: transitive description: name: persian_datetime_picker - sha256: "7ccbfd3a68dc89d405550f624e9fa590c914fed2aa2d48973c4f4400baab2e06" + sha256: "0ec2879d2bee8390dda088b412739e6316e3a54d77640ec54dc1eeca8c5baa59" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" petitparser: dependency: transitive description: @@ -1272,7 +1384,7 @@ packages: path: "packages/livestock" relative: true source: path - version: "1.0.0" + version: "2.0.0" rxdart: dependency: transitive description: @@ -1318,14 +1430,22 @@ packages: description: flutter source: sdk version: "0.0.0" + smooth_page_indicator: + dependency: transitive + description: + name: smooth_page_indicator + sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c + url: "https://pub.dev" + source: hosted + version: "1.2.1" source_gen: dependency: transitive description: name: source_gen - sha256: fc787b1f89ceac9580c3616f899c9a447413cbdac1df071302127764c023a134 + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.0" source_helper: dependency: transitive description: @@ -1350,6 +1470,46 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 + url: "https://pub.dev" + source: hosted + version: "2.4.2+2" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: @@ -1382,6 +1542,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 + url: "https://pub.dev" + source: hosted + version: "3.4.0" term_glyph: dependency: transitive description: @@ -1394,10 +1562,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" time: dependency: transitive description: @@ -1466,10 +1634,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -1567,5 +1735,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=3.8.1 <4.0.0" + dart: ">=3.9.0 <4.0.0" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5472dd0..badb658 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: 'none' version: 1.3.6+4 environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: flutter: @@ -36,10 +36,10 @@ dev_dependencies: sdk: flutter flutter_lints: ^6.0.0 ##code generation - build_runner: ^2.6.0 + build_runner: ^2.7.0 hive_ce_generator: ^1.9.3 freezed: ^3.2.0 - json_serializable: ^6.10.0 + json_serializable: ^6.11.0 flutter_gen_runner: ^5.11.0 change_app_package_name: ^1.5.0