From 223ccbd8079b00b5fafe11c93213479c0de76066 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 3 Aug 2025 11:55:57 +0330 Subject: [PATCH 01/39] feat : auth live stock --- .../service/app_navigation_observer.dart | 8 +- lib/presentation/pages/modules/logic.dart | 2 +- .../data/common/dio_exception_handeler.dart | 58 + .../data_source/remote/auth/auth_remote.dart | 16 + .../remote/auth/auth_remote_imp.dart | 71 + .../login_request/login_request_model.dart | 34 + .../login_request_model.freezed.dart | 286 ++++ .../login_request/login_request_model.g.dart | 23 + .../response/auth/auth_response_model.dart | 20 + .../auth/auth_response_model.freezed.dart | 283 ++++ .../response/auth/auth_response_model.g.dart | 21 + .../captcha/captcha_response_model.dart | 17 + .../captcha_response_model.freezed.dart | 286 ++++ .../captcha/captcha_response_model.g.dart | 25 + .../user_profile/user_profile_model.dart | 73 + .../user_profile_model.freezed.dart | 1479 +++++++++++++++++ .../user_profile/user_profile_model.g.dart | 104 ++ .../data/repository/auth/auth_repository.dart | 14 + .../repository/auth/auth_repository_imp.dart | 37 + .../lib/injection/live_stock_di.dart | 59 + .../lib/presentation/page/auth/logic.dart | 188 +++ .../lib/presentation/page/auth/view.dart | 541 ++++++ .../lib/presentation/page/root/logic.dart | 3 +- .../lib/presentation/page/root/view.dart | 36 +- .../lib/presentation/routes/app_pages.dart | 12 +- .../presentation/widgets/captcha/logic.dart | 47 + .../presentation/widgets/captcha/view.dart | 105 ++ packages/livestock/pubspec.yaml | 2 +- pubspec.lock | 2 +- 29 files changed, 3833 insertions(+), 19 deletions(-) create mode 100644 packages/livestock/lib/data/common/dio_exception_handeler.dart create mode 100644 packages/livestock/lib/data/data_source/remote/auth/auth_remote.dart create mode 100644 packages/livestock/lib/data/data_source/remote/auth/auth_remote_imp.dart create mode 100644 packages/livestock/lib/data/model/request/login_request/login_request_model.dart create mode 100644 packages/livestock/lib/data/model/request/login_request/login_request_model.freezed.dart create mode 100644 packages/livestock/lib/data/model/request/login_request/login_request_model.g.dart create mode 100644 packages/livestock/lib/data/model/response/auth/auth_response_model.dart create mode 100644 packages/livestock/lib/data/model/response/auth/auth_response_model.freezed.dart create mode 100644 packages/livestock/lib/data/model/response/auth/auth_response_model.g.dart create mode 100644 packages/livestock/lib/data/model/response/captcha/captcha_response_model.dart create mode 100644 packages/livestock/lib/data/model/response/captcha/captcha_response_model.freezed.dart create mode 100644 packages/livestock/lib/data/model/response/captcha/captcha_response_model.g.dart create mode 100644 packages/livestock/lib/data/model/response/user_profile/user_profile_model.dart create mode 100644 packages/livestock/lib/data/model/response/user_profile/user_profile_model.freezed.dart create mode 100644 packages/livestock/lib/data/model/response/user_profile/user_profile_model.g.dart create mode 100644 packages/livestock/lib/data/repository/auth/auth_repository.dart create mode 100644 packages/livestock/lib/data/repository/auth/auth_repository_imp.dart create mode 100644 packages/livestock/lib/injection/live_stock_di.dart create mode 100644 packages/livestock/lib/presentation/page/auth/logic.dart create mode 100644 packages/livestock/lib/presentation/page/auth/view.dart create mode 100644 packages/livestock/lib/presentation/widgets/captcha/logic.dart create mode 100644 packages/livestock/lib/presentation/widgets/captcha/view.dart diff --git a/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 6438add..44357cd 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; @@ -16,7 +18,7 @@ class CustomNavigationObserver extends NavigatorObserver { 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,6 +26,10 @@ class CustomNavigationObserver extends NavigatorObserver { _isWorkDone = true; await setupInspectionDI(); + } else if (!_isWorkDone && + (routeName == LiveStockRoutes.init || routeName == LiveStockRoutes.auth)) { + _isWorkDone = true; + await setupLiveStockDI(); } tLog('CustomNavigationObserver: didPush - $routeName'); } diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index e73eefe..d35b096 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -5,7 +5,7 @@ class ModulesLogic extends GetxController { 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.liveStocks), ModuleModel(title: 'مرغ', icon: Assets.icons.liveStock.path, module: Module.chicken), ]; 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..6f5e233 --- /dev/null +++ b/packages/livestock/lib/data/common/dio_exception_handeler.dart @@ -0,0 +1,58 @@ +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?.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/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..f67a63d --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/auth/auth_remote_imp.dart @@ -0,0 +1,71 @@ +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, + headers: {'Content-Type': 'application/json'}, + ); + 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/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/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/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..0b58774 --- /dev/null +++ b/packages/livestock/lib/data/repository/auth/auth_repository.dart @@ -0,0 +1,14 @@ +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..d3ffcba --- /dev/null +++ b/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart @@ -0,0 +1,37 @@ +import 'package:rasadyar_livestock/data/data_source/remote/auth/auth_remote.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(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/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart new file mode 100644 index 0000000..58f1585 --- /dev/null +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -0,0 +1,59 @@ +import 'package:rasadyar_core/core.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/repository/auth/auth_repository_imp.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; + +GetIt get diLiveStock => GetIt.instance; + +Future setupLiveStockDI() async { + diLiveStock.registerSingleton(DioErrorHandler()); + var tokenService = Get.find(); + if (tokenService.baseurl.value == null) { + await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); + } + diLiveStock.registerLazySingleton( + () => AppInterceptor( + refreshTokenCallback: () async { + var authRepository = diLiveStock.get(); + var hasAuthenticated = await authRepository.hasAuthenticated(); + if (hasAuthenticated) { + var 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 the DioRemote client + diLiveStock.registerLazySingleton( + () => DioRemote( + baseUrl: tokenService.baseurl.value, + interceptors: diLiveStock.get(), + ), + ); + var dioRemoteClient = diLiveStock.get(); + await dioRemoteClient.init(); + + // Register the AuthRemote data source implementation + diLiveStock.registerLazySingleton( + () => AuthRemoteDataSourceImp(diLiveStock.get()), + ); + + // Register the AuthRepository implementation + diLiveStock.registerLazySingleton( + () => AuthRepositoryImp(diLiveStock.get()), + ); +} 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..884edc3 --- /dev/null +++ b/packages/livestock/lib/presentation/page/auth/logic.dart @@ -0,0 +1,188 @@ +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_imp.dart'; +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; + + 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; + + AuthRepositoryImp 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 => authRepository.login(authRequest: loginRequestModel.toJson()), + onSuccess: (result) async { + await tokenStorageService.saveModule(_module); + await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); + await tokenStorageService.saveAccessToken(result?.access ?? ''); + 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..b2cda08 --- /dev/null +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -0,0 +1,541 @@ +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, + + 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), + ), + ], + ), + ), + ), + + 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(), + SizedBox(height: 23), + + 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/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 0aed723..4bb8c4c 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -8,6 +8,7 @@ import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class RootLogic extends GetxController { List pages = [ + MapPage(), Navigator( key: Get.nestedKey(0), initialRoute: LiveStockRoutes.requests, @@ -22,7 +23,7 @@ class RootLogic extends GetxController { } }, ), - MapPage(), + ProfilePage(), ]; RxInt currentIndex = 1.obs; diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 1951ca1..3544cef 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -9,7 +9,6 @@ class RootPage extends GetView { @override Widget build(BuildContext context) { return ObxValue((currentIndex) { - return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { @@ -43,28 +42,39 @@ class RootPage extends GetView { 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: 'نقشه', + 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: () => controller.changePage(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/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index d7840fd..4ada648 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,5 +1,7 @@ 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/profile/logic.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/logic.dart'; @@ -9,6 +11,7 @@ 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/captcha/logic.dart'; part 'app_routes.dart'; @@ -16,6 +19,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(), @@ -40,7 +51,6 @@ sealed class LiveStockPages { ),*/ ], ), - GetPage( name: LiveStockRoutes.requestTagging, page: () => RequestTaggingPage(), 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..fe8cfdc --- /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_imp.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(); + AuthRepositoryImp 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/pubspec.yaml b/packages/livestock/pubspec.yaml index a15d59a..5b61757 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -1,6 +1,6 @@ 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 diff --git a/pubspec.lock b/pubspec.lock index b93bb67..8351850 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1272,7 +1272,7 @@ packages: path: "packages/livestock" relative: true source: path - version: "1.0.0" + version: "2.0.0" rxdart: dependency: transitive description: From 7d3ab64705b1af0e5f236fdd858e1a2f2721f75f Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 3 Aug 2025 11:56:27 +0330 Subject: [PATCH 02/39] feat : container constraints --- .../widget/bottom_navigation/r_bottom_navigation.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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, From 693d8cbfabb09a1e9bebf5c4a706302b318d6208 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 3 Aug 2025 14:17:08 +0330 Subject: [PATCH 03/39] feat : Map Widget --- .../widget/map/custom_marker.dart | 10 - .../lib/presentation/widget/map/view.dart | 207 ------------------ .../lib/injection/live_stock_di.dart | 44 ++-- .../lib/presentation/page/auth/logic.dart | 4 +- .../lib/presentation/page/map/view.dart | 22 +- .../page/map/widget/map_widget}/logic.dart | 48 ++-- .../page/map/widget/map_widget/view.dart | 179 +++++++++++++++ .../lib/presentation/routes/app_pages.dart | 3 +- .../presentation/widgets/captcha/logic.dart | 4 +- 9 files changed, 232 insertions(+), 289 deletions(-) delete mode 100644 packages/core/lib/presentation/widget/map/custom_marker.dart delete mode 100644 packages/core/lib/presentation/widget/map/view.dart rename packages/{core/lib/presentation/widget/map => livestock/lib/presentation/page/map/widget/map_widget}/logic.dart (81%) create mode 100644 packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart 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/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index 58f1585..10dd71e 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -2,24 +2,40 @@ import 'package:rasadyar_core/core.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/repository/auth/auth_repository.dart'; import 'package:rasadyar_livestock/data/repository/auth/auth_repository_imp.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; GetIt get diLiveStock => GetIt.instance; -Future setupLiveStockDI() async { +Future setupLiveStockDI() async { diLiveStock.registerSingleton(DioErrorHandler()); - var tokenService = Get.find(); + + + final tokenService = Get.find(); + + if (tokenService.baseurl.value == null) { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } + + + diLiveStock.registerLazySingleton( + () => AuthRemoteDataSourceImp(diLiveStock.get()), + ); + + diLiveStock.registerLazySingleton( + () => AuthRepositoryImp(diLiveStock.get()), + ); + + diLiveStock.registerLazySingleton( - () => AppInterceptor( + () => AppInterceptor( refreshTokenCallback: () async { - var authRepository = diLiveStock.get(); - var hasAuthenticated = await authRepository.hasAuthenticated(); + final authRepository = diLiveStock.get(); + final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { - var newToken = await authRepository.loginWithRefreshToken( + final newToken = await authRepository.loginWithRefreshToken( authRequest: {'refresh': tokenService.refreshToken.value}, ); return newToken?.access; @@ -37,23 +53,13 @@ Future setupLiveStockDI() async { ), ); - // Register the DioRemote client + diLiveStock.registerLazySingleton( - () => DioRemote( + () => DioRemote( baseUrl: tokenService.baseurl.value, interceptors: diLiveStock.get(), ), ); - var dioRemoteClient = diLiveStock.get(); - await dioRemoteClient.init(); - // Register the AuthRemote data source implementation - diLiveStock.registerLazySingleton( - () => AuthRemoteDataSourceImp(diLiveStock.get()), - ); - - // Register the AuthRepository implementation - diLiveStock.registerLazySingleton( - () => AuthRepositoryImp(diLiveStock.get()), - ); + await diLiveStock.get().init(); } diff --git a/packages/livestock/lib/presentation/page/auth/logic.dart b/packages/livestock/lib/presentation/page/auth/logic.dart index 884edc3..2431423 100644 --- a/packages/livestock/lib/presentation/page/auth/logic.dart +++ b/packages/livestock/lib/presentation/page/auth/logic.dart @@ -5,7 +5,7 @@ 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_imp.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'; @@ -44,7 +44,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { RxInt secondsRemaining = 120.obs; Timer? _timer; - AuthRepositoryImp authRepository = diLiveStock.get(); + AuthRepository authRepository = diLiveStock.get(); final Module _module = Get.arguments; diff --git a/packages/livestock/lib/presentation/page/map/view.dart b/packages/livestock/lib/presentation/page/map/view.dart index 6935217..451a95e 100644 --- a/packages/livestock/lib/presentation/page/map/view.dart +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -1,6 +1,7 @@ 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 'logic.dart'; class MapPage extends GetView { @@ -8,23 +9,6 @@ class MapPage extends GetView { @override Widget build(BuildContext context) { - return Scaffold( - body: Stack( - children: [ - MapWidget( - markerWidget: Icon(Icons.pin_drop_rounded), - initOnTap: () { - - }, - initMarkerWidget: Assets.vec.mapMarkerSvg.svg( - width: 30, - height: 30, - ), - ), - - ], - ), - ); + return Scaffold(body: Stack(children: [MapWidget()])); } } - 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 81% 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..53575a7 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,17 @@ import 'dart:async'; 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 'package:rasadyar_core/core.dart'; -import 'custom_marker.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 +19,20 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; + RxList markerLocations = [ + 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), + ].obs; + @override void onInit() { super.onInit(); @@ -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,8 @@ 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); - } - - void setMarkers(List newMarkers) { - markers.value = newMarkers; - } - - void clearMarkers() { - markers.clear(); - } } 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..bd2226b --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -0,0 +1,179 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.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', + ), + + 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), + + // 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: FaIcon(FontAwesomeIcons.locationPin, color: AppColor.error), + ), + ) + .toList(); +} diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 4ada648..fa24e46 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,8 +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'; @@ -38,7 +38,6 @@ sealed class LiveStockPages { Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); - Get.lazyPut(() => DraggableBottomSheetController()); }), children: [ /*GetPage( diff --git a/packages/livestock/lib/presentation/widgets/captcha/logic.dart b/packages/livestock/lib/presentation/widgets/captcha/logic.dart index fe8cfdc..b35df6d 100644 --- a/packages/livestock/lib/presentation/widgets/captcha/logic.dart +++ b/packages/livestock/lib/presentation/widgets/captcha/logic.dart @@ -1,14 +1,14 @@ 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_imp.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(); - AuthRepositoryImp authRepository = diLiveStock.get(); + AuthRepository authRepository = diLiveStock.get(); @override void onInit() { From e262b0394a859c9ef5524dee3008d0bd107edafa Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 4 Aug 2025 08:10:18 +0330 Subject: [PATCH 04/39] fix : stack fit --- packages/livestock/lib/presentation/page/auth/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/livestock/lib/presentation/page/auth/view.dart b/packages/livestock/lib/presentation/page/auth/view.dart index b2cda08..2c5d35c 100644 --- a/packages/livestock/lib/presentation/page/auth/view.dart +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -13,7 +13,7 @@ class AuthPage extends GetView { return Scaffold( body: Stack( alignment: Alignment.center, - + fit: StackFit.expand, children: [ Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill), From 7a3061d9a46d51b0d301dd25efbd7f71b53a66d9 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 4 Aug 2025 08:51:06 +0330 Subject: [PATCH 05/39] fix : enabled in buttons --- .../presentation/widget/buttons/elevated.dart | 4 +++- .../widget/buttons/outline_elevated.dart | 16 ++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) 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 ?? ''), From 2c10800ce7944b7da70c81b90cbdf3421cb85695 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 4 Aug 2025 15:31:34 +0330 Subject: [PATCH 06/39] feat : first step request tagging --- android/app/src/main/AndroidManifest.xml | 6 + .../app/src/main/res/values-v35/styles.xml | 7 + .../service/app_navigation_observer.dart | 2 +- lib/presentation/pages/modules/logic.dart | 24 ++ lib/presentation/pages/modules/view.dart | 66 ++-- packages/core/lib/core.dart | 4 +- .../remote/app_interceptor.dart | 5 +- .../lib/infrastructure/remote/dio_remote.dart | 1 + packages/core/pubspec.lock | 24 ++ packages/core/pubspec.yaml | 2 +- .../data/common/dio_exception_handeler.dart | 14 +- .../remote/auth/auth_remote_imp.dart | 1 - .../lib/injection/live_stock_di.dart | 35 +- .../lib/presentation/page/auth/logic.dart | 2 +- .../lib/presentation/page/auth/view.dart | 44 +-- .../lib/presentation/page/map/logic.dart | 5 +- .../lib/presentation/page/map/view.dart | 155 ++++++++- .../page/map/widget/map_widget/view.dart | 35 +- .../page/request_tagging/logic.dart | 90 ++++- .../page/request_tagging/view.dart | 325 ++++++++++++++---- .../lib/presentation/page/root/logic.dart | 2 +- .../lib/presentation/routes/app_pages.dart | 2 + .../widgets/app_bar/i_app_bar.dart | 87 +++++ .../presentation/widgets/base_page/logic.dart | 25 ++ .../presentation/widgets/base_page/view.dart | 143 ++++++++ .../lib/presentation/widgets/search.dart | 82 +++++ pubspec.lock | 24 ++ 27 files changed, 1044 insertions(+), 168 deletions(-) create mode 100644 android/app/src/main/res/values-v35/styles.xml create mode 100644 packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart create mode 100644 packages/livestock/lib/presentation/widgets/base_page/logic.dart create mode 100644 packages/livestock/lib/presentation/widgets/base_page/view.dart create mode 100644 packages/livestock/lib/presentation/widgets/search.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 96504e7..d9e2fba 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -44,6 +44,12 @@ + + + + + + + diff --git a/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 44357cd..3fe440f 100644 --- a/lib/infrastructure/service/app_navigation_observer.dart +++ b/lib/infrastructure/service/app_navigation_observer.dart @@ -16,7 +16,6 @@ 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)) { _isWorkDone = true; @@ -31,6 +30,7 @@ class CustomNavigationObserver extends NavigatorObserver { _isWorkDone = true; await setupLiveStockDI(); } + super.didPush(route, previousRoute); tLog('CustomNavigationObserver: didPush - $routeName'); } diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index d35b096..8985caf 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -1,7 +1,12 @@ +import 'package:rasadyar_chicken/presentation/routes/routes.dart'; import 'package:rasadyar_core/core.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 ModulesLogic extends GetxController { TokenStorageService tokenService = Get.find(); + RxBool isLoading = false.obs; List moduleList = [ ModuleModel(title: 'بازرسی', icon: Assets.icons.inspection.path, module: Module.inspection), @@ -25,4 +30,23 @@ class ModulesLogic extends GetxController { tokenService.saveModule(module); tokenService.appModule.value = module; } + + Future navigateToModule(Module module) async { + if (module == Module.inspection) { + Get.offAllNamed(InspectionRoutes.init); + } else if (module == Module.liveStocks) { + await setupLiveStockDI(); + Get.offAllNamed(LiveStockRoutes.init); + } else if (module == Module.chicken) { + Get.offAllNamed(ChickenRoutes.init); + } + } + + void onTapCard(Module module, int index) async { + isLoading.value = true; + selectedIndex.value = index; + saveModule(module); + await Future.delayed(Duration(milliseconds: 800)); // Simulate loading delay + navigateToModule(module); + } } diff --git a/lib/presentation/pages/modules/view.dart b/lib/presentation/pages/modules/view.dart index 880050a..6ff320a 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'; @@ -16,39 +15,38 @@ class ModulesPage extends GetView { centerTitle: true, backgroundColor: AppColor.blueNormal, ), - body: GridView.builder( - padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), - - 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); - - // 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; - } + body: Stack( + fit: StackFit.expand, + alignment: Alignment.center, + children: [ + GridView.builder( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), + itemBuilder: (context, index) { + final module = controller.moduleList[index]; + return CardIcon( + title: module.title, + icon: module.icon, + onTap: () => controller.onTapCard(module.module, index), + ); }, - ); - }, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10, - crossAxisSpacing: 10, - ), - physics: BouncingScrollPhysics(), - itemCount: controller.moduleList.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + ), + physics: BouncingScrollPhysics(), + itemCount: controller.moduleList.length, + ), + 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/packages/core/lib/core.dart b/packages/core/lib/core.dart index c881e08..1539941 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -8,6 +8,7 @@ export 'package:dio/dio.dart'; export 'package:flutter_localizations/flutter_localizations.dart'; 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_rating_bar/flutter_rating_bar.dart'; export 'package:flutter_screenutil/flutter_screenutil.dart'; export 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -21,6 +22,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 +38,6 @@ 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'; //models export 'data/model/model.dart'; @@ -57,5 +58,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/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/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/pubspec.lock b/packages/core/pubspec.lock index 9eea597..936d0e5 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -725,6 +725,30 @@ 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: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index f87b92b..90dd599 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: ##image_picker image_picker: ^1.1.2 - + image_cropper: ^9.1.0 #UI cupertino_icons: ^1.0.8 diff --git a/packages/livestock/lib/data/common/dio_exception_handeler.dart b/packages/livestock/lib/data/common/dio_exception_handeler.dart index 6f5e233..e3f34d2 100644 --- a/packages/livestock/lib/data/common/dio_exception_handeler.dart +++ b/packages/livestock/lib/data/common/dio_exception_handeler.dart @@ -32,22 +32,16 @@ class DioErrorHandler { _errorSnackBar( error.response?.data.keys.first == 'is_user' ? 'کاربر با این شماره تلفن وجود ندارد' - : error.response?.data[error.response?.data.keys.first] ?? - 'خطا در برقراری ارتباط با سرور', + : '${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), - ), + 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, 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 index f67a63d..e4f227b 100644 --- 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 @@ -16,7 +16,6 @@ class AuthRemoteDataSourceImp extends AuthRemoteDataSource { '${_BASE_URL}login/', data: authRequest, fromJson: AuthResponseModel.fromJson, - headers: {'Content-Type': 'application/json'}, ); return res.data; } diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index 10dd71e..954be4c 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -11,27 +11,17 @@ GetIt get diLiveStock => GetIt.instance; Future setupLiveStockDI() async { diLiveStock.registerSingleton(DioErrorHandler()); - final tokenService = Get.find(); - if (tokenService.baseurl.value == null) { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } - - diLiveStock.registerLazySingleton( - () => AuthRemoteDataSourceImp(diLiveStock.get()), - ); - - diLiveStock.registerLazySingleton( - () => AuthRepositoryImp(diLiveStock.get()), - ); - - + // First register AppInterceptor with lazy callbacks diLiveStock.registerLazySingleton( - () => AppInterceptor( + () => AppInterceptor( refreshTokenCallback: () async { + // Use lazy access to avoid circular dependency final authRepository = diLiveStock.get(); final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { @@ -53,13 +43,26 @@ Future setupLiveStockDI() async { ), ); - + // Register DioRemote with the interceptor diLiveStock.registerLazySingleton( - () => DioRemote( + () => DioRemote( baseUrl: tokenService.baseurl.value, - interceptors: diLiveStock.get(), + // interceptors: diLiveStock.get(), ), ); + // Initialize DioRemote await diLiveStock.get().init(); + + // Now register the data source and repository + diLiveStock.registerLazySingleton( + () => AuthRemoteDataSourceImp(diLiveStock.get()), + ); + + diLiveStock.registerLazySingleton( + () => AuthRepositoryImp(diLiveStock.get()), + ); + + diLiveStock.registerLazySingleton(() => ImagePicker()); + await diLiveStock.allReady(); } diff --git a/packages/livestock/lib/presentation/page/auth/logic.dart b/packages/livestock/lib/presentation/page/auth/logic.dart index 2431423..755fe07 100644 --- a/packages/livestock/lib/presentation/page/auth/logic.dart +++ b/packages/livestock/lib/presentation/page/auth/logic.dart @@ -122,7 +122,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { final loginRequestModel = _buildLoginRequest(); isLoading.value = true; await safeCall( - call: () async => authRepository.login(authRequest: loginRequestModel.toJson()), + call: () async => await authRepository.login(authRequest: loginRequestModel.toJson()), onSuccess: (result) async { await tokenStorageService.saveModule(_module); await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); diff --git a/packages/livestock/lib/presentation/page/auth/view.dart b/packages/livestock/lib/presentation/page/auth/view.dart index 2c5d35c..f0a71b4 100644 --- a/packages/livestock/lib/presentation/page/auth/view.dart +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -17,27 +17,29 @@ class AuthPage extends GetView { 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), + ), + ], + ), ), ), ), 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 451a95e..670308d 100644 --- a/packages/livestock/lib/presentation/page/map/view.dart +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.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'; @@ -9,6 +10,158 @@ class MapPage extends GetView { @override Widget build(BuildContext context) { - return Scaffold(body: Stack(children: [MapWidget()])); + 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: [ + 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/livestock/lib/presentation/page/map/widget/map_widget/view.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart index bd2226b..30c7a42 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; import 'logic.dart'; @@ -172,8 +173,40 @@ class MapWidget extends GetView { .map( (element) => Marker( point: element, - child: FaIcon(FontAwesomeIcons.locationPin, color: AppColor.error), + child: IconButton( + onPressed: () { + Get.bottomSheet( + detailsBottomSheet(), + isScrollControlled: true, + isDismissible: true, + ignoreSafeArea: false, + ); + }, + icon: FaIcon(FontAwesomeIcons.locationPin, 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/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index de94cdb..f8875fc 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,10 +1,32 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; class RequestTaggingLogic extends GetxController { + RxInt currentIndex = 0.obs; + final int maxStep = 3; + + RxBool nextButtonEnabled = true.obs; + + final TextEditingController phoneController = TextEditingController(); + final TextEditingController fullNameController = TextEditingController(); + final TextEditingController addressController = TextEditingController(); + + ImagePicker imagePicker = diLiveStock.get(); + Rxn rancherImage = Rxn(null); + + @override + void onInit() { + super.onInit(); + setUpTextControllerListeners(); + setUpNextButtonListeners(); + ever(rancherImage, (callback) { + setUpNextButtonListeners(); + }); + } -final TextEditingController phoneController = TextEditingController(); @override void onReady() { super.onReady(); @@ -14,4 +36,68 @@ final TextEditingController phoneController = TextEditingController(); void onClose() { super.onClose(); } + + void onNext() { + if (currentIndex.value < maxStep) { + if (currentIndex.value == 0) {} + currentIndex.value++; + } + } + + 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() async { + rancherImage.value = await imagePicker.pickImage( + source: ImageSource.camera, + imageQuality: 60, + maxWidth: 1080, + maxHeight: 720, + ); + + getFileSizeInKB(rancherImage.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'); + } + + 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'); + } } diff --git a/packages/livestock/lib/presentation/page/request_tagging/view.dart b/packages/livestock/lib/presentation/page/request_tagging/view.dart index 0ff57ed..73ed45c 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/view.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; @@ -19,91 +21,272 @@ class RequestTaggingPage extends GetView { ), body: Padding( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15), - child: Column( - children: [ - RTextField( - controller: controller.phoneController, - label: 'تلفن دامدار', + child: ObxValue((index) { + return Column( + children: [ + Expanded(child: _buildStep(index.value)), + nextOrPreviousWidget(), + ], + ); + }, controller.currentIndex), + ), + ); + } + + Row nextOrPreviousWidget() { + return Row( + spacing: 10, + children: [ + ObxValue( + (data) => Expanded( + flex: 2, + child: RElevated( + height: 40.h, + enabled: data.value, + onPressed: controller.onNext, + child: Text('بعدی'), + backgroundColor: AppColor.blueNormal, ), + ), + controller.nextButtonEnabled, + ), + Expanded( + child: ROutlinedElevated( + enabled: controller.currentIndex.value > 0, + onPressed: controller.onPrevious, + child: Text('قبلی'), + borderColor: AppColor.error, + ), + ), + ], + ); + } - 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, + Widget _buildStep(int index) { + switch (index) { + case 0: + return firstStepWidget(); + default: + return Center( + child: Text( + 'مرحله $index در دست توسعه است', + style: AppFonts.yekan16.copyWith(color: AppColor.redNormal), + textDirection: TextDirection.rtl, + ), + ); + } + } - decoration: BoxDecoration( - color: AppColor.lightGreyNormal, - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Assets.images.placeHolder.image( - height: 150, - width: 200, - ), - ), - ), + 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), ), - 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, - ), - ], - ), - ), + 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(); + 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(), + Spacer(), + /* RElevated( + text: 'ارسال تصویر گله', + onPressed: () { + Get.toNamed(LiveStockRoutes.tagging); + }, + height: 40, + isFullWidth: true, + backgroundColor: AppColor.greenNormal, + textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + ),*/ + ], + ), + ); + } + Future showCropDialog() async { + await Get.dialog( + Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + 'آیا نیازی به برش تصویر دارید؟', + style: AppFonts.yekan16Bold, + textAlign: TextAlign.center, + ), - RElevated( - text: 'ارسال تصویر گله', - onPressed: () { - Get.toNamed(LiveStockRoutes.tagging); - }, - height: 40, - isFullWidth: true, - backgroundColor: AppColor.greenNormal, - textStyle: AppFonts.yekan16.copyWith(color: Colors.white), - ), - ], + const SizedBox(height: 24), + + Row( + mainAxisAlignment: MainAxisAlignment.end, + spacing: 12.w, + children: [ + RElevated( + height: 40.h, + onPressed: () async { + Get.back(); + await controller.cropImage(); + }, + child: const Text('بله'), + ), + ROutlinedElevated( + onPressed: () => Get.back(), + child: const Text('خیر'), + borderColor: AppColor.error, + ), + ], + ), + ], + ), ), ), ); } + + Column secondStepWidget() { + return Column( + children: [ + RTextField(controller: controller.phoneController, label: 'تلفن دامدار'), + + 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, + + 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), + ], + ), + ), + ), + ], + ), + ), + ), + ), + + Spacer(), + + RElevated( + text: 'ارسال تصویر گله', + onPressed: () { + Get.toNamed(LiveStockRoutes.tagging); + }, + height: 40, + isFullWidth: true, + backgroundColor: AppColor.greenNormal, + textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + ), + ], + ); + } } diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 4bb8c4c..7496d7a 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -26,7 +26,7 @@ class RootLogic extends GetxController { ProfilePage(), ]; - RxInt currentIndex = 1.obs; + RxInt currentIndex = 0.obs; @override void onReady() { diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index fa24e46..411f5c0 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -11,6 +11,7 @@ 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'; part 'app_routes.dart'; @@ -38,6 +39,7 @@ sealed class LiveStockPages { Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); + Get.lazyPut(() => BaseLogic()); }), children: [ /*GetPage( 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..2d776c5 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; + +RAppBar liveStockAppBar({ + bool hasBack = true, + bool hasFilter = true, + bool hasSearch = true, + bool isBase = false, + VoidCallback? onBackPressed, + GestureTapCallback? onFilterTap, + GestureTapCallback? onSearchTap, +}) { + return RAppBar( + hasBack: isBase == true ? false : hasBack, + onBackPressed: onBackPressed, + leadingWidth: 155, + leading: Row( + mainAxisSize: MainAxisSize.min, + spacing: 6, + children: [ + Text('رصددام', 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..adeea02 --- /dev/null +++ b/packages/livestock/lib/presentation/widgets/base_page/view.dart @@ -0,0 +1,143 @@ +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, + }); + + 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 VoidCallback? onBackPressed; + final GestureTapCallback? onFilterTap; + final GestureTapCallback? onSearchTap; + + @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, + appBar: liveStockAppBar( + 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: 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/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/pubspec.lock b/pubspec.lock index 8351850..c98f20e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -749,6 +749,30 @@ 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: From 7b8cfb5ae92a95531f76769b5d4be93b63b13ff3 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 5 Aug 2025 08:04:04 +0330 Subject: [PATCH 07/39] feat : new app bar --- .../widget/app_bar/r_app_bar.dart | 77 ++++++++++++++++++- .../widgets/app_bar/i_app_bar.dart | 9 ++- 2 files changed, 81 insertions(+), 5 deletions(-) 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/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart b/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart index 2d776c5..0960fe8 100644 --- a/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart +++ b/packages/livestock/lib/presentation/widgets/app_bar/i_app_bar.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_livestock/presentation/widgets/base_page/logic.dart'; -RAppBar liveStockAppBar({ +RAppBar2 liveStockAppBar({ bool hasBack = true, bool hasFilter = true, bool hasSearch = true, @@ -10,16 +10,17 @@ RAppBar liveStockAppBar({ VoidCallback? onBackPressed, GestureTapCallback? onFilterTap, GestureTapCallback? onSearchTap, + String? title, }) { - return RAppBar( + return RAppBar2( hasBack: isBase == true ? false : hasBack, onBackPressed: onBackPressed, - leadingWidth: 155, + leadingWidth: 180.w, leading: Row( mainAxisSize: MainAxisSize.min, spacing: 6, children: [ - Text('رصددام', style: AppFonts.yekan16Bold.copyWith(color: Colors.white)), + Text(title ?? 'رصددام', style: AppFonts.yekan16Bold.copyWith(color: Colors.white)), Assets.vec.appBarInspectionSvg.svg(width: 24, height: 24), ], ), From 59e6d621cf3e0166a7ff945e77a8de799f37d97a Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 5 Aug 2025 14:48:47 +0330 Subject: [PATCH 08/39] feat : request tagging --- .../widget/list_item/list_item2.dart | 51 ++++++++---- .../widget/list_view/list_view.dart | 1 + .../widget/list_view/r_list_view.dart | 5 +- packages/core/lib/utils/file_utils.dart | 10 +++ packages/core/lib/utils/utils.dart | 1 + packages/inspection/pubspec.lock | 24 ++++++ .../remote/livestock/livestock_remote.dart | 5 ++ .../livestock/livestock_remote_imp.dart | 29 +++++++ .../login_request/login_request_model.g.dart | 8 +- .../data/model/response/address/address.dart | 49 +++++++++++ .../response/auth/auth_response_model.g.dart | 4 +- .../captcha/captcha_response_model.g.dart | 16 ++-- .../user_profile/user_profile_model.g.dart | 40 ++++----- .../data/repository/auth/auth_repository.dart | 3 + .../repository/auth/auth_repository_imp.dart | 7 +- .../livestock/livestock_repository.dart | 11 +++ .../livestock/livestock_repository_imp.dart | 18 ++++ .../lib/injection/live_stock_di.dart | 20 ++++- .../page/request_tagging/logic.dart | 82 ++++++++++++++++--- 19 files changed, 318 insertions(+), 66 deletions(-) create mode 100644 packages/core/lib/utils/file_utils.dart create mode 100644 packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart create mode 100644 packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart create mode 100644 packages/livestock/lib/data/model/response/address/address.dart create mode 100644 packages/livestock/lib/data/repository/livestock/livestock_repository.dart create mode 100644 packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart 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/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/utils.dart b/packages/core/lib/utils/utils.dart index ba7f6b2..40b6ed5 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'; diff --git a/packages/inspection/pubspec.lock b/packages/inspection/pubspec.lock index dda8513..126a3f1 100644 --- a/packages/inspection/pubspec.lock +++ b/packages/inspection/pubspec.lock @@ -741,6 +741,30 @@ 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: 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..5534a7c --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart @@ -0,0 +1,5 @@ +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; + +abstract class LivestockRemoteDataSource { + Future getLocationDetailsByLatLng({required double latitude, required double longitude}); +} 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..a9748ec --- /dev/null +++ b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart @@ -0,0 +1,29 @@ +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'; + +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; + } + } +} 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 index 4504142..f10c8a6 100644 --- 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 @@ -10,14 +10,14 @@ _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?, + captchaCode: json['captchaCode'] as String?, + captchaKey: json['captchaKey'] as String?, ); Map _$LoginRequestModelToJson(_LoginRequestModel instance) => { 'username': instance.username, 'password': instance.password, - 'captcha_code': instance.captchaCode, - 'captcha_key': instance.captchaKey, + 'captchaCode': instance.captchaCode, + 'captchaKey': 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/auth/auth_response_model.g.dart b/packages/livestock/lib/data/model/response/auth/auth_response_model.g.dart index dc5d66d..642fa02 100644 --- 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 @@ -10,12 +10,12 @@ _AuthResponseModel _$AuthResponseModelFromJson(Map json) => _AuthResponseModel( refresh: json['refresh'] as String?, access: json['access'] as String?, - otpStatus: json['otp_status'] as bool?, + otpStatus: json['otpStatus'] as bool?, ); Map _$AuthResponseModelToJson(_AuthResponseModel instance) => { 'refresh': instance.refresh, 'access': instance.access, - 'otp_status': instance.otpStatus, + 'otpStatus': instance.otpStatus, }; 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 index 8d69248..a0ffdcb 100644 --- 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 @@ -9,17 +9,17 @@ part of 'captcha_response_model.dart'; _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?, + captchaKey: json['captchaKey'] as String?, + captchaImage: json['captchaImage'] as String?, + imageType: json['imageType'] as String?, + imageDecode: json['imageDecode'] as String?, ); Map _$CaptchaResponseModelToJson( _CaptchaResponseModel instance, ) => { - 'captcha_key': instance.captchaKey, - 'captcha_image': instance.captchaImage, - 'image_type': instance.imageType, - 'image_decode': instance.imageDecode, + 'captchaKey': instance.captchaKey, + 'captchaImage': instance.captchaImage, + 'imageType': instance.imageType, + 'imageDecode': instance.imageDecode, }; 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 index 7bf5323..79560bd 100644 --- 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 @@ -26,12 +26,12 @@ _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, + firstName: json['firstName'] as String, + lastName: json['lastName'] as String, + isActive: json['isActive'] as bool, mobile: json['mobile'] as String, phone: json['phone'] as String, - nationalCode: json['national_code'] as String, + nationalCode: json['nationalCode'] as String, birthdate: DateTime.parse(json['birthdate'] as String), nationality: json['nationality'] as String, ownership: json['ownership'] as String, @@ -39,21 +39,21 @@ _User _$UserFromJson(Map json) => _User( 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, + otpStatus: json['otpStatus'] as bool, + cityName: json['cityName'] as String, + provinceName: json['provinceName'] 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, + 'firstName': instance.firstName, + 'lastName': instance.lastName, + 'isActive': instance.isActive, 'mobile': instance.mobile, 'phone': instance.phone, - 'national_code': instance.nationalCode, + 'nationalCode': instance.nationalCode, 'birthdate': instance.birthdate.toIso8601String(), 'nationality': instance.nationality, 'ownership': instance.ownership, @@ -61,14 +61,14 @@ Map _$UserToJson(_User instance) => { 'photo': instance.photo, 'province': instance.province, 'city': instance.city, - 'otp_status': instance.otpStatus, - 'city_name': instance.cityName, - 'province_name': instance.provinceName, + 'otpStatus': instance.otpStatus, + 'cityName': instance.cityName, + 'provinceName': instance.provinceName, }; _Role _$RoleFromJson(Map json) => _Role( id: (json['id'] as num).toInt(), - roleName: json['role_name'] as String, + roleName: json['roleName'] as String, description: json['description'] as String, type: RoleType.fromJson(json['type'] as Map), permissions: json['permissions'] as List, @@ -76,7 +76,7 @@ _Role _$RoleFromJson(Map json) => _Role( Map _$RoleToJson(_Role instance) => { 'id': instance.id, - 'role_name': instance.roleName, + 'roleName': instance.roleName, 'description': instance.description, 'type': instance.type, 'permissions': instance.permissions, @@ -91,14 +91,14 @@ Map _$RoleTypeToJson(_RoleType instance) => { }; _Permission _$PermissionFromJson(Map json) => _Permission( - pageName: json['page_name'] as String, - pageAccess: (json['page_access'] as List) + pageName: json['pageName'] as String, + pageAccess: (json['pageAccess'] as List) .map((e) => e as String) .toList(), ); Map _$PermissionToJson(_Permission instance) => { - 'page_name': instance.pageName, - 'page_access': instance.pageAccess, + 'pageName': instance.pageName, + 'pageAccess': instance.pageAccess, }; diff --git a/packages/livestock/lib/data/repository/auth/auth_repository.dart b/packages/livestock/lib/data/repository/auth/auth_repository.dart index 0b58774..52fa9d5 100644 --- a/packages/livestock/lib/data/repository/auth/auth_repository.dart +++ b/packages/livestock/lib/data/repository/auth/auth_repository.dart @@ -1,3 +1,4 @@ +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'; @@ -11,4 +12,6 @@ abstract class AuthRepository { 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 index d3ffcba..11a7c60 100644 --- a/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart +++ b/packages/livestock/lib/data/repository/auth/auth_repository_imp.dart @@ -1,4 +1,6 @@ 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'; @@ -7,7 +9,8 @@ import 'auth_repository.dart'; class AuthRepositoryImp implements AuthRepository { final AuthRemoteDataSource authRemote; - AuthRepositoryImp(this.authRemote); + + AuthRepositoryImp({required this.authRemote}); @override Future login({required Map authRequest}) async => @@ -34,4 +37,6 @@ class AuthRepositoryImp implements AuthRepository { 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..4b9b70a --- /dev/null +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -0,0 +1,11 @@ +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 LivestockRepository { + Future getLocationDetails({ + required double latitude, + required double longitude, + }); + +} 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..5223f74 --- /dev/null +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -0,0 +1,18 @@ +import 'package:rasadyar_livestock/data/data_source/remote/livestock/livestock_remote.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; + +import 'livestock_repository.dart'; + +class LivestockRepositoryImp implements LivestockRepository { + final LivestockRemoteDataSource livestockRemote; + + LivestockRepositoryImp({required this.livestockRemote}); + + @override + Future getLocationDetails({required double latitude, required double longitude}) async { + return await livestockRemote.getLocationDetailsByLatLng( + latitude: latitude, + longitude: longitude, + ); + } +} diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index 954be4c..d374105 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -2,8 +2,12 @@ import 'package:rasadyar_core/core.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/presentation/routes/app_pages.dart'; GetIt get diLiveStock => GetIt.instance; @@ -17,7 +21,7 @@ Future setupLiveStockDI() async { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } - // First register AppInterceptor with lazy callbacks + // First register AppInterceptor with lazy callbacks diLiveStock.registerLazySingleton( () => AppInterceptor( refreshTokenCallback: () async { @@ -55,13 +59,25 @@ Future setupLiveStockDI() async { await diLiveStock.get().init(); // Now register the data source and repository + + //region Auth diLiveStock.registerLazySingleton( () => AuthRemoteDataSourceImp(diLiveStock.get()), ); diLiveStock.registerLazySingleton( - () => AuthRepositoryImp(diLiveStock.get()), + () => AuthRepositoryImp(authRemote: diLiveStock.get()), ); + //endregion + + //region Livestock + diLiveStock.registerLazySingleton( + () => LivestockRemoteDataSourceImp(), + ); + diLiveStock.registerLazySingleton( + () => LivestockRepositoryImp(livestockRemote: diLiveStock.get()), + ); + //endregion diLiveStock.registerLazySingleton(() => ImagePicker()); await diLiveStock.allReady(); diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index f8875fc..22bf9d3 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,22 +1,43 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/response/address/address.dart'; +import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; import 'package:rasadyar_livestock/injection/live_stock_di.dart'; class RequestTaggingLogic extends GetxController { RxInt currentIndex = 0.obs; - final int maxStep = 3; + final int maxStep = 2; RxBool nextButtonEnabled = true.obs; + LivestockRepository livestockRepository = diLiveStock.get(); + + //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); + RxnString addressLocationValue = RxnString(null); + + RxInt selectedSegment = 0.obs; + RxBool searchIsSelected = false.obs; + RxBool filterIsSelected = false.obs; + RxList filterSelected = [].obs; + + RxList isExpandedList = [].obs; + + RxBool tst1 = false.obs; + + //endregion + @override void onInit() { super.onInit(); @@ -25,6 +46,8 @@ class RequestTaggingLogic extends GetxController { ever(rancherImage, (callback) { setUpNextButtonListeners(); }); + + determineCurrentPosition(); } @override @@ -52,11 +75,11 @@ class RequestTaggingLogic extends GetxController { void setUpNextButtonListeners() { if (currentIndex.value == 0) { - nextButtonEnabled.value = + /* nextButtonEnabled.value = phoneController.text.isNotEmpty && fullNameController.text.isNotEmpty && addressController.text.isNotEmpty && - rancherImage.value != null; + rancherImage.value != null;*/ return; } @@ -94,10 +117,47 @@ class RequestTaggingLogic extends GetxController { getFileSizeInKB(rancherImage.value?.path ?? '', tag: 'Cropped'); } - 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'); + 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 = '$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'; + } } } From f571a5b646a48d5c297593a492be1afca63e1a36 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 5 Aug 2025 14:49:01 +0330 Subject: [PATCH 09/39] feat : request tagging --- .../response/address/address.freezed.dart | 650 ++++++++++ .../model/response/address/address.g.dart | 81 ++ .../page/request_tagging/view.dart | 1081 +++++++++++++++-- .../presentation/widgets/base_page/view.dart | 30 +- 4 files changed, 1707 insertions(+), 135 deletions(-) create mode 100644 packages/livestock/lib/data/model/response/address/address.freezed.dart create mode 100644 packages/livestock/lib/data/model/response/address/address.g.dart 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..5cf9150 --- /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['ISO3166_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, + 'ISO3166_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/presentation/page/request_tagging/view.dart b/packages/livestock/lib/presentation/page/request_tagging/view.dart index 73ed45c..085d317 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/view.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -3,7 +3,7 @@ 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'; @@ -12,53 +12,59 @@ 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: ObxValue((index) { - return Column( - children: [ - Expanded(child: _buildStep(index.value)), - nextOrPreviousWidget(), - ], + 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), - ), + + nextOrPreviousWidget(), + SizedBox(height: 10.h), + ], ); } - Row nextOrPreviousWidget() { - return Row( - spacing: 10, - children: [ - ObxValue( - (data) => Expanded( - flex: 2, - child: RElevated( - height: 40.h, - enabled: data.value, - onPressed: controller.onNext, - child: Text('بعدی'), - backgroundColor: AppColor.blueNormal, + 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, + onPressed: () { + controller.currentIndex.value++; + }, + enabled: data.value, + // onPressed: controller.onNext, + child: Text('بعدی'), + backgroundColor: AppColor.blueNormal, + ), ), + controller.nextButtonEnabled, ), - controller.nextButtonEnabled, - ), - Expanded( - child: ROutlinedElevated( - enabled: controller.currentIndex.value > 0, - onPressed: controller.onPrevious, - child: Text('قبلی'), - borderColor: AppColor.error, + Expanded( + child: ObxValue((data) { + return ROutlinedElevated( + enabled: data.value > 0, + onPressed: controller.onPrevious, + child: Text('قبلی'), + borderColor: AppColor.error, + ); + }, controller.currentIndex), ), - ), - ], + ], + ), ); } @@ -66,6 +72,10 @@ class RequestTaggingPage extends GetView { switch (index) { case 0: return firstStepWidget(); + case 1: + return secondStepWidget(); + case 2: + return thirdStepWidget(); default: return Center( child: Text( @@ -77,6 +87,50 @@ class RequestTaggingPage extends GetView { } } + //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), + + 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( @@ -160,8 +214,6 @@ class RequestTaggingPage extends GetView { ), ), - Spacer(), - /* RElevated( text: 'ارسال تصویر گله', onPressed: () { @@ -177,40 +229,455 @@ class RequestTaggingPage extends GetView { ); } - Future showCropDialog() async { - await Get.dialog( - Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + //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.string ?? 'N/A', + 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(); + 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(), + SizedBox(height: 10), + + Padding( + padding: const EdgeInsets.fromLTRB(35, 0, 35, 20), + child: RElevated( + text: 'ثبت نهایی و ارسال به اتحادیه', + textStyle: AppFonts.yekan18, + height: 40, + backgroundColor: AppColor.greenNormal, + onPressed: () {}, + isFullWidth: true, + ), + ), + ], + ), + Positioned( + right: 10, + bottom: 75, + 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: RListView.separated( + itemCount: 20, + 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(20, (i) => i)), + separatorBuilder: (BuildContext context, int index) => SizedBox(height: 8.h), + ), + ); + } + + 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: () { + 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.all(20), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 15, children: [ - Text( - 'آیا نیازی به برش تصویر دارید؟', - style: AppFonts.yekan16Bold, - textAlign: TextAlign.center, - ), - - const SizedBox(height: 24), - Row( - mainAxisAlignment: MainAxisAlignment.end, - spacing: 12.w, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - RElevated( - height: 40.h, - onPressed: () async { - Get.back(); - await controller.cropImage(); - }, - child: const Text('بله'), + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), ), - ROutlinedElevated( - onPressed: () => Get.back(), - child: const Text('خیر'), - borderColor: AppColor.error, + 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), ), ], ), @@ -221,72 +688,434 @@ class RequestTaggingPage extends GetView { ); } - Column secondStepWidget() { - return Column( - children: [ - RTextField(controller: controller.phoneController, label: 'تلفن دامدار'), + 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( - 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, + SizedBox _buildLiveStockImage() { + return SizedBox( + width: Get.width, + height: 350, + child: Card( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Expanded( + child: Container( + width: Get.width, + 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), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } - 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), - ], - ), - ), - ), - ], + OverlayDropdownWidget _buildTagType() { + return OverlayDropdownWidget( + items: ['نوع پلاک 1', 'نوع پلاک 2', 'نوع پلاک 3'], + onChanged: (value) { + print('Selected Breed: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'نوع پلاک'), + ); + } + + TextFiledFixedHint _buildTagNumber() { + return TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک دام', + onChanged: (String value) { + eLog('father Tag: $value'); + }, + ); + } + + TextFiledFixedHint _buildFatherTagNumber() { + return TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک پدر ', + onChanged: (String value) { + eLog('father Tag: $value'); + }, + ); + } + + TextFiledFixedHint _buildMotherTagNumber() { + return TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک مادر ', + onChanged: (String value) { + eLog('Mother Tag: $value'); + }, + ); + } + + OverlayDropdownWidget _buildLivestockBreed() { + return OverlayDropdownWidget( + items: ['نوع نژاد 1', 'نوع نژاد 2', 'نوع نژاد 3'], + onChanged: (value) { + print('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, + ); + } + + Container _buildLivestockBirthday() { + return 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) { + print('Selected: $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(), - - RElevated( - text: 'ارسال تصویر گله', - onPressed: () { - Get.toNamed(LiveStockRoutes.tagging); - }, - height: 40, - isFullWidth: true, - backgroundColor: AppColor.greenNormal, - textStyle: AppFonts.yekan16.copyWith(color: Colors.white), + 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/widgets/base_page/view.dart b/packages/livestock/lib/presentation/widgets/base_page/view.dart index adeea02..e9e42dd 100644 --- a/packages/livestock/lib/presentation/widgets/base_page/view.dart +++ b/packages/livestock/lib/presentation/widgets/base_page/view.dart @@ -23,6 +23,9 @@ class BasePage extends StatefulWidget { this.onFilterTap, this.onSearchTap, this.filteringWidget, + this.title, + this.padding, + this.avoidBottomInset = true, }); final List? routes; @@ -37,9 +40,13 @@ class BasePage extends StatefulWidget { 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(); @@ -115,7 +122,9 @@ class _BasePageState extends State { 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, @@ -124,15 +133,18 @@ class _BasePageState extends State { onFilterTap: widget.hasFilter ? _onFilterTap : null, onSearchTap: widget.hasSearch ? () => controller.toggleSearch() : null, ), - body: 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, - ], + 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, From 9b16a06f55ee02a420970ad9dbde579138e367cf Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 9 Aug 2025 08:43:26 +0330 Subject: [PATCH 10/39] feat : profile ui --- .../lib/presentation/page/profile/logic.dart | 143 ++++ .../lib/presentation/page/profile/view.dart | 697 +++++++++++++++++- .../lib/presentation/page/root/logic.dart | 4 + .../lib/presentation/page/tagging/logic.dart | 1 + 4 files changed, 844 insertions(+), 1 deletion(-) 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/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 7496d7a..750671f 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -26,8 +26,12 @@ class RootLogic extends GetxController { ProfilePage(), ]; + RxInt currentIndex = 0.obs; + + TokenStorageService tokenService = Get.find(); + @override void onReady() { // TODO: implement onReady 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(); } } From c05086a37b3af10625071fc5b382c3a03f389160 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 9 Aug 2025 09:17:30 +0330 Subject: [PATCH 11/39] fix : list padding --- packages/livestock/lib/presentation/page/requests/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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( From 2669af7a921d908b5ca1c354b9637b17cd1915df Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 9 Aug 2025 16:58:52 +0330 Subject: [PATCH 12/39] feat : live stock batch --- packages/livestock/build.yaml | 6 + .../remote/livestock/livestock_remote.dart | 8 +- .../livestock/livestock_remote_imp.dart | 26 + .../login_request/login_request_model.g.dart | 8 +- .../model/response/address/address.g.dart | 4 +- .../response/auth/auth_response_model.g.dart | 4 +- .../captcha/captcha_response_model.g.dart | 16 +- .../response/live_tmp/livestock_model.dart | 50 + .../live_tmp/livestock_model.freezed.dart | 1454 +++++++++++++++++ .../response/live_tmp/livestock_model.g.dart | 88 + .../user_profile/user_profile_model.g.dart | 40 +- .../livestock/livestock_repository.dart | 3 + .../livestock/livestock_repository_imp.dart | 11 +- .../lib/presentation/page/auth/view.dart | 4 +- .../page/request_tagging/logic.dart | 189 ++- .../page/request_tagging/view.dart | 204 +-- 16 files changed, 1974 insertions(+), 141 deletions(-) create mode 100644 packages/livestock/build.yaml create mode 100644 packages/livestock/lib/data/model/response/live_tmp/livestock_model.dart create mode 100644 packages/livestock/lib/data/model/response/live_tmp/livestock_model.freezed.dart create mode 100644 packages/livestock/lib/data/model/response/live_tmp/livestock_model.g.dart 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/lib/data/data_source/remote/livestock/livestock_remote.dart b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart index 5534a7c..f16fc1e 100644 --- a/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart +++ b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote.dart @@ -1,5 +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 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 index a9748ec..642c3ed 100644 --- 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 @@ -1,6 +1,7 @@ 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 @@ -26,4 +27,29 @@ class LivestockRemoteDataSourceImp implements LivestockRemoteDataSource { rethrow; } } + + @override + Future createTaggingLiveStock({required LivestockData data}) async { + try { + Dio dio = Dio(); + dio.interceptors.add(PrettyDioLogger( + requestBody: true, + responseBody: true, + 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/request/login_request/login_request_model.g.dart b/packages/livestock/lib/data/model/request/login_request/login_request_model.g.dart index f10c8a6..4504142 100644 --- 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 @@ -10,14 +10,14 @@ _LoginRequestModel _$LoginRequestModelFromJson(Map json) => _LoginRequestModel( username: json['username'] as String?, password: json['password'] as String?, - captchaCode: json['captchaCode'] as String?, - captchaKey: json['captchaKey'] as String?, + captchaCode: json['captcha_code'] as String?, + captchaKey: json['captcha_key'] as String?, ); Map _$LoginRequestModelToJson(_LoginRequestModel instance) => { 'username': instance.username, 'password': instance.password, - 'captchaCode': instance.captchaCode, - 'captchaKey': instance.captchaKey, + 'captcha_code': instance.captchaCode, + 'captcha_key': instance.captchaKey, }; diff --git a/packages/livestock/lib/data/model/response/address/address.g.dart b/packages/livestock/lib/data/model/response/address/address.g.dart index 5cf9150..9e5f9aa 100644 --- a/packages/livestock/lib/data/model/response/address/address.g.dart +++ b/packages/livestock/lib/data/model/response/address/address.g.dart @@ -16,7 +16,7 @@ _Address _$AddressFromJson(Map json) => _Address( district: json['district'] as String?, county: json['county'] as String?, province: json['province'] as String?, - ISO3166_2_lvl4: json['ISO3166_2_lvl4'] 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?, @@ -32,7 +32,7 @@ Map _$AddressToJson(_Address instance) => { 'district': instance.district, 'county': instance.county, 'province': instance.province, - 'ISO3166_2_lvl4': instance.ISO3166_2_lvl4, + 'i_s_o3166_2_lvl4': instance.ISO3166_2_lvl4, 'postcode': instance.postcode, 'country': instance.country, 'country_code': instance.country_code, 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 index 642fa02..dc5d66d 100644 --- 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 @@ -10,12 +10,12 @@ _AuthResponseModel _$AuthResponseModelFromJson(Map json) => _AuthResponseModel( refresh: json['refresh'] as String?, access: json['access'] as String?, - otpStatus: json['otpStatus'] as bool?, + otpStatus: json['otp_status'] as bool?, ); Map _$AuthResponseModelToJson(_AuthResponseModel instance) => { 'refresh': instance.refresh, 'access': instance.access, - 'otpStatus': instance.otpStatus, + 'otp_status': instance.otpStatus, }; 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 index a0ffdcb..8d69248 100644 --- 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 @@ -9,17 +9,17 @@ part of 'captcha_response_model.dart'; _CaptchaResponseModel _$CaptchaResponseModelFromJson( Map json, ) => _CaptchaResponseModel( - captchaKey: json['captchaKey'] as String?, - captchaImage: json['captchaImage'] as String?, - imageType: json['imageType'] as String?, - imageDecode: json['imageDecode'] as String?, + 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, ) => { - 'captchaKey': instance.captchaKey, - 'captchaImage': instance.captchaImage, - 'imageType': instance.imageType, - 'imageDecode': instance.imageDecode, + '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.g.dart b/packages/livestock/lib/data/model/response/user_profile/user_profile_model.g.dart index 79560bd..7bf5323 100644 --- 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 @@ -26,12 +26,12 @@ _User _$UserFromJson(Map json) => _User( id: (json['id'] as num).toInt(), username: json['username'] as String, password: json['password'] as String, - firstName: json['firstName'] as String, - lastName: json['lastName'] as String, - isActive: json['isActive'] as bool, + 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['nationalCode'] 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, @@ -39,21 +39,21 @@ _User _$UserFromJson(Map json) => _User( photo: json['photo'] as String, province: (json['province'] as num).toInt(), city: (json['city'] as num).toInt(), - otpStatus: json['otpStatus'] as bool, - cityName: json['cityName'] as String, - provinceName: json['provinceName'] as String, + 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, - 'firstName': instance.firstName, - 'lastName': instance.lastName, - 'isActive': instance.isActive, + 'first_name': instance.firstName, + 'last_name': instance.lastName, + 'is_active': instance.isActive, 'mobile': instance.mobile, 'phone': instance.phone, - 'nationalCode': instance.nationalCode, + 'national_code': instance.nationalCode, 'birthdate': instance.birthdate.toIso8601String(), 'nationality': instance.nationality, 'ownership': instance.ownership, @@ -61,14 +61,14 @@ Map _$UserToJson(_User instance) => { 'photo': instance.photo, 'province': instance.province, 'city': instance.city, - 'otpStatus': instance.otpStatus, - 'cityName': instance.cityName, - 'provinceName': instance.provinceName, + '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['roleName'] as String, + roleName: json['role_name'] as String, description: json['description'] as String, type: RoleType.fromJson(json['type'] as Map), permissions: json['permissions'] as List, @@ -76,7 +76,7 @@ _Role _$RoleFromJson(Map json) => _Role( Map _$RoleToJson(_Role instance) => { 'id': instance.id, - 'roleName': instance.roleName, + 'role_name': instance.roleName, 'description': instance.description, 'type': instance.type, 'permissions': instance.permissions, @@ -91,14 +91,14 @@ Map _$RoleTypeToJson(_RoleType instance) => { }; _Permission _$PermissionFromJson(Map json) => _Permission( - pageName: json['pageName'] as String, - pageAccess: (json['pageAccess'] as List) + pageName: json['page_name'] as String, + pageAccess: (json['page_access'] as List) .map((e) => e as String) .toList(), ); Map _$PermissionToJson(_Permission instance) => { - 'pageName': instance.pageName, - 'pageAccess': instance.pageAccess, + 'page_name': instance.pageName, + 'page_access': instance.pageAccess, }; diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart index 4b9b70a..7a1aaca 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -1,6 +1,7 @@ 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 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; abstract class LivestockRepository { Future getLocationDetails({ @@ -8,4 +9,6 @@ abstract class LivestockRepository { required double longitude, }); + Future createTaggingLiveStock({required LivestockData data}); + } diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart index 5223f74..2911c6c 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -1,5 +1,6 @@ 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'; import 'livestock_repository.dart'; @@ -9,10 +10,18 @@ class LivestockRepositoryImp implements LivestockRepository { LivestockRepositoryImp({required this.livestockRemote}); @override - Future getLocationDetails({required double latitude, required double longitude}) async { + 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); + } } diff --git a/packages/livestock/lib/presentation/page/auth/view.dart b/packages/livestock/lib/presentation/page/auth/view.dart index f0a71b4..983d6bc 100644 --- a/packages/livestock/lib/presentation/page/auth/view.dart +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -136,11 +136,11 @@ class AuthPage extends GetView { }) : null, validator: (value) { - if (value == null || value.isEmpty) { + /* if (value == null || value.isEmpty) { return '⚠️ شماره موبایل را وارد کنید'; } else if (value.length < 10) { return '⚠️ شماره موبایل باید 11 رقم باشد'; - } + }*/ return null; }, style: AppFonts.yekan13, diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index 22bf9d3..245ae69 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,6 +1,12 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; + import 'package:flutter/material.dart'; 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'; import 'package:rasadyar_livestock/data/repository/livestock/livestock_repository.dart'; import 'package:rasadyar_livestock/injection/live_stock_di.dart'; @@ -11,6 +17,7 @@ class RequestTaggingLogic extends GetxController { RxBool nextButtonEnabled = true.obs; LivestockRepository livestockRepository = diLiveStock.get(); + LivestockData? liveStockTmp; //region First Step final TextEditingController phoneController = TextEditingController(); @@ -25,19 +32,37 @@ class RequestTaggingLogic extends GetxController { Rxn herdImage = Rxn(null); Rx> addressDetails = Rx>(Resource.loading()); RxnString addressDetailsValue = RxnString(null); - RxnString addressLocationValue = 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(); @@ -53,6 +78,37 @@ class RequestTaggingLogic extends GetxController { @override void onReady() { super.onReady(); + + rancher.value = Rancher( + name: 'حسن حسنی', + phone: '09121234567', + image: + '/9j/4QLmRXhpZgAATU0AKgAAAAgACAEAAAQAAAABAAADwAEQAAIAAAAOAAAAbgEBAAQAAAABAAAC0AEPAAIAAAAIAAAAfAExAAIAAAAOAAAAhIdpAAQAAAABAAAApgESAAMAAAABAAgAAAEyAAIAAAAUAAAAkgAAAABHYWxheHkgQTU1IDVHAHNhbXN1bmcAQTU1NkVYWFM5QllGMwAyMDI1OjA4OjA5IDE1OjE3OjA3AAAakAAAAgAAAAUAAAHkkgIABQAAAAEAAAHpkgQACgAAAAEAAAHxiCIAAwAAAAEAAgAAkgUABQAAAAEAAAH5kAMAAgAAABQAAAIBoAAAAgAAAAUAAAIVkpEAAgAAAAQ4NTIApAMAAwAAAAEAAAAApAIAAwAAAAEAAAAAgpoABQAAAAEAAAIakBAAAgAAAAcAAAIikgkAAwAAAAEAAAAAkpAAAgAAAAQ4NTIAgp0ABQAAAAEAAAIpiCcAAwAAAAEE4gAApAUAAwAAAAEAGQAAkpIAAgAAAAQ4NTIApAQABQAAAAEAAAIxkAQAAgAAABQAAAI5kgEACgAAAAEAAAJNkgcAAwAAAAEAAgAAkgoABQAAAAEAAAJVkBEAAgAAAAcAAAJdpAYAAwAAAAEAAAAAkggAAwAAAAEAAAAAAAAAADAyMjAAAAAA4wAAAGQAAAAAAAAAZAAAAOMAAABkMjAyNTowODowOSAxNToxNzowNwAwMTAwAAAAAZAAACcQKzAzOjMwAAAAVfAAACcQAAAwDAAAJxAyMDI1OjA4OjA5IDE1OjE3OjA3AAAAAAEAAAAZAAABdAAAAGQrMDM6MzAAAAUBEAACAAAADgAAAqYBDwACAAAACAAAArQBMQACAAAADgAAArwBEgADAAAAAQAIAAABMgACAAAAFAAAAsoAAAAAR2FsYXh5IEE1NSA1RwBzYW1zdW5nAEE1NTZFWFhTOUJZRjMAMjAyNTowODowOSAxNToxNzowNwD/4AAQSkZJRgABAQAAAQABAAD/4gIYSUNDX1BST0ZJTEUAAQEAAAIIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAGRyWFlaAAABVAAAABRnWFlaAAABaAAAABRiWFlaAAABfAAAABR3dHB0AAABkAAAABRyVFJDAAABpAAAAChnVFJDAAABpAAAAChiVFJDAAABpAAAAChjcHJ0AAABzAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAEYAAAAcAEQAaQBzAHAAbABhAHkAIABQADMAIABHAGEAbQB1AHQAIAB3AGkAdABoACAAcwBSAEcAQgAgAFQAcgBhAG4AcwBmAGUAcgAAWFlaIAAAAAAAAIPdAAA9vv///7tYWVogAAAAAAAASr8AALE3AAAKuVhZWiAAAAAAAAAoOwAAEQsAAMjLWFlaIAAAAAAAAPbWAAEAAAAA0y1wYXJhAAAAAAAEAAAAAmZmAADypwAADVkAABPQAAAKWwAAAAAAAAAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAgAAAAHABHAG8AbwBnAGwAZQAgAEkAbgBjAC4AIAAyADAAMQA2/9sAQwANCQoLCggNCwoLDg4NDxMgFRMSEhMnHB4XIC4pMTAuKS0sMzpKPjM2RjcsLUBXQUZMTlJTUjI+WmFaUGBKUVJP/9sAQwEODg4TERMmFRUmTzUtNU9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P/8AAEQgC0APAAwEiAAIRAQMRAf/EABsAAAIDAQEBAAAAAAAAAAAAAAECAAMEBQYH/8QAQxAAAQMCBAMEBwYGAQQCAwEBAQACEQMhBBIxQQVRYRMicYEUMjORobHBBiM0QlLRFSRicuHw8SVDU4I1RGOSshZz/8QAGQEBAQEBAQEAAAAAAAAAAAAAAAECAwQF/8QAKREBAQEBAAICAQQBBQADAAAAAAERAhIhAzFBBBNRcYEUIjJhkUKx0f/aAAwDAQACEQMRAD8A8pCiMIlQL4qIwoiIgihCAIeSaEIQBTREhTkgCIU2U5oDKdrlWiCg0NMK5jphYw5Ox5nVBqQSseCVZEqBCFI8kxChbdAm6IEIqBUSOagU3RhARqtdAxELK25WmnoAoNmIcHUhcrq16hzYbEgy19Nt+oF/jK4xk04W7Chz+Dggkuo1S0jkCLfVQW8Veyliszm9yq3O2B5H4rFUqtfRJpujoupUpMxnDmZwC6ifcDr9Fy6tBtBuVhMHWVUW4Ml1KZ8le6YslwzQ2i2BE6qwoKDMm91NPJWVGy0gC6z4enUZOdBco25TRoiAJQWgd0IstVCGygMVGk7oPQtM0mxyVbkaLgaLfBR/RZ1rCTCUuRSE6ouAXWXn+LgDFtJ/Su6uPxakalRhaOiRLHPZrYrfgzlcIWeng6sXC6GGwxZBIVrMroCMoWfF0g+iQXZRzV7dAFTi3NbRdnNki1zKHZUnBrXCCLmVc1lFlYOBGdyxsp0y3M92VqesxrMuIpuOUaBbRpxVcUWxYk6JMJXNV4LtYVdGl6XVD6hPgtAoto4juCJCDfhCO2XTpmCuThbVhK6jNbqB+IXwNUCJLSvEVnAtjQhe0xrowVWP0leEquLnX06KNCAS2QLaSuhgKtXC1hTqyA7RZsJUYaJpu5roYo06jaZaQXN5Jo3VqzKNE1HkRC41Nj8dii8jKAU9es7E1hTcQ1o6rpYSlTpU4pkEblPoW0g5jA22iLnFOLbJSFEUukmUHENEuIATu0VbmhwuqM2KcCycwKzK3FUyIIVIVR08BADPFdVxc1staHHkuTgTZsc124us1YSkS5gLm5SdlHszMPzVgSvgMJJtCiuMylTw9cvFTO4ujXRaXUsMaorEtnZYmsp1az8hIbMklW1aNM0A+lUJbTMkqo2YusKNHvQZ2VGFxoq0oqPyHxVIH8Qe3tHZWtsBzWmrwuk8y0ltogWQLi3tGHOVweNyVpwTnuw7S4giLFYn4X0ZnZznzHfZdLDMFOiGt0hAXEgGwHVVtztEAhX7rJjmVOyiiDmlRVzXmwcVHujfVCk1wptzawrIQIC4jVI6m43DzKtUUCNzgd4g+AQJdysnNlCgrEgXKV1RrfWdCtIVTqYOyAyHCZsslCu+rVexzYjQq9tEAmSXTzThgaSQgQMcJkyq3mqKrQGyzdaIQjogX5rBxGlTcG9o/KNl0FzuKOaQ1haXH5Kwqqg6m5rqLyA0aDmFbQdSyHsSMreSz020qbw1853aAbBVlpw9Y0GzDjcqsvRYN4fQY4HUaq9ZcA0NwzGt0AstR1VFbtUp1TPS7oqHzQ2Cm6myCIoBFAUdEEpqMaQCYJQOEUCCNVEDBFBFBTi/YO8FyV1sX+HcuSoJsjR9vT/uCVNS9tT/ALgg7g0UKg0UVERi6iCDPi/UHisi14v1PNZLKAKIoIPnsopAUQVVMgoCoqiKQioEAhSEVPJAsIFPCCBYQhMgUAhTZFSEECIKCiCxrr6q5j7hZQnaYQbwQUYCysqELQx4IUBLUmmiugESke26CtRQoC1ygtatFNwWQFWMeQbIOjTaHea14Cv6FiIqgGjVGR4PI7+S5dOrGqudWzMAcJQdzBtdTrVcNUEBwLR4rE0PdWqMrNswwJC00n9pgsNjA6XNPZ1PLT4QqeMYtuExbZZmFRoeDPkUFgAFh8FI6Lm/xdn6D71P4wyb03JlHSgFKQuf/F6f/jKP8Vp/oKuVG5ELn/xOnfulEcTpT6pTB0p7p5Kqq6Mp6rJ/E6QHqlJUx9J9OIMymD1FGpOFDgiKriNZXFwnGcOzD9nUzSNLKxvGMNNyQs2VrXXzFIS6bLnjjGEn1ne5EcXwm7yplXW66pdTJqgnQKj+LYM/nUPFcGf+4mVNbMoMWQNgsg4phIvUAU/iWFP/AHFcqNeiV4DtQqG4/DuFqk+AQOOw3/kCuBa+HbUYWEQDySBlOjQFN5sOarxeNZ2f3NQFyx9oK+Xt6oEFX2jpUKLWHM02OiDzOIM6hKzF4ZrQ3tWwLKupi6BqAioCg24cxVF12GBedoY2gKgJeIXZpcSwg/7zPeosPxE5cFVj9J+S8SGOqEgAles4jjsNVwr2trMkgiJXDwpoUrmq2eUqNMuHpClVDnXHJbMOBXFQacjyVNapTLnQ9vkVbgqlOmHEvaJPNE1zsY2pSrQ7yKswGNfRqgE90m66GL9HxFKDUbOxlcYs7OoRIMaELUR62k8PYHDQ3TGy5vDMUz0YCo8AjYlaziaX/kZ71kO7qqyg7EUf/I33pPSKR0qN96oqxd6axrRiqtMsID2k9CsoeOYVR0sAZgdV3gvN4GsxsS4a813xiKUe0b71mrFqBAIIOhSCvS/8rPep29H/AMrfeopH0KZYWxAdqq6NClhaJY42PNHE4iKZFHvPi2W6xspYjFMy4juwfBBso0KeYVGeqdElWpW9KDGTlAkkrRQaxtPLTcCByKeEGOiRi3uNRkFhsVs0soGgC1kddUAUi6mqiBTEqIlRQAoI7IIoKKKIAgeqJQKCIFTwUKBSgUd0t0EPVIWiZgFOUrjAJ5IjK/DsdWFR3rNSh9GvV7MHvC6zVBiKuIDxma2YWvDYZlElwHeO6qOpRbDGgbKw+KSmO6E5VFbtUh5JnapbFACigVFQQih4ooA5wa0uOy5japqVy51wtPE6vZ4aBq4wuZSee8BsLqDt0MR6VmfvN1cudwj8OTsXLoqghFDZRBVi/wAO/wAFyV1sTfDv8FyVBNlKYPb0/wC4IKU/bM/uHzQd7ZRQaKKiKKKIM+L9mPFZFrxfqDxWRQRBHZBB84aUZSSoCtKslEOlV7ogxogtlQFVg2RBm6CyVEk3TAzZAUCiCpGiBVEUEREEUEE6KeaOiiAI7IKIHBVjHQqUQg3UqsWK0ANe2VzGuWinWykXUF9SluFSQQVpZUa47JnMa5s2lFY0w0VjqRAsEsEIggqwOtCrTDkg7XAy6rhMbhwbNDao8pH1V3EcIOI4Cg/MQaDiNNZj9lk+zdUU+IupnSrTLT5X+i67WlvpeFaJLmHsxzMW+MIOB/B9fvvgkfwosv2ojmQq6XEsS6WtaSeapdVrVqkYio4A/BX2hMRTp0jDageeiNGhVqu7tN0c4sunhcPg2gFpDzzK2gACBAHQJpjlDhlSLvA5oN4eSY7QSF1SQAVgqtc1+ZpvKaMlbDGi8NLplXM4fVIkkBa69NlSjIPeAV2GeH0GncWTVxlo8KrVI7zQE38HrzZ4hdbDmGALQ1TypjhHg1fXM1U1uGYmkPVLvBenCm108qY8eabg6HAjxC00+HVaozMezLzJhdzHuw1Nn3tNrnHQQuO+s54LWgMZ+lui1KYLcHhaLga9V1Z27KfdHv8A+FfTxdKgf5bCUKcc2Zz73SubUxLGGGy49FU+rXPJtpEXVHpaf2i4hTaGtrAAaDKP2Rd9ocXU9sKVT+6m0/ReYIrAEuqEECY1TOFdky/vDbWVMHojxWk+1Xh+Dd40Gj5JDieG1HS/hlAH+lz2/Jy4JdXZILhmmMu6JqYhtjGYmMu/uTEegLuCPbB4c5h5sxDvrKp9F4O6SBi2E/8A5Gujyyj5rjdvXBAyAkzYG6YYqoCAacnkCnsdYcK4e/TiNVg/qoA/JyDuCMkdjxPDmf8AyNc35ArlNxp0NM2807eINi+YJ7MbH8Cx35KmHqDm2u36kFUng3Eb5cJWfG7Gl3ySt4jTn2hC0M4l+mtA8U9mOdVoVaTi2qxzHDUOEFAUqjmyNF3W8UrlmT0hzmfpLrJm4qmW5XYagQeVMAnzF00cIYasW5g0kIMo1HmGNkjku+w4KC0UH0xya8kfGVMPh8NTc5zKned+oWTRxBg8ULBjlHYXEtu5rh4ldeuMe4luHpUyB+YPH1us54djat8VWcOibRyiTJGb4pm06r/VBK7VLhmHpCS3ORuVeKbWDutA8E8jHnzh6zblpASlr26iy7WLH3RXLd95UaxoTRWxlUmWg+5aRhcdHs6kea7vDcMGU2tIE6my6VRzKbJdYBZ8lx5D0bHf+Op7ioKGOB9lU9y9gwte0OGhTADlZPIxwuDGpSz+kNe09QVuq47Ctp1Aave25o8WxbcJhjEGo6zQuDw7CvxmJ6EySU+x3+EEupvflIaTaVvCWnTbTYGMEAaJ1lYClipqLKKKG6ihUQDxSVKjad3ugJzG6x4xgqyCTACqHxdbs6PaMIPgjha4r0g8LJhmtNHs6rgRoBK2YenTpUw2mIagtQUugVFRQ81IshsgCCOyXmgiVGeqoGIa6t2YE9UFyUiU26CISNkW6oqDUINlP1AiSlp+oEzlpFb0qLkoKCFRBTRAwRShFUYeKtLqTAB+ZZntY2nDPWcIMLqVW52ER4LHQw7jVLntsg1YKn2WGa1aAlFh4JkDBRDZFBVifYP8FyF18T+Hf4LkbKCJqftqf9wSpqftmf3BB3AoooqIooogz4v2Y8VkK14r1B4rIoBsoptoog+bbqKw0rWKUscNitKGqgR3UQBEGyinkgIRBhAKc0QwKcXVYt4IgoHB3Q+qgKiCIdEUEEGqikKboAp4IqIIpuoogITtddVJgUGim+CtNKqf8LAHbbKxr4N1B1A5rhCD6Qiyx06p6ha6NUEwSoKy2ChC1OYHXGqqcyBcKi/g7xT4tQJ0LsvvsvT1wGV6Vdti10HqF4/D1OxxNKpu1wPxXs6mWp3Q4FtQd09NioOBjqlDB46rTLWsMyAGxY3HwKy1MVhHDvBpnotX2lwjqnouIb6+Q03jax/z8Fym8LrECSLrUQz3YSe5ULT0VfpT6XqVJCb+FV41ap/Ca+5bCvoKzH1WvBcZbuFofj6bgBAWOvgX0AC4gqunSdVcGtElXINjMS3tSHPhu0rbgKjXF7WuBBuFzjw+qdCHHkFswOEr0HBxAjks3FdH0yjQOR7oKs/ieGa32gJ5Lm47B1a72vYI5ys38MxHRMhrvM4nhnNk1APFHEcQYyhmpmS71VwqfDTTPaYk9xuw1J2RqVMxL32A+ATxhpq1eZqVne9Y3VH1gDOSnMTFkaYdi6h7oLWiQCYA8UzDOC7udzmG/wCkBX6DNpNphhu1pcWl7bz4BWBoY5jHAsa5pjIJLo5pH1QclbtmucHA5G7K2uQzEUqpHZl0yRcoKg2GgezzUrNYCcx68kz7BzHODIphway866nZCDSqU3ezDg4ZgJzeIhR47Jr2ECiXUbAXk3QPUEZmnuklpDBefNK+zsrjkcHginIze+US7IalO1IOa05JnOeijiW9pTEiXt+6mXO03QQM77WxJDz92PW33lRsZ2NB72ZwLWWeNdT5ItJnIZjOYpg9/wB6gzHs2GTlqOOVju+Nd0C0iIblJ9QyKWv/ALJ6TQapk5TkB+6Eg/BKyTTpAkEdkT9zqNPWVoAbWcO8D2YA7ESDrr70FHYtOBzmkwXs4nvaqVaFEvpRLs2rWjLKJaRw6mTTpgOIBePW1VlQZ8XSbmdVAEwBlhBScKBicjHPaIkBzr/BBjK4a+K8OYfVJ1V9BhfiqrmsaQ2BlqO0+aSk8swVR7Xtkz3d+Vk0worYunTY+c4dtBV7MdXa5zamHdLRJABsErgQyhRBqEzJaWwRHir6bDUxVSGOIY2CHG4QNS4nRMd4tPWy3UcdmECqCORXJ7JowzX5Wd54jmLoDB0nVXkPcAGggs0BU9DvjENcIeweLbJsrHjuvvycuCxuKp5TTqNMn1XG6sZxF7IFekR/VsmDbxBr6dBxLdtRosnCcOX1TUfo1bMNj6bvUqR5rYHU3UyzKGZtS0QgfC4iWzTEtzZfcr62V4GZ8AXK89W4fjKDXPoVO1pzo2zvcsPaYpwPeeQp4mvY0MTSc09m6WhO/EspsL3GABN141rsUwQ3MJQccZV7ry8t3CeJrVi69TiGMzXLZhgHJek4bhBhKABHeIkrFwLh5YO2qi8d1dsidVKQjqrBv7ktRzjTcGi5FkTRbmm/gqsU7sqRN1FU0g7DtHavOtpK1MqZxmAsuIxmJxJa6RAdsuphzXFbs6kFoGwQaZPJCTrATlAhRXO4i6qWTTlpbuN1XhcY92FPaWcNytuKYHUiZ0vbdeer4mrUeKTB3Q6AIWka6/avNN7Gkg6wunh3gUgNYss1HLTpNp1TlqEWCvwVB1Jr80d4zCgvDhF7JH1QGOLTJCtgQqW0WU5yjXVFCjVNSmHObBKYuIuBKOUDZSygrzugmISZy7oFcdFXUYY7qISnng5+dlndWZhqjWBpJcdUKlXPUFJjgHA3SYvDPq16RaRDT3tlRtzHkpJ5IgCBOym6gQ5p3QdVDNdU5lAtDiAQEGyg7NSaYVjklEdwQmK0it6QaJneaSUBUOuiinigI0RQlTZUHZEIIoCRzTJQigYKboXRQV4n2DvBcfwXXxP4d/guR1UE3Rp+2p/3BBNT9sz+4IO5sogEfNURBFRBnxfs/NZFrxfsx4rIoAooUEHz0OumDpKolNmi0eaqriA5L2Q2Sh3IpmuPigBpuBOhSEEahXtdITEg2KozKQFoyNSmiRoZQUjRRWCmeqUiLIBKfZJCYSiIiNUN7KIDCnNSFEE2UhFRApRiyOyEbIAgmhCIQQFNNglRJQWNceatbUh0g3WYG9k7T1QdCjiCCJ0W9pbVbA1XEa+y1YeuQZJ96lir69ItJkarv8Jqmpwqk6SSwlp96yUW08XQLRGaE/CQ/DYmtgnj2ols/qHLx+iyjq4umKuBLhciHX+K5YaV08DU7UVKD9wYWPJBII0KqqwFMqsDfJNlQZ6lGnVGV7ZCrp4WnReXU6d1sDEwbzTRip4dlKsapJBcdOS2Bt0/Zg6gFOGDzQI1nmoWBoJMABXRG6x8TrdlQDRq5BzMbXFWrlb6oXNxL8zhTboImd1e92VrnHZZ5a7DVJfGYg5IuVqItawDGZHMDg5ujLAKU+6zEU3OfvDWiQo9sVqP3cAj1aZg+9Skctau2X0xHqjvHzVA7RzsAGl7I/SNU1V3ZjDuDXsM+s4yhSJ/hz7tAEg8yhXbOHpOyvbBF3GyC4u7PG03h/bF06WQqd3EPaD2JNPSoc09EmIeamIozUbVPJliPOU85MfAHZTTg9oc2/igOj3saDTBaJa7vOd4XQd672tBANRs09XnTeU+HcBiqwk1SQO+0SkaScxFwa3qj2miA0nDO1pDshqOljfaDVQHIach2Uh5+7nOLiJQpH1KgEgFzu564HMqCG02vFndiSDSFyT+ooA7M0FjZBbRA+60I/qVhd2YxBLnsIbYUhLZy7lF7IDmthuYNbFP1Tf8x21+SjyGYfEQ5zA4x2dNvcOg1hAKlNraOEAYymXPBDwe9526hM09rj3SXVgxou20JXtNPEYYFraENJzF2YFSg4DE4mqXOcQfXpi2nJQLTDThcRW7Kk7vHvOPeby+aZxPo+Hoh7XNLhLWtlwhVFhbwyTSbLiIfuLrS+pOIog1g8UmuIdSbMaePJAQTWxpntqjabLflIJ9yRhc6gXmlm7V1nyZbsJTtEDFPqE1K7byx0GAJS0g4NZSHqy0ODNDaZnnoirXgtq06eZpNFsTTbodACo0XrgWD3ZYbsdJlQvGd3eD2hoaP0kCTBO5ugHBtNnQfmsDaYjcyUDtsQA4MbNv0jr1sPioc0XEOiwcNDGg5SSENRYkzYc40jorKYNSoA1peYBcJiWjvEE8wQERXUwtE5w1hZUlokm4Optva6OXE4eDSqiq0zYbAK8GWtqMcC9rXVM2Um50aTz1HuTtGYtY8PIltPMQBlJu63JNEw2PzEMqNc13IroMoMqtJi5MlYatDtLO15xcHT6adV0OGOc5sPkGPcpVh/RmjZNTw7ZFgtOXoma0Tos6pmNyttonHJADZGFBIuqa1IVYnQK5QhBTRpNpNytbHgrOabzSlsnXRUTopt0TR1QhQVkSqHYemDmbTbm5rTAUVGOph2l3bVG5nt0haGmWAwRbQp4EoaBQDZKUQ5rtCCoRCBSLIJyByQcANECJTdNshZBnGFY3EGqPWKsygExElOgRsgVRMlQAobqwATcIgN2CIvoezCZ3RSmAGBRy0ipyRM7VLugKik6KbIDsp1U8lAqDujsgEUB2RQGiIQFHdAIoqrEfh39AuT811sR7B/guSoAmpXrM/uHzSlNS9uz+4Ijt7IoBFVUUUKiDPivZjxWRa8Xdg8VklQDZAooIj5qDzRmyXdSea0pwUcySVJQWh45Ih/vVUqB1uqDSH2smFQbrMHQiHXUGsOBCkNdyWdrrIh5lBcaY2KU0yFBUKcVAbFBUWkXQhahlNigaTZQZo5o7K40uV0pplUVqDkmy2vZTKgEIJ4soGygSFIsrMqmWyCqFNkxCkWRCwoNEYUiNkEBhWMfBVSI1Qdbh+KNJ4ItyXfqhuKw7a1MjtGXBAuCvI03kQu1wvHGm7K6C06qUdhmID6tPGtj1stVsaO/zqrsQ0Cu4gWd3gsAqBuMDAR2VfunlP5T7z8SujB9HbmkuZYrIqyqFtpRJDRLlix1Vxp5QYk2hVWms8UqTnnbTqq8LiO1e0P7pcJATiiKuHDXkxCNLCU6b21CTmYNyg1BqjxDSmYWubmBkdFViXEUjlaXE6AIKcI95qOpvmBoSuXxepmxRbs2AtuEZXFYvcHZdbrk41+fF1Xc3n5qwZsQSaYaNSbpS4NpVWtqCLWc27rKVjLmjeJQDobVa54bmaPWHeNlpDVBD6EsDZ2YblPTLW4uqHOdTBaP6iq3shlA5AwSBLTc2VrSGY53eLJb+e5QV0hOErwxkAnvE3RqtHoNIgVCZHrEwpTaHU63cpuue86xRqD/p4l9Q6d0i3yQPiRNbDyQRMQyxCcNycRblBEs/7hlLVpnPQMMaJ/7eq0iiX48ZWipNO/amN/BFV0mn06q4l0x/20aFKq5tTI1oOY99xh3hor6VA08dVmaYyiBRGb6K9nDatLMKuEZUdUOdjn6uadDEf7yUHPYKZwJLc7Hhru8Get4mFBRdBY1uVxptAbTEg+Jha/QK4wbsEPSTXNjT7F2sz+lPUwdZtNrXYTs2d0vaATmANzEIYyBhc8sytjOJpCzDbWY1VYJ9DDM7+8+OyywPW2MLfUaw1WhlPOwd4MDMgboN9dVmr16LcLQY+uH5XAuawEaA7+aBXxTxrJyUYp/9wzNyq2tApYupLzLnQ5nqlVVeI021nvosLmuAbDiZ96zniVbJ2bAxrTtln5piN9Kh2gpNp0i6o2DkYJzdT1WzEYSsaxrVqtKhmZEPqNbvoRrC887G4lzMpxFXLyzGPcs5dJmVcHqWDhpa9mI4tQpNuQ2jTqPv4wJQNfgDHOL8Vi6zTfJSohgmNbkry+ZAulXB6c8Y4Gxzj/DcTXDtRUxGXpoBrCZ32mwLQTQ4JQBJ/wC7Vc9eWlSUxHo6n2pcZFLhnD6cmSRRkn3rO/7Q4tx7tLCsH9NBo+i4klTMmDrHjmPII7UNB/SwD6JP4tjpn0h0+QXNlNKYOj/Fsdviqn/7It4tjmiBiqg81zc0BMCmDpjjOP3xVQ+asZxvHiP5h3muSDdEHdTxg7bPtBj2n2gPiFpp/abFj12U3eULzuZMCnjDXqWfacn18MPJy1U/tJhnEB9N7fOV44OM6pw5Txi7XuafGMBUsK2U/wBTSFqp1adS9N7XA3sV4BtS4WiliKjD3HkeBU8V17tA6X0XmcLxfE04Dn5x/VddNnEG4hkTkcdROqzhre2sxwcWkGNVzRi6gqF73dzPDQtGAZ9ySY1Oi0djTBzZGzqirBcAjdI+zTKqp4yjUe5gdDmmISYl57E98Nnc7IKMI4NxDgH2OwWp1ZgqZCYKx4TDDMajambqFMTRLq9PUEGZQbygleSynNrBZ6GKNaq5oEwg0lKUHVGttIlAPBidVAUExQKAb3QRJjVBAEQYNkCoPWCI2U/UCjlKfqBR+q0ilxlKLpnJN0DBSUAigKgQCIQHdFAIqgohBQBFMoNFEUFWJ9g/wXJXWxNsO/wXJUATUfbs/uCVPR9vTjXMEHbGihU2QVEUUR3QZ8X6g8VjWvGeoPFZFBCgoUER811UUUC0qKKKIIooogJQkjRRRA4dOyIKrCKC0OjUo5x1VUlGUF4qFWNq7FZQ4hEOi6g3CoIuna8HYLAHmblWtqQg1lrSlDNoVTas73VraoQKaZCGWNVeCCJlGAgpAMKQrSyRb3KZZ2QUll5SlqvLR4lKR/hBQRdKRsrnAzolLeaqKiEJiFZAhK4Ai2qCNIV9CoWvCzEEJgSCg9DRqGpSvsN12qbzUqZsxPbsDpPPf4ryvDsTlqZT6p5r0eFeHUHBrpfQM+LDv7zHuWVMWiYdNlVWp5yGgkCZmFpxLW5muBHfEhKD5oHp91gF7WUqGWEaAiFGkHdFwzMI5oMODb2NR/3wyzodVp4gagwzsrgNws2G4cW4lznmWnrqt2KwgxAbmcQG9dUGfhWIe/DudXdIF1wapzVS7mZXcxzjhcL2bWwDay4JMlaiKnkZnEiQ0Kyk2o/tRSdc6h/rRCzkjPV1sRedLq9jiXub6+Zxlsw421KoNSnT7Ok6mAGggGPWJVjR2NV9S7szNf0Cd5SZpAeXZiMvfaIPgAlJk3ZcNcRGovfN+yKdrKDnVC85mZ/aiJNv3Kdwc7BMbUkHL3Q24PjySAk1DUziQ8RVA0sLZSrKbf5YkS2Wu0uXxz5INLKY7Sm4BoqgidcmnONVrp0ScQHtYXOAIeHZgNjYlt1XQoSCwsg2PZhvcNtScpWnsQ6GloqXs1zAGN8DkCirO1acHTp02vFKnmlxLg65EwMvRSsWVWU6j6Z7NjWgPiXGDyypRTD+9kLspPfewBzegGVDs/8AuZXCfzhozHoe6ourxWb6S19Vpa1zjkYIMzsZZA9y52JxGDwZbUdTBxAbAZTiNd5bI8lZi/5fDVKjezZciBBz+MAdV5iq6TqrIlrTi+I1sU6XnK3k1YnG6VzkhNlqMmJQJSF0qSqhpQSzspKBlEqkhAwKiWUQeSAhGUsyigZQGEsoygYFEFIjugebozdLKMygcJgVWmlQWA3RlIDeEZQWtcrWG6ztMKxpCDZTN7FbKT72XOY5aqTlKPT8Mqdph4ESDdaagcR9FyOE1cmIAmzhC7ZE2XOtRxe0oDFu+77/APSruIGn6PkcDLxAC2NwtFlY1IAJVr6THkZgDGiK5eAacJhCaggla6dUVgHMjzWXiVN2ZraboB/KSmwdOuHDO0NaERpqPygNO9tFT6K9ry5r4DtQthAQ8UVlGGa1+csDncyn7xJ7oEc1dFuiUiCoKi6rJkAhHMeSdyUoFJPJBxcQU6B0QVNa5ogEQrG5lDomaL2RGymPuxug8aymZ6gS1Oa0ih6XxRdqlQNyR8EN0UVPJFBFAUQgoqCjKCIQMNEd0FLoK8V+Hf4LkldXF/hn+C5RUAlWYf8AEM8VWrMN+Ip+KDsg7KKWUVERQUQZ8We4PFZFrxfqBZFACh1RKCI+aoo2UWlRAhMhF4QQDVCE10I1QLsijCkXQDdQaokQplOyBVJsjGykGUERlCFBZAwtCOYpAjKCwPhM2odJVOiIN0GptUiyuZWKwh904eQVB0BWtdWNe3dc5tTqnbUPMlMG+Gu0UNMcgsra1xdXCt1soGdTVZp2VwqA6ppaU0Y3U0pbAW/I1wlI6kNldGEjmgGytLqR3VD2lt1Q9JsGQu5wuu2nXpuf6p7jpOx/zB8lwWOK24euBIdoVKO5xZrvQdw/Dug2vH/PzXEbjq7NKhK71F/pWDaajrPBpPd12J/3ZeXrMdSqPpus5pgpEdBnFsQImCtDeOPEZmg+a4bT1ULirg9B/HnEy2mAPFbKHGqTm/eNIK8m191aHxuQr4j0vEMVRxGGPZvFtlw3TJlV06hJN002OqSYKCJa8wDcXm4urg6SR60vPd0cbak+apYPu6jsoMDU7eCuYYcRBMuByu9Y21lAQS6HFwJY1vfiC2+gTBpgkXs4Q31j4pcrchN3EMvtlA5JzGfQuJfsYe6156IGYZe5wcHAQc40b5SrqLDmLc2XMHjM0Tn/AGVdPMe8SHQ0GQLMvuJutNES9rojM4jtGtku8lFbqOHy0WtNHKHSezF2nqTCPYQchpNdERT0Y3zi5Rp08rcnYsDjqxo7p/u7tv8AhWiGva2qxhEg5exJAPPRTVK6jmeJDSRMPqC7fAAKNbU7Imn2b6kQ58Q6Ol7K1ocJNVtBpg5X5c0DwSsJqUSczKwkeq3KfiVByeNVHUsPTogBjKhLi0Onl1/bzXAeV0+OVu0xmQS1tNobBM31K5DzdbjNAmUsoEobLQKEoKXQGYUlC+wUCAzopKCiAyiEsptkBCZKFJQNsogEUQUeSCKA2BUBQlGUDBMCkzDkiHNi4UDyJRm6UZeqYZf1EeSBwUzTKRsfqHuTgfpcCgvabrTSKyNDpiJ3tdX0nIOphqhY9rgYgr0kdq1lRpsQDAXlaLjZdvCY2sKDW08HUrNaPWa5o8oJlc+moGJqVTW73mOS14CoalA6w0wCs9WvVqyDwvGXsS1gd8iraNdtGkGtwOOpga5sM4D3qKufRY6oHOEkaJ1jdxjANdD65Y7k6m4fRNT4ngKsBmLpGebo+ag0oKNLXyWuDv7TKnVAEsJkIQKQIS6JihAQCUqYofJAEzdVmrYplOoGEGea0UyHAOCI3M9mElQ7KxnqBJU5rSMztUEXc0PFAZRCAR3RUR6oIoCEUB4qKgpgEEQgKKARQU4v8O/wXKK6uK/Dv8FyjqoBsrMN+IZ4qtWYf8RTHVB2UVFFREFFAgzYz1R4rJqteM9QLIoIUqZBEfOYhGAngboEDZVSxyQVkRcKZd0FcKR0VkIxbRBWhsnyqBqBFIT5VC1Am8olMW2QhUJCBCtIQMboK4U0TwhBQDdRGFIQBQqRspugMwEzSlUQW5oTCp1VOyIQaRUMKxtYxqsoMokqDYKu6cVyLz5LCHmE+aboNorggSny0qot3SVz88FMKhnWyDS/BvYJaC4KtstdpdX4bGPpOBaV0mPwnEKRbUe2jW2dlsfFQPwZ4fUdRe8jtR3RNi5c/jtLs8Ua0Edrc+O60HCV8HUHaCwPdcNHeBW7jVKnieH+kN/uLRq06H91ZUeVDu6pINlW7uvIBRBWxY3VWKtpThBdS9byTuPdceiSj6x8EanszO6BaQzMfZju5MnbwVoIDIjUNIa/V3nOiGHgvawBj+5+e2VLOVga5xaHMgz+aDsoLcrnNLSG5gHA5tG32KsiTGU2cCAbPNufJI0FtQNIbZ0Bjh3QI1nmo2xAfmyuLbOs51/ylFaKDQ5gkhxZu0jucputtKo5r6bgIa51qguXW5bLHhzT7FweW52E5GZrtvvddFjclRr3ZGON3VIuVBtcXOph1KjSLCTLS3LPkVeKzRXZTDQ0xZmSJ+iDadOpTYTTpOO5c25+Csc6iKobmEH8pgA/BRSUqha55fRLQ6bggz8VmfWFWs0MdnZH5HwfmFrYylRFVxa2nmmCCAD8RCyV6jXAvzsqhrCSKbwDa/6vFB5HHP7TFVXiYc866rESrajryTO6oc7ktxlMp3sgco3JSkpZVD5xs0eaBedkiKA5jzUkoKICCigogYIpQUUDIylCKBpRCQI5ggeVEsqEwgZRCygKBlEJRBCBgUZlKCjsoGBsnaeirBTA9UF7XEbnyV9OsdHXHVZQQd1Y3Xog6FKoIsYXb4NiaFMPGIrMZcZMzonWV5tltFppYf0p4oZsue0xMLNmrHsv4ng6Qzel0I/vCI+0WCb/APap/Fee4fwfBPqtwmLplmJcYYXViKdQ9CBY9CupU+zFOiB/0ztR/wDixBJH/wCxasZF2ug37Q4J8D0ikZ5uj5p6voGJaHPweHqzoSxrh74XlsVwnBNaWjD4nD1XGzKmZpPhMg+RK5dHFYjheIz4eoS2btdo4dVfE16HG8Io18QH0cOyiOdI5Pkujh+BOFMdnxPGB0aF4e0eRH1VPDcfS4hh+0p91zbPYfyn/QtTyRprspoqrYDi9D2dTC4tnUGm8/GPis9XGPwpH8QwtXCt/WRmZ/8As2QtbMXjKVMljy+PyvvP1WnDcUFUhtWk5jubbj/fegxUqtOtTz0Xte07tMpjor8Twfh+MeKzGmjWme1oOyOPjt8JWGrhuJYKXODcbQG7Blqgf26HyuouLTqgVThcXQxVPPReDGoNi3oU9Z4ZTLiYCI5uKxFJ9SGtLnArbRqZcKHi3ilpillzAAjoqXFuLL8PTlrmqo7mGeKlBrxuFKqXA0XUcJTpvIJA1TVddFUZjoUp8UxQRR2RQEFEIIjupspqgI6ooIqghEaIDRRAQmShFBVivw71yjqurivw7lyjYqAKzDfiafiq1ZhvxDDtKDs7KKKKibqKBRBmxnqhZFrxmjVkN1BClROiCDwCEJM6IeqLAAolD9EcwQNHJCEA4HRHMgkIwgCmB3QDL1Uy2ujKMjmgTLdQhOpZBXltZTJKsBQhAmRDLF1ah1QUlt1IVpF1CEFMKZSrYQhUVZUQIVkIRdAkclFZl6Ihk6oK7pgrBTHknawckFIaeSIB6q8NANkSBMiyCnKeRUDSLwVcY3TDQWUFEnqrKbyJvurCJExcJWlp1ag6GE4nVoCHZalM6seJBXdweIwuKpVeyJYx7Yq0zfKL3HgvLtYx2llpwwqYes2pRcSRsFMHOx+GdhsXUpnQGxGhCoHVdvijBiOHUa7Ac1GabgOWo+ZHkuKtyoYKwKsaJwqLqP5uoRq+zshS0KlQwwdSoLKR71LMZgkd8QG+aNOzi4SB2hbnBlumgEqNa80ge8XB/dbHNQWe90iQ4S5v5TpETqgc2aO6ABBA1brvyKspua6qGMa+o0Nh8dDtyCpMNEHW1xoSDq5anwKtMuDnhwIAp93fnKKal38NXayo1jQSQwiXRymV18LRGQ1AwsIFjM+e65VNr/RcUwFwyhxykdNJK6WDYRhw9tB7BFyA5zvGMqiuh2QdTZmaHmZl3dKsc2a0ds+9wCB81UW1TkY6gagIkue0g/BqYB/ahpfWAiS0NlvvLVBXVaKIBaHNJeJJd3fdmWTjdd1PhFYjEte4gCGWsSAfzX9y01KbySSHsAcJcajvHQiCquKMfU4RiGuqPLSyQC3Lpfc9ENeFfqqirHawqyMp1W2S+KCJKioChRIMKQgEoypCkIBN0RKkXRCAXRup4IoBvqmkoIoBJUvKIRUAvKl04UiUCy6FJMpwjCBJKknkngQjCBMxRzEBPARDUFeYnZNmPNWhoCJpg3hBW15nWysZVUFBpi6YYbk4+CC6nWnddDBVjTqB7DcLk9jUabCQvR/ZTBmtUq1qnqMaWwdyQR8lL9LHSoV6HFcIaRblxDWjtKZ0d/U3p8ldg+N4nAP9Fxr3GlMU6jgO7/S4/X3rncS4bVwFZmKwj3ZWmWuAvTPLqD/jx0sqUuM4V2ZjW4tjfvKU+uP1Dp8tDsVzxu+/t6WlxNj7VGHy/Zee+1fC8NXwrsfgMrarL1aemZsXIHMa+EpeGYp2He3CYt0tNqNZ1v8A0PXl7l1nta5pa9oc06g6HokuM48BwviL+H4wVGCWnuubzHJezpY2i94pVBUoViJFOs3IT4bEeC8PxHDeg8Rr4aZFN3dJ1LTcfAhe8wNTC8V4FhWYmkyo0MALXbEWkHUG0+avV/JzNWHlCoNVoqCmXQ47KmtQxeABdhKhxFAaUKh77R/S7fwPxVeGfQxlbtGEiqyzmOs5vi1ZWzG1lV7Xd3MI3V54g1rQ2sfOFWdEjmB3rNBUwiviOCw+LcK16dcDu1qdnDx5+a4uMxOIo0uxxrQ4j1a7bNPKeRXeI7sLBi6XdcHAFrhBlXlb7UYGnFI0y8Em9ir8DhfR6hJdLiuMW1cE8Pw2Z1Pdk3HgVuweMb2rq3aZ2PHcG605vUUr02lV1VMCXHCsLyCbmR4qV9CgzFBElDRFEaWRQTIqIoIoIioIUVEhEaKeaiAhFQQj4IKcV+HcuUdV1cX+HcuWdVEDbRWYb8QzxVZVmH/EM8UHYUKKiCKIHRSUGbGeqFkWvGaNWRAJQRQKD5xPNHZAC6IlUGVFIKgCAgoyVIKICCA9UZSwUYKBvBNKrupcDVBYCpm1lVi26k80FshAusllSUDZrdUQUnVQFBYpKQX6phJQRENJ0TBkapgLwgUMgXTBgA0TG6At4QgIASEQjnAtKQ1JkAFBZAAUBv0VJLypkcfzFBaXgFB1RtoKryHdN2YhAe0B1uiKoiJKAppxTbrAQRtYAxJShwBPKU/Zg7IGkALIGa+6vp13UnhwMEXWTIQUYcBzHVFeiZUpVsDiWUmt7Wu0DLG45DYrzDwWuLSLgrbh8QWw7MWlpBHj0V3G6TXmljKQtWbLwBbMNfofNWJXMbrorAqm6q0aQtIupeqUKxs2OaNL1Clras8UFwJdSgkkNdYyQ4yifXdpmy6/+OD8SpH3LmlzZNy47dE0ZjJaM8mA/kdyeainzMa+CcrYsXNjNvLhAndWNqkuJlxBm5M577XskFzSdnmRBNUCAmpvLaDsjSRLszptHvsoNbC99NzCBuMpFmdZvK6FAVBTzkFzi29Tsu9PhlWDMKlZopspVKeWwI9XTe8ro0gW0Wucx+nr9kc/kMlworUO0Dg14yy6Mop90mPzHLb/AAp2lUWIl7WS2mZDYnYx1Tg1GZW5CIMwynId49yyDalXKKYpDMaZ7gByATzy6oEe57u0DSTlJAzAjLb4rLjB2+EqtL2y5rg14sBYjTN1P7LcKhNR3de5xc3MHZreFhPgqcQ8Clne6oGsBeHAEFsHcTpZEeCqAtGWIO87KnLzK14yv2+Kq1jq9xcspK2gQhIUmyWUBUQlCeaAqSgogKISo+CBlEAogO6KG6KCIoTdEdEBCKFrI+CAhTdQfNT3oGGiZKDCZAdlAgjdA4+CcEaKsJgUFrVYNYVTU4QXNItK9h9nazH8P7FrQ11J3ejedD9PJeNabr0H2Yr5MYaZdDajSPMaft5rPSx6Z7GvaWuALTYgiQV5ziPDamCrtxWEc5gaZa8asPLqNr+C9Lsle1rmlrgCDqDcFc9acJr6PF6D/umtrt9rR5/1D/fpN2Axr6bmYTGOLibUqxPtP6T/AFfNUY7AVcJWbiMG9zCD3Xa+R5hMex4phHOawNrNH31GbtPMf78darifaygKfFGVWttVpAuPNwJHyyrrfZOrm4Y+luyqT5ED9iuNx6tiKjMPRxHfFLNkrzd4MWd1Ea7rofY14y4ulHeOVw8BI+oVv0z9V6N4zBcjiGFD3h4LqdZo7lVhhw89x0XZOirqU2vblcJCzGtcvC8VIe3D8QDadQ2bVHq1D9CumRtC4vEsFkaczc1J2hKowHE34F7aGMcX4Y2a83czx5haz+GXoFTWotq2dNuSuBDmhzXAtIkEXBQ1WRy8XgnQXUhPNq4j2uo1hWoi4Mubs5egxmLfTqAUW5jusuJ4fVrMdWpsGbUtG/h1W5Urt8FxtHG4BrqRh7BFRh1YVfX3XiKFetgsSMRhnZXjUbOHI9F6vB8Qo8RwwqUzD2gdoz9J/ZLEP1Q1Kb6pYuophoiNJQHVMipCkWUCKCKKQognvTIIxZUEIhAIhBTi/YOXMK6mL9g5csqAKzDD+YZ4qtWYb8QzxQddEqIIIopqp4IMuN/KspWrG6NWTUoiIEo6hBB86hRMApF7qqEIgIwpEFBN0RoiNFEAGibdARCMogEBQtkhFRAhUFkxSxzQEXCMgpdNEUBtsoASi0SeqYCJQQMVgEDVQO0F5RkFAbboA2KBdeBEpC3MYQMao2ulOZ3TwTNphOGoKmsvcWVgA2CYNRAvogXKjlTtCYWKCvJZEMVqO8oKsiIb0VoHvVjWgorMGlWBqvDATrCcUAbWQZsgOqU0oWz0Zx0CIw1QbEhBzX0czeRW2g04nhlaiSc1MBzfLX/eiZ1K8EQmon0eu2oR3dHA7hBxRYzunB5K/iGGOHxj2Ccp7zTzB0VDbbLbK9ns56pX+u0EJmeog/2jL7oLQe6DuBry8eaIAaAItAgR3SZ35ICREkft1TGBNiSdvqVFGmS1tMy4Q4jM8yweAlXgA0sRJk3IINj5SqW5ezzNJs/1ge77pV7WE1KzIznLMyRtyCg0Ne1z6F2PJsA4aLsUxlpAvpjMAe/Tpud8cv8AsriZQaeGu55Dg3K9hDdOcLt0WhmFa4A0yNRRYCD55FKq004fPY5ZI9SkTm/u7lt0op2NPsaYLQe5k7vmcmqbKSczKdMTElrAHEeGRO+iKb3sbTpugTlFMZD19VBSGhziOyBILTDmw1vh3Fy+OYmk3hzmtOeq52UkiC3wsJELpPZSbAflcDl+6exuVp6WXP4vgfSKGcVSQxxvlBtysBO0a76b2I8gUhXZHBahY57n5GDdwIWWrw54cW0yKkCZC0OdKBWp+CrMbmIaR0cFUaDwLt9yCpREsdOiGU8lUCUdlC0jVCI1UBUlCVAeqBgillTMgZHZIHXCbMOSKMo+KUPHJEPHIoGRlJnE3RzBEPdHqq8wnW6OYc0Dg8007KvMCjNtUDhyM87KvPB1UD/BBcCiDdVZtlA4WQaQ4c7JwVlD95unFTqg1h110OF1hSxtF5uGvB8bri9r1VlLEZXCJ1spR9QqvbTaS46KmliadU5Wm+gC8a7iuJLQ01XxMwefNPT4i5tQVA7aCJXPxa17I5XEsMHmCuPjcHUw1duKwrg17dCbgj9LuYPwXNp8YdSqPcJLDpJuOS3M4wKlK8OG7XckyxdLim0OJYKpXa0tcCG16RuWOO4+c7+9crgs8O45Ta94FKtLMw3B0+MLXinNFbtaFRrZBY4EWew6tPMf7ZcWuazA6lW7zWkgOmfjv4rUS49+RqECvL4L7T1ezZTr0g9zRBfJl3U9VvpcepOrAPpvh4sIFj0Ph8uts+NNjruaCC1wBBEEc1wOKcPNHNUpguonUalv+P8AfHo1eL4WjRbUqSC94AYCJjc+AV7cVhq9MFlRr2vER9CrNhuvPcM4icA/saxLsK42/wDxn9l6UEOaC0ggiQRuvOcXwHo1TOxpNF+lvV6E/JHgnEhhqgwmIdFBx+7cdGHkeiWflHoOyZJMCSrmjSEACLRCsYLrKuZxzg/a0nY3DDvgF1Vs+tG468+fjr5ihiKmDxLa9D1hqDo4civpFMfdheP+0vDGYeocVQbFN5+8aNGnmOh+HmukZdPB4qnjMM2tSmDYtOrTyV+q8hw3HOwGKz3NJ1qjRuOY6heuY9tRjXscHNcJBBsVmzFMEyDUYvCKMKIqIJoFFEdkACKim6oKbwQCIQU4v2DvBcw6rqYr2DlzCVAsKzC/iWSkKsw34lnig6qiPkgeSCKbIoIMuNtlWRasb+VZERNkEZQQfPZRSSeSMqqaVJSyhKBwQoXe5JKBKB8yOZVShMFEXB/vTZlRO6koL5S80oceaMoCbBETZKOqsaBF0DBu4TZuiEEBDMgaQehCUu5FITm0smAQM1t1YBBSjRGeaBwjZJMJpCBwLIwlBJumB6IGAE3RypcwAuUvaycrAXIuLFCQNUaeHr1I26laafDJ9o8lTY1OaxGsG7pfSQDzldujwmkY7snwW6lwKg7WmI8Fnyi+Dy4xmU80zMdHReuH2aw1T8uU+CD/ALH0ag7lWD1arsPF5mnxEDUrdh+LMYRIBC11vsVitKPZu6hwHzXOxX2X4pQv6NUdG7WyPgrjOOxTx3DcWA3EUmg/qBgq2pwmjXol2Eqh/ReQfg8ZSMZHSnoY7F4Z/dfUY4ciRCZUxt4xQqNpUnVGFr6P3bp3GrT8/cuXC9DT4+zE4d1DiOHbWa5oEixtpoubjcCKLRWw9Q1cM8w18QQeR6rUqWMzBDEr/aM8U7BDErhNQLSL2tcGNe5pyuJgkd2d5PO4TAECwJJJ7sjN4norMO1zqFUADKIcSRoRzWnBYN9dlKoxrn03kyBJNgL25yorK5hcx5HeOYd4WA8ltwuCdiK73PAc3J3TUES7YCy63D+HGhXdUNOn3WR2jrxI5b/DRdejg8NhyO46o5olriRbwGymjg0+B42rgcMajMzu0h1M3DBzNp35LqU8McO12He2hmeYaWhskDUgm/LdbX4p9+wawMaQ06Wk7D5/8rHiGup0w4uzVmVMzXExynzOimmUcVWo4V1Ko1lR72M7MvygNiTPjr0TGnUq1MlQNa0sDg8DNLZA9XXor6z89KC17qLnd5rxtA+tkoxDi9jWZWNAlnfyxOwjz8uUJq4x1OGNLg51cFsyMozSNj4SE9LDMALakvaTIktibj/R1WjK7C1c1Wo4d/Maee43vsRpfor20aJaHsLgSDPNpI1/3VNXGJ3DcI6k6GPGY3aXW8lT/DMGGzDAYgNAJ943XUfIcGFrXVNJFgZ96qGHdkPaATJkub6kTEdPl8RNMcZ/B8I9/wB3Tg7wJEdLpanAsOBJb3TaBYhd2C6W1JLzZzmEh1umsIPFI2EHbqPeprUjzNT7P0gCWNLhzKzu4FT3YvUvZpkqHLvLQQqy1r2ai3Iyp5VZI8q7g1LQskqt3CKDTemPivSvpi4F76lZ30omR4KeVb8Y4B4XQB9kPigeHUP/ABBdl1MRp5qss1snlTxjjnhmHIvSASnheH/8fxXYLbXhL2fRPKnjHEdwqiJEEeCqfwlv5XuHku+WGLAKvs1fOnhHnn8LqN9V8+Sqdw+u3SCvSmleyV1Pp5p+5Wf248s7D1mG7CqzTqDVhC9UaI/M0JHYVjvyj3LX7iftvLweSi9C7BMP5RZI7hzTPdEK+cZ/brhBx5oyuseHCPVCrPDLWEK+UTwrnbaqea2u4e8CQSVWcDVHq3V2J41nUJVrsHXBs2Uho1P0GyuplKCU0o9i+0gp2UHE3QwmqupNOYOGy0Mw7T6oGYbc1c2m3lB3U0wrQTzBKtaWCzwc06qxgFw73bhQU2ayYU0wTdmovvyUbXLHSAA4Wc2bFPkho011/wB2VL2gwI8EGum9xpAtbI0Efl/wq69bO2HMkN1AWdj3snKYCtLs+WrmLHaZm2QN2TGhzmNBE2+f+EmLMPcym77ue7G26vc3JJaWluuZpt4xsqqzQaRc31+iqMZo1qjy7vPOkytOErYrBPFSmCQ033Csok0wHC5i55qxrwGGlYZjY9CNEHfwuPwvFcO6m9ozEd6mTr4LgcSwpw1c0y37s3YeY/dWYXC9hVzNeZW6tVZisM+hWFxdrtwpmKs4DxJ9dvoldwNSmJY4n1mjbxHy8F3mPAjMYXjqeFrUZdTcWVGkFrxqIIP0XquH4mnj8K2sGtDj67R+UrNg69Eh1EELBjmNeHMeA5rrEHcLoUGBlAAaBYsX6yI8JxTAnA4osEmk69Nx5cvEftzW/wCz2PFOp6FVPceZpknQ8vP5+K7HEcG3GYV9J0B2rHEeqV4x4exxY4Fr2GCDYgha+x78RKNlh4NjvT8EHOP3rIbUHXY+f7reNFlpAipAU3QTqFAEfkogig+KiiBgp4qBTZBVivYOXM3XTxXsHLmFACrcN+JpqtPhfxLPFQdZRTwU3VEQRUQY8bq1ZFrx2rVkRAKARKCD53aFEFFVQmVJJUQ2QFBRSFRFIR3RQKjCIBKMIALIhSEzYKBmtlWZSEo0UzOF9lA2aAk9Y9FCc0BECyAiwRCiiIMxZFLuigYapxokbqmmBKB2kQgX7MuUrKbqzoGi6GHwzabZIkrN6xvnjWejhH1TNSQCuhRw1OlENBKta0AQi2xXK9Wu05kWMHRaKTATdZxpYrVSgaKauN1BrRABE8t10KMHT/lcxlVoEgSJWntywTGnJaZrqNJAzECVb2oaJ81yH4gZWy4uMWvopTxDic2WGi0xcq6zjudoAJNp+KZtfYa6rkPxJYwE7ct1BWa9r35nlvqlsmOkha1nHVqmnWjtabH5tA5oIWepw7h1ZuV+AwxHSmB8lgbinMc3LlcBtJ/0K9uKGeDNr23V8jAP2f4O4QME1k6EOd+6DPs7w1lN1NoqFj4lpcDf3K5mMAAz5rdLJa+ImC3MTIF7NA8bpqYxP+yeAqEllWpSB2IBj5LnYv7MYfDMc7+INAjMCaR09+i61bEtDHuGVo0JbaSueXjEVnFzrOAGZx8lqWs1jwXDezpgBzmZpLXmwkAm667XYSjQZSyRmaAXMs8XveDb/YS08BSp1gR2rsQ8CW5RaByGqqfVNRrmvPeygNdoQR05ESgNWsXAusW54IJi02Vpc/0fK2qXOAjvO2i9/cqKbWCmWmXte2BGoKupuGWW5ZAh3QrLWNVTKXis1tqsFzX7nf5+YUe6mSzM0OgmZ/dZaeJyMyuAdT6CC3wP7ymfXk5cxc0gw3KT5WQPPaP+7dECIsImdh/uqJ7hqABgD7td+k262/ylbXHYuaXQW6tdz/3dAvDh7MzqCCpq4ue9j2t77u0/pgAcoOvxTsDaTiRkDCLuDRIPhaVipFwqllVoaQZAmPJXDECqS3K/ONCIjzH+U1cbBVa6m3OGZo7rolN6SA7MSDBvH7rK0vqFrXuAJ1JFo96NOoWzldF7QJ+P0TTxWkNqUsxbmpzZzRMOjpoqSGAAcz3id/JMA59IgkZc0jLt79FW5h9oQCQPWEi31UakMTBhgIbpdUvJBOg6BHncEn+mPKVU4PiC6Gg7FZWFe0a+apqa3BjwVzjlBaXAGLc0oIL4a1xDRrsEVmcCRl5dFW5sm3mtTgHGPfzVJAv3iOaKqcwZSAkyp3lrbAylzCJE+CKUtEdFMsp9RI1UGygqNO8wEIV8WSxzQUFgid0pbqVeRulPwVRQacoZPcr4CUC+tkFOQaQgWDktBbuqybWRFPZyEewaU8xbmi1wBAQI2g3cIjDMP5QrpBIOya2pVRm9CpH8qR3D2G7QugxsnZPltCupZHGfhCw6W6JDSLpvfaV2nUwdVmrYYC4Wp0zeXNyucwgtIcDc8lGucCB0Wl7O+CJDhuLKrKQdJWmFgpueyGDNBsEr6ctsJV1Jo7K5EjYqt7nMJBIJKCgMgXBuj2rqYNN4BaDdhMT/ALOvVQO7RpPL/f8AfFVVAXNBAJLRBRF4axj5pEmmdnfIqqo9zKroFnC4O8qsVbZSI6q6i8ZjTdA8dCFpEc2KOZjpmNNE1N3aYeAJdsOqXJka7K8Fp1BGn+/7zVDc9N8OaQ10gyNeYQbKT5p02ucc0SAVYyuB6wsb9Sswk1myZB/N+6rqDPUJBRHTbjGuJ7QRAWrh+NZRqNq09HCHidY08/3XCc8lukHQqMqljGhuszdTB7/h/GMPiPuc0VB0idf8JsS4F9ivF4Y1HFz2ggG1jodV1cBxNzgKdYSdiFLFjrkc1537S4OC3GUxrDakfA/T3L0IdmALdChVpMrUX0qgljwWuCkqvG8IxxwXEGPJik7u1P7SdfLVe3EGCCCCJBGhXz3FUKmExNTD1fXpuiRuNj5iF6z7M4z0nAGg72mHMa6tOnu09y11PykrsKKIrLQQojysogGyKigRBRCgUQU4r2DlzV0sX7By5p1UAVmG/Es8VWrcL+JZ4/RB1CoodENVREVFEGPHes1ZFqx3rN8FlUQEESoqPnHkj0U1KiqgipFkwCBYTZTEqRdOEChqbKBtooVCYQGwKDkJ6oSdkETtGyARHdKBoIQeZsFHPIHNBlwgjRe+yab2Q2t8ECUBlSdEpN7IhEN80wuEg1ThFEGFbRpGo7eEtKn2j+i6NGmGjRZ6rfPJqNFrNFobZVi2imY+S4u2Lc0KGpGmqpzCdUC87BMVpY82JN1YzEdywJgrF2oFib8kWua0kwYWsZtdFlW4zPvynRWnEiTDyGyBAGq5GfnpyVtKuxkEySOiuM66xqOc6WOaY5IvxD6YzTlAdcgd1srFTxLy13Z0xmIsAL+8XVTcTmZVz0wHvESLRfTw6Ko6fpQe0hrgMrpLouRy+BUOPFNwDR3Tr1XKdiSwdoDAiMoRpB2YEwZ/MUHQdWqGoCwOk6LWO1oEZ/Xte58ljpVHsJkNa1txmcAfcrMJWq1cQzDvmnnqNguaY3H1ScpesdKlV7z6riQwNi5uZmfKFzsTWxGNqtbTc2lR5kwXeAWmq6pQOMY9zXjtOynMWmAZnLpBIjXZY2VKxa9rgC1pkMaQQOtukrc9Mbq+kCX5c1VoPfYS4gtgWv0+iJqVHU8sS6c5JO6qYGPosqPYe1pyNYkTP1PvUxD4Ap02gHmHTupasi6rifuGC7g3WNZWYVnl4dkLmvJiJJ5wloYmkSWPf3+eXugq9rQXS0gjXu6KWrIvbkLQQZAuCmc4tLspzBwvaCFQA2m+WAwdQT8VZUZImmQJIInY+OymtYFJoJPZv7k3zbe5RrsjnZTGbWRr9UjYM5ZaZuJ1WpjAQHNBkmCN00xW0OdUGZvdidIK1UnVRSZmzu7NvrSbDmUlOo0AszS07EgJxl2bdhkAkgn3a+9BXVa/UhjgDaT+yIl5a6m493XKNFY9uduYAwNgDYLOHu7SA9trEkwo1i81W5SAJ5gwPeN0vaOGXPSa7kRIHwhKQTVnPnnZU5nB0N05Zk0xcXgiT3S3cb+JUc7MXEgEDkP9KzOc9oJaWjkJJSSRBDi136puprWNZr05DjYx4/4VbqpJt6psJWcOLnFxqA3uSoTBIa6RNlDF7q4EmDAt0VTqkd6JPPkqzUyyHk+Q0QzscO6Dl3vdFw7nuINsreZVRN7C3OErnCYkwlLi0bEc0DZtbC6TLBlKXg6KAkiEU+a0FHMBfZVqZgIBQWyoVWCo4nzRDaJZuoCCEqCEpZGqhN0JVQc4GpgKsu5FLUKzuqZRdVFjnxYpe0sqnVQhmBFiriNLKgabjXVO2qQTaQDoshMhAOdJumM66+HqNfy6q4GD0XEZVc14h0Lo4fEB4yuNxumErWIJSuGYQmjQnZGFGmSrRFiNVmqUi2pMrpFmY2VdShIEarUrFjAWydIKR4BMkW2Wt9F5BBAkBI2k5xnKfBXUxnFB8do0NI8dFneHNcSWkEbLpilkMx5IPoZrtmOSupjkOYXCY6qsTvqNF1/Ry10flOyqqYHNMCCr5J4sIrua8SA5u4KL6mUwwDsnaA3/AN1Wg4M6QVRVwlRkiCVdiZSCC6QcvSVUanZ1jm8kxY4XMkD4JKkus4eCqYY1Q4WQzg1AQbhUSWOvore63DPcR3iQAem/0VRc7F1G1XPBjtAQ6BGqvpYpoIcLP6brmZpsStfDzSD3mrrl7vig7uD4v2VjLgDdp1Ww8XpQSDUHKwXlxTc+cjz202bHreHXolbiKguLEbLPia63E61HG1WV2U2GrGR8j12/Qjn/AKa+Du9B4ix5eQ13dIjUHUH5rEyrTqtvLTyB0UZWE5X94c1cNfQPC/VRcvguOOIoNp1HBzmAAHcjZdUXWGghRHopCKCm6KgQQbIwoLogIKMX7By5hXUxfsHLmKBVbhR/M0x1+ir8lZhb4pnig6pU02RKUj4qoimyOiGyDFjvXb4LIteO9dvgsiiIopFkEHzqEYU5qLSiBKYADe6UGEZQSEZQnZTqgMmECQChKh1QSVAgOqYBA4RSyoSYQA94ymbYQg2IuoUBNmpZQJPNBAZkpwk3Ti+qBgE7GlzgAlZfurdhqUN01WerjXPOrcPTDRK0WAsladlJaFy3XeTB0NygSAEpdNouhoboAULjSyJISkxebKxKTK4OzZjMp21I1JKqe6NUGgkTJJ5BaZXdoYsYCbtS4BpymDMxf3rPpNk4qBo7wEdERqp4nIZHxRDw4kt3Oyz5u0holoPNbKNJgoxTJPOeaCzD4drgO0cGjmXAR7yE1TD1qdRrG1A5kBzHs0I5j/dlVRa6vVFNsMH6naBXjF1KDH4WqMwp1CMjvynQx5/vCsjN6W4WjSdjWUq5NQvcA4Zrgn5LVjHNrYmrTo1ctLDQDcXufeJ+N91z6JmpmY/s3kjKGQ221xF0MRUZTa5jabGwO6CLhaZ+1wxD6jbknK4ktmJtYjqed10aFPsXAVHdpScAczW3HOeuq496YyiZcJJGy6VEPbRDHgBv6jt7lKsgNqBzcjRsT/hZsY7M4RMFW0mE1srTJF4VldtJz2tEExBBEf8AKy2z0gztCxxFtTGpWxgaDkab8x/lZhSZ2piOoWmmMrrxCasjVTa0gZiM4MyrMoDgCQJStAiWlsDqne5vZthkgaOi5+iypX0W5gWZRGtiZ8kwp2B1nQRc+STtWEDtGy4eqT+31QdXYGjKy8nXvfP/ACmmLi1tSlIqBsGDa/zuqBVgd5+ctMSqnvDzLnAeUKlzgWkhxDhaNiEXF7qjS/WI0g3CVlVjXEA5esrIXSDBPVL2kC4nx2UaxrL4N6rgdRe5SOqZZOqzFwzCbnmhnExPmhi/OTEOB8lC4wfnCznWx8UQSdZsoq1zwBcADokLiQLwkJOhUJE6SiicwN5ulzknvEmOajnSNECTrIQEuJbBFuSrLj+pSSEHRGmvNAwcbXlQkzM+SSYNkZmyosDjAIQk80k2hQFBcDbXVTQQqw7qoTogebEqTukzSrAUZCCUC0pgQFJ6qxms1VuXXRY6y6NUgtgrnYgRPVaiVmc5pEFIx7mkgmVVWcQZ2SiqDZ2i1jOtzH5gYKcOvqFiZUgwr2PBF9UwWE/eAnxVtOsWu1jkqCTc9FWXkmeWirL0OCxEwx29wthaNoXmqeIcIcHw5pkLu4PEitTuL8lixqVoERyRAmfqjHuRA6rLSBrYkoOpxfLBTifJMAL3lXTFIpB3SeiIoAHRXgRflogCJu7RTTFJoNG3+EuQTzWhxlsTZBt3Rp42TTGQ0mg2+SDqIdciVrIBCQtvZNMc6tgmk2FisOJ4efy2hd48lU9uYG1lqdM3l5Wvh3MSNa+owU2tJi8Lt4jDh5NrLn1KfZusIA3XWdOV5xiqUHN1a5oPNNhsJialQClTm03cG/MrSa9NrbgE9Qo/FuqxD4jSFWVhw1Q0yx7Cx39Qso6m57H9o0dqBJdrm/c/7zSU8a+n3c7iNS2bEpjjQ4mG3O3JBidTLCZ7pGyRjiXkSumXMqhoa4B3IhV1cMGNFQAAmxjQq6gcPxlTDVgWE+/Ze3wOKbicMx49aId4r59OQmLLucDxxpuDS6GuF1nqNSvXqdUtN2doM6p4WGgCmyMKFUQXUNlIRQUYv2DlzCupi/YOXLhQBWYX8Sz/AHZIrML+KZPNB1IkiT0RMqaRCB8tVUCOqOyhvt7lDy2hBhx/tG/2rIteO9dv9qylRAQR8kPBB87hRFBaUUFFJQFAmyk81EEkKIeanigKdqQXKceMoCTdKL7ouNkLABAwKBKCVxKCaqbIeCO6BmlWNSsHvV1IZnJSLcPSJMldBohsKui0Nb1VotZcbdejmYiHNGUCQTZRQ3SOBNkS/ohKCs20QJnXZMQldAHRbZFpBumBN4GiQctU4c4NnbZELmdUaM7oaNLTCgawCQZ6quxnMYVrabiAS4Bp0AcJVRZREmWiep0WgYtz6RZVylrbWaBHmFjqkZwynU70aFawzMxodlZSe0HOR+bceNvkrIxelWKeW1mtoOAFSDrodIKsqURReWh5f3y3NMgkaqmjmZWLTM7SpUZUDMos1rpsbhaZa6VKo6lSrmC14IaRvGoPIqAE1yQGztIVWCntctMODb5wR8VpxPcrU6bcxOWxAmfDopVjSCabGuqBznvHdgoVavo7WGoBlNgJ0WbCVanprS2bgzIJIJVuPrPex9J8WgmNlluLe1DqjMhjM4AzY6K4Ymk6pkcGg7ElcjtMjMkzBkSmqOFbvNeC4a7Soroisxjy4OY0GzhEielrLQMRTLIYZdsI1XE7SWljtfmqzXcxosQBYFMXXeZiQ1sRblrPkUjsU0A2gnVceniSWd66hxBDrFZ8WtjqvxAjM28JTi293MDB84XLGJIJlwM7JRiA8bt8VfE8o6xrBpkaHmiXT3i6wXIFe5Bd011RbXymHGRzTxPKOoajdJN0HE6i4WIVp7p8uqsp1JtN1lqL5voiHQYKqzFSTCNLc06FAuMWJVZcQAg1xLuigtDyTdEEXEqsmdB4KZu8inJPuUm9glDoN0zSAdECk8tFCZPRG26CBVCdIUkG6F0EJtKAKhkJSdlQ4dJUL5dbVVTZTP3oRKva5EugdVTPX3Ih8qsrcwJndNmuRN1lkZrI54mNVWavJm+iw4kzTdOnPkr31XhuoIWPEO7UQBAWozWOqxzWB2rXfBZd11/RHupXPkufiMO5liLhblYqolzIWinUlohZ6bhDmP8ABBhyviQlhK6AdDdlQ933g1hFhSVTJkaEKQpqdS4N5PNdLCVw14vcrkMccgMm2kq5jzZwF1akeuw9YVWjmrhBXEwdf1XTrY+K6rKocAZ3XGzHWe2iZPRMDyVcoZrKNYsLv1OJ2Qc4NEi6qc8iyTOd7oYtFYIh8wspdeVA7SY8UMbA7S6OdshZm1BvqnDwSguLQVU8GDCbNYQQgXAqox1LAhc+tSDnS+4Oy6Va3WVhqwSdlvmufUYq2BcQHBmUEWkgfNZXYVwMEj/9wtz4Z+UOnUEarJUo5g5wAHQldJXOxUaFZrbNDh0IJSBp0LCDsg6nUB38ijTLj3XSeu4WmVzHlzmtbsu5gqHpdJwFqdME1HH5LFh8KDfMAAN91txL/ROFDD07GpJcRdQc+thKJqHs3Zv6ZhVUh2dQZAQAdNUlMVA4ZKZgfmNloY9oDqgMOboYsUHq+DYgVaAZ+YLqQvJYbFZcQx1Nxph4gEH1Ty8F3cJxEvd2eIYGGPX/ACn9lixqV0EITdUICip5qIiyKDPi/wAO5cw+a6eL9g5cwoAnwv4pkpFbhb4pn+7KDqDyulnkjpbqheFpB6wfchAJRNh1UttZBgx3tG/2rKtWO9q3wWXVRA2QRKCD55oogVN1pUChKBUQHwU2Q0UQRSRuoogLdUwsEAiNEAJlQoKIITZKSUXaJZVBndMAkTsUFjFtwtO8nVZWC66NEQwWWOq3xNWiIsmnqlBRXN2K4xcJQbXUN0vvVDEqeaAmVDogBmFS8u/KrAHE30UcJ8lYzVTS5sm8lEVHO1PdHRCoZGUW5pcpsGrUZO2DL3QQNl0sJUwQpZK73N7QRnaxr8viCPkQqi9lOixjntq0nNactVl2c8rtoM9D10WfFQ55LMrR/QABC1I53pceH0BWcX45jQXHs3lhyuGxJ2T0wWDI+oCJsWusfLcLIxlV4IBLgNAExYGgQTm5rTLU5vZVu0ABqAzOo8whTac33rdRYgmfcqmvzsPaOJMxqtRDqjJFSSBbZTVwrcTkeXNbkJkdHDkhWqHuPpkiAhnJYGFkltxI1T0XCpU7zcrTsNAVK1GZ2KJr5gC1x3FlpdWa+C9wHd2MpcXhmt9VuipLBmMDwvqo0tazPBYBe4cqiSKueSD71fQplpBk5eXJPVoh3q6gyCprWMz8wcHJKh9bkVqNAuYOmyoqssZU0xma4tkzflzSl2aRN1Y5hyyFRUY4c4ViUXEhtzog6vmEGJ8VTBJhyUsym2i2zVwrEd19wN07ak2mFlmHSUxfewTE1tFZ+YBzp6Lax8tDxr81xc83BMrVhqs2LjdZvLXPTrMdIB+Kedljw7zlcNSNloYYMHQ6LnZjtOtWTOt1AY0CE+5RRs4dt8lJ56JJtr5qSCIUDAkmxkdU0kBVxtonBsEDTcDZQk7boWnryUm6AO8ECrDBF0rtICBHaJDqmdeEhsLqgE31S7qPMhJeZlVmnCMhV5lM1rKoZxg6qtz9uqDjKpc+DdWM1a+q5o1kJ8NSFR4kWWXNPgV0cECGkqpWsMMd1thusuKw7arCYutwrNbTyxJ5qh0noq515nE0jSqERBVRJgHkurxSmLuG2q5YNoWkaKRGVLUMGUKPqoVCcyBWgn3mFbSAgbqlrosBvsnBJ002QdbCmCBNt11qTrAFcnDmwgXhdCm6+boufUb5dJjgWhAuWem8EQnzdVzdYsJDh1VBmTYpi5QO1CCtxOhQzA7qx0KpwgqiwORz+SoLrhNmCC01IuLq1vaPYHNaSDyusjniIVbar2GAXAdFZGa01Z5GfBZntLvyH3KwPe18Od1idFH4rUZGRvcn5laZY61N0g5SDGkLM9tW4yFaK1dx0cB4LFWLtzK6Rz6U1hUm/ulW4UnDU3VC37x7S0TsOazv1urKZ7RzGlxO5WmMdbAjszRbU7ziM7jOn+2VXEsU2rUJJgN0Eoir69YwJbDRyC41V5qPkm0qRFlTEPc7WGjRoVwrAUg3Um9lj1NlC6H22Wh1MEe+28wV1fSiaTwXdAuHh3lrC/QnuhXmtko3N9VKPRcK4y2m5mHxJOR3qP5ePRehDpANiDuvnNKtDmuGukFeu4HxAVqTaTjOURO7eXksWY1K7KAFkCS11/VKYWHNRVGL/DusuYdV1MYP5dy5ZUAKswn4qnf/AGFWrcL+KZ5/JB09B/hDy96PigZ1+SqJsiIhDW1yoB1ugwY/2w/tWVacd7YWiGhZroiFDwRKCo+dIKEyoqqKKKIIopKiCXQ1RUGqBwoSIQChuJQDZDZEIFApQChUQME7OYSBWM1QX0hLgui2IWChrotwNoXPp14PKDnbIOMBJKy6CTB1uolOoTbWQEmAlEqG6Bs0qoaZ3VL6hJyt0RcYbGnNIe6VUtEjLqkrZmmBIciRm7s+ZVDnvYS1w01lakc+q1VcYatNjKrGBzd2tiepAtPXU7o9rVdTADLDeNFRTFKoe9nEchK0AFozCpMGC1zSCFtzHDue94DAcx5FXPaZAqsygCx5rOCc8sdM62WunTIpZzdosQCpWpFRc4sfSbbMLjaU1DOWZT6w0lQNdT7rLsJmOStbleR+sXKza1IZriWlugOoVtOm00yREH4KUwzNmAIOhVlIZQREmdAs2tyFqSWNa+TO51VT6OXKQPESr6tQEGRulJnqprfijQA2AmEpDJ0siDz31UXBvOpWd1PMTMrQZKQi5Qxmc3KYi2ioqAFa3ifFZalpKsrNjLUAnZVGw6q6oCFnc6V0jnYV17IA3UMoRC0wI11VtM5TISRaSmYL6oN1GoczTpNrLew94RssFJp7EHWDK20agiYF1y6deWgiSIQNtfNM29xuESsO0VFERKJEHSyXRFMNEwKrj3KAnNOgQWAx5lNN1XO5RBnSVFPsib80oNpRJ0RC7qp470BWmdpVdybj4IKX23Sz71ZUEBVOMC5WmaDriPipNolCZUJ5qoDuiy1DDpC0O08Vmq81qM1GuJK61Co2nQBJXIp6khHiGJcKLaY3F1qOfVX4rirgYogHqszOJ15vDhvIWNoLpLWzCDszYzAiRYFbxjXTfi24ljw6A6NFzZglVtdD83mnJkkzqoL6VmQNVXVN/FCmYaUrjLhuii0xEc1czURzuqBfRX07QOQRHVw+lzotjHdeix4c/d25K9hAiZK5115bKbiG6q5rpCzsKtHNc66Q5N0AZslOmqWTKgckoEiOqXNeCl16oDIJRAA5HkqjcI5rQVQXCxlRrst7TslJCBIiysRH5XTuqnMBiGp7JKjrdFqM2K3spAS4mf0g/VZqrrEABvgrH38lTVv47rcc6zPi8p6Ehsx61pSOEuACYVLECy0xVznn0d4J0tCwTdav+2dpKyGxI5KxkzSmpjM6SLBIDIVjbQBoqNTKheQNAEMQ6RA3VchrCfckmY95QWB0O8F0+F411Ktma3vE7brktu9XYOv2VdrtYOhUo+j4Ou3E4ZrtczRZXU5iDqCuLwGu17ajKbj3TmaOQO3vXaZeTzuubavF/h3aLlnddXFCcO6Fy1KpSrMJ+KYq1ZhPxTPFB0zzmOsIGL2hMbkXSnxlVBiALoDrqjMXA0UEASfig5+O9uJ/SFlOt1qx5++H9oWVEBDdEoKo+dDRTZRGFVBTdGFIQBT5qQoghUbqgiNUDIHQIygUAKkqJSqASogVBzUDt5lWMMGVWFY0d2UGuhrK1g9ZWWjEXWgLlXfn6G/NBQqE2UaKSSRyTTAugEJQML6qO0S/mHRBxvdVAqGYPJUvOkqxxSZXPeGNiTJEmFqMUWVA4diaY71s2Yg/t8EHyyGdmKrYtM28wf8ACQgmsGV81PLY2uPJWtqV8M8VKNdp2zMMELpHKlY57WZQ09d0zK9RkgE97W6lXHYmoSatao/nJlIXh4zEXOolBoFSmR3Gva4bkyFaXsgObmDj1ssoczLYAeaGXQtdKlWNmZxYJIzdFA60g94bqlr53hOyCL7rFdI1UK7y7vwW7QtQN7Fc+j3XETK2N0B+azW+RqS4GEonKESbwhMLLYPE2UYZaEHSCY0QBgyN0FySZnoiDZCxuECO3Wd91pMETKoLZCsSstRgvKysGZxstuIkNJESslLWdF0lc7BdSA2sqS2JlbTdpKocAToVdYsUzHki0xHMqGxg7oER4qo2UHPbUg3B+K30mgMEGxuuRTqOD296wuuhTqB7gb6LNjfNdOnApgHVMegWKjWJMEiNJWwd4arnZjtzdK4bJCIVpHMIEclGlM3jdRF4GwSze1kU0iLWTMPRVgz1TXAQWTa+qOsEBIDunaZ/4RBAsg4XhODIULRB5oM72rNUC2kSFnqMgSNlYzWbdE2QdbSUNRZaZB5VL781Y66R0hWM0mgWfGTmaei0agqGiK9Aie8NFuMdRhoue10U3QYvHKEuIqCoWENDXNaGmNyN0jg6m4gggpSVpzAG6tMxqq2NOrlYLuARVhMMN1XvIuU7jZK0ZTe9lAzBeY0V1Id+DzVYGUR71bRvBi+pUqunRPclaKYtJGizULQ2FqaOZiN1zrrGhlwrBoq2iBZONJWK3BcTCrB+aZxkQk5kFRUJUJKE3U3VAde5U2QJUm6IhJQJnRQoFUQnZVuKZVvNirGaqeqHnXmrndVS9bjnVDrBVzdWPIkqvmtudWPdNOyzus4yVc8w3zVDruViGbp4qymJudlW0pwbKoZ5lwE2QBElISSUQgcGGnqg2cwhAlATIQeh4BiDRxdNocJdLbr21BwcF80wVUtxNIg3DhdfRsNUtTJ/NafJc+o1FmK/DvC5cLqYr2D1yys1osJ8L+KYlIT4X8VT8fooOmbjWEul0xOmiAutInPVCByTbkoCxMoOfjx96P7VlWrHe0H9qyIiboJkPBEfOgjCikQtKimqiiCIGERqlKAbItQKg1VDIO2RQcgGyBRlA3QKVAgmGigZtyradrKlpjVWtSrGyjpAV50sqKGivOi5V2n0AUlCVOqKhMKTKBUQGdOaDtJUIuke47qorc425oMzl8sIlIXFztLBP25azIGMI55b+9ajFGti3vIFakwuaIkDL8lRbMC5pjcSkeTqhJ3JXRzWOdJ3jYJm3N1XmmyduqgvbEeKcEiGNb7lS0x4KxryHB3yUbi7sKjTDmlv9whOwEOy7bJqdapAD3FzeRMpnOpuADZCw1ILRDgZ1WtptGqxsaZyzK0MGgBiFnp05OYB8UJuoTeN0P8AZWW02KAAAJKDnQLaqp77fO6qVaHwY5KTcFv/ACsheA494p219pVxjyaTcSgdLhIx0jVWm7ZFlMXWPF+posbIhbcTJEQNFhpwHkLcZrTTdzuEtUTpayVpyuTvd3TzVSxjqToQlznTZM920Koi8hac1rTaeS006k+HJY2lXU3iQ2bfJCV0sLdpB3K2YerdzHzLd1yqNd9MgOHdnVbKNecQ8gDK6CVix156dEGYSOMSoxwLbGyrqPvGyxjrqAl7oaCStDOF4yoMzaYH/sFXhqrWuXZw2OLS24IUHDq4LFUT3qTgqg4zcQeq9k7JXpyInkudiMIx1iwR4ISuGwzur2iYBVtTBZDNOSkDS03CgLWhuiMZii0CboxA5oKC2NlTUAWsiZVD2XVGCo2JKr01Wqo2xELM9tluMVWUjoTm2iR60yrJT4R0PIlVuBVbXFriR8lUbK1KlUMuaCsVSlQpXADncjsmqVnEQDKocDuqzYrdc2TMbAkotaTBKsI8FWcVuElKLuk7bKzLJTsYN7nbqoYXJbvG/wBFpojuwBqkFMF0EiOS1sA/KFLWpF1IaWnotdMKiiIsVeyVzrrFzSjMpGm6J+Cw0JIhLKiBhACgVCpZUBTdQ6WSzeEBQJCO8oGUCEpHHZO5VOK1GaR4tcWVDytE6giQVRUbFxcFajnVBIuNZVcd080zj3kAdQV0jlTOvT8wVQRBJVxM0jCpN45KoAuYTOsoDeUpVQRpdMDZLOwRQHQIA+9QqDxQXUCW1ARsZX0PAVRiMCxzZGhXzykQO9K9t9mahqYCowkd24WOmuXbxBmg/qFzSug78I49FgKw2UpsPbEs8UpTYf8AEU/FQdQ6IbC6J0KX8oE2WmRjyQ35owJMkKGNLIOdj/aj+1ZStfEPbD+0LLqiFKihUQfO1FDKm60IopuogChUUKBTqo3VRQaoDKBTIHRUKgdEdkIsoFvsiNUEW3QOAnZZVqxpQbKBsrzos1I2V8yubvALksyVDrZQdFFMTZRpvohMqQqglxy6pHGyYiAq3ExfdCqtNVXUPjCY+tqqzmvEx0W450ryJOU2QaTF9ErpCgJjWy2wsGsqwX5KpqtaDyUWLW9E7Gxf4JRtorWiBqFluRYxsNkE9QrGNgAtJBVEvbvqpTdBi/v0WWo1jvWIlWUpBWYE8ytNN2hhZrcPVJid9lVnkXsrHkEW+KzOIOiimfVAKqec7Tl1SuId6qzVnEGy1IxaBeQbhQVCTdVOfmF4kboN1C6Y566OHcHEc10A4Fi5WHIzAbldNnq2XPqe3ThmxFzIssJtWW2vcnksR9qZMqxqnOicerBSiYRp6qss1VpzGyrWrEAEjmsjmuBWo5WDG6hiZafeg1yaJEhVFjXE330V+HqFj4GhELK23mr6QBcOalix2MM49kGgWUrUnBhcpgoyw7Zb3M7SkQ0SVzsd+a4orOpuvot2HxEwuVjZpPIIIKPDK+auGE6qXn0vn7e04dVLgAVvqUJEjdcbAS0jUBeioODmwSsyFrk1aRFlmdTEwQuti6eV0iPJYi2TELN9NT2xmgdQUmUhdAsED5qp7ALJq4wuYCbWVWXmFsqMIVDgFYjJUZmWapTgFbzTiSqKlO8LUqWOc9uoVRFoW2pTuTss7mlq1KxYzOFoVORwcSIgrURJ0SuFrCy0yzgADqq8suklXuaEkdFULGyIEJ2Nk6fBO5sdE1FUBMANZnqi4Cb3QDbS1BaxrdB/ytlIQ2IWGkwz0XQpjui1ys1rlcwQd1ckAsrByWK6RJ96JU3shKjSWSlEmyU3ughOsIbKQhpZEExCXVQwogiBsjGyDhsiEcq3J3WVTjdaSldoqybEfBO691U71d1uOdZn2d0Si7k7jLYhVF3LRbjlT6NIVZ1hNMjmk1PkqguOiG6WZN0wsFUEKeaEqRogM2R1hCFBcoLKfJen+y2JLarqR0IXl2mHdF2eD1OyxLSDBdZZ6WPduEYNx5hc86LoEzgPJYFyroUo4f8AEs8UCmw/4qmeqDqeY6pPzckx3uhHjqtIljqpoOahFp08lNQTpzRHP4h7cdGrJK1Y/wBuLatCy7ogaqIoeao+dIqbqKiKKIaoCgZ20RUQKpCh1QQNZAhTZQ+CoXqodLqHVAoFN9ERZSbqSgba6fwCrCcGwUGiib6rSCslEwb7rWNFiuvP0hQUN0JjxUaGUAbwgURqghNkrh3UxE6qGIVRnI719UucUzN/JO/XqqXCZWoxVTnZjLrqTrCQpgZW2DtKuDlQ2Fa0ypVi4GSrGjxPgqJV1N3mFluLmtLuZjYphTE6IB29kZd0IWWlgbAAGiup2CqECDzCLX7KWNQ1UnwVJMT8073G8Kh5I3SQtJmhxCqquCJIJgqqpMxIW5GLVbxeRog215QIN40CIJlaYbcMb3C6jLUrhcnDGD5rqNMU+ax07fHGfEGD/lYT7WBotWI1nZZGgl5spGul0qyk0EyUg0ur6bcrM0qpjPi4BGUrGXbFaMQczjZZXC61HHr7EAaqxhjXdVAK1jSVWT5YjkrqcWtcKqCCAVpoUp8FK1I3YZ+Vl1uw1ctdAFlzxZqvwsvqAc1yrtz9LuM0aVaiHBkOOp5rk8HwFWrjAQCGt1K9BjcKHFjc4DSASeSajVo4dmRjYHzKeXo8dro0cO1lKZEjqr6eLbTJE9FyKmNJ39yp7ckk396xW/F3HYnOZJB80gqtLrLlNrToT1VraptJUa8XQc60DRI8jmsoqk6FAv3Qxc8A2KzFt4Th9rozfZDFRaZVT2HX6rZllqUstzTUxzX0zm0hZ6lKSV1nUQRIVL6A20VlSxxX0SDokLHRourVwxus7qBlbnTF5c4sI1QFO9gugcPe6gpAbK+TPixGnGyVwkLW9uoVBYZVlSxnJtupTBkjVWupgaC6LKcEHRXUxZSZ3Zjey1U72NkjANIVzR0WbXSRYBsmbdK24Tj4rDSSRCCkqbIpTpCBUKiIinipuogBFlFN0UASn4I8kHe5VFb9wqnXIVriNlU4+UKs0rhZUVjaArzoqK1wtRis7jCqcLkbJ6h0gpHGTK6RyqH1Es2RcRpul0VRGhNpzQ3UJlVBRCUIxZAURp4pUdTCCxtyt+CqlmKpuGywCABbTVXUXRUlSkfSKFUVcBUdbTZZiqOC1+14c8EaBXlcq6QpRoD+YZHNQo4e+JYorpygYjpzR5gg8kCOi0ym/VQATCE20Rkmfcg52P8AbD+0LJ0WvHz2wn9Ky7ckSgpuoUCqPnM9FEJUVBlQIKIDKhKChKAoKKICoh4KKgKKFRAvyQlEoeCBwj4JQmQWU3Q5bW6Bc9phy20jIWOnTinKESjElTTZZbKBeEVFEEF1W4kGJVgEJHi6qEIJMkqmq0huYLRoOqorGGLUZ6ZSbohKiNCVpzWAhMNQkAMJmg6Iq8BWAOGipZYm6uYTNio1D5ojRQPIOZxJ6Sj2ToGhlHsXQc0WUX2djwTeIV4c0Wt+6ytbOhiOaem4B3MqNSrXA7hZ3esYVr6hgwI8VSTPQIVU4mSqXODtSrXXN0govd6rCR0WoxVVxzCgJB5qxzXNs5pB6qALTLRhvWC6TbMEclzsPJNl0xAp3XPp3+NjxGqz0z3yNea017ukLI2RU6apGquGt1oJijos28laWgOpEdERznuklKE1Vpa8jQKvNC1HGrW+AVrSAdBKyhxKsa4AjWVUbGgOOkTyWmk2IWBlXJa1lqpVpiN1mtyxocFZhqgpvk7KnNLYCBK52OsbH4t1R0k2SF5cZWUG6tYVMalXg3srGG/JVNgiFazWFGlrTeAnBv5KsGDcppgKYqxpThyqaeSMwbKCzMBqi191VJTNMWOiC7ORYKB5VQcpKi4u7Q7wg9wiypLoQLkTBJCpcL9VYTKR2virEsIQqnwFcqn6LUYsUOE3VZaOUq89ErhGy0yoc3YhQSrTqplBHxQRogxCvbY3VTZ/wrG6IsO34JogDmgCICM7LKoAoTZRBFCNUqaLIIiIKeak3QTZTZRRBCkKaUs/BVFZCQjdOUDCrNUnRU1DLSr3LO7eea1GKyxqlOoT7pHWC6OVKTdDxQKi0gkoC6FyU3KUQQEZQ3UAlAeaYWS9ERZA+aGq2hdwWdaMPqg9n9nL8PqEbBblh+znd4XV6FbibLjXSFKbD2xLPFLsmw9sSwxuorqHVLO8QQmtpCUfFaZQAXiPBQaTuhMWEX6I3gAIOdxAff6flWU6BauIR24j9P1WU6KpQKCJKEwg+b7IyhrqoqCogogKGyiiA3UQCkoCooFAqAVFCggBQROiEckBGqYeSQdNEwQOFpoOWVWUjBWa1zW1QqNiFFl0Dqpqo4wFAZCgkpT63gn30SHVUDYrLW9WZWqJbAWSqImQtcs9M6YD3qG+iLbLbmYAqxsQLKtpMq1uyiw0XmNU7SQUzYi8Jmx0UaFjzKtDy7uxqqpkw1MwgHVRpaGbHRMGZbgpmwRITtG2qzrUihwMaKsttcLaWWJVDmkkhqspYyuYIsq3ghtxZaYdoR7lXUMGSAtaxYyk8go0Gbp3TM6JRrdVlswzYcIXRy/dwR5rBhjJ+q6JuzaFzrtwxVdbrILVCR8VsreCyEEVFY1TaLRReQIVM20T0ZDvBEVV6LnPJAgLK9gaYGq6VZ/dKxa1CdStRy6ikNhMAR3uWicgFyM0w27Q4+KrBW3uraRuqs5cdI8LJg4NAgyixvpGQrCLSqMLmcMxVld+VpAXOusvoWxNlcwXXMZWNOpJuCbrp0yHAFtwVLG+asbrZXMvqq2gRMK1g56LDosTAeaLWlMBAU1QiLBGyg8FNrhQTxUUlSd0BFlDog6VJMIBqjslc6EM0ySUBJtqlc6fJAuEJC4IGnVVPNkXOtZVly1IxUQ1MKZjBUmyrIBnVENgXv4otumGqAAeSIF0YRCKKYaIBMVFBQqC3gogWPigm6IHoiBCUzKfolPigiCJsgRZADBSpr81HaIipyXYhOZSEQtM1U6VQ/qtL4WerYrUY6ZnawqXclc/VUuMmV0jnSnkFFIQK0yKkoIhENoptKmyiAhTUypE6IiwQEaq9gyx1WdaWCb8kHrfs7ULsJWp7i4XSGi5n2ZbFGq7ctK6a437dIBRw/4hnilKah+IZ4qK6mlkDa25RM+SBMG60gzqDslbqjrspPmiOdxD246tWTwWniE9vc/lWY6IlBSVNkFR84UURsqBsooFEEUU3UQTZDdFBAQihqUVQDdT5o7IIIbJUTKEIAj4oKeKB53RBvMpQioNtF8gBXxusNJ2UjmtjHBzVix25RwQZuE8TsgBaVFK+YhIRBvorErh0VQshZ8QJvCvLSBoq6gJmFeWemI2KZpkIPF1GarowsaNFaBKQBWtF1CGBAlESTZOxgiU2X/hRooadpKdjYNxdCSIvYKymYJPxUaWU2mZ08Vopgi0aqukCbkXWmm2+9litwuWUuUN2VxCSLKNYoe0AH5rHVEkrdUbuRcLJWAGolWM9MrmtBtKSBsncC4aQOaAF7X5rq4teFEXXRHqbLBhjEWXRiWSudduGKrrostQAOBtqtVaJWOo7vQOasWrDpEq6mMokxdVUgDc7q2o4ZdETWau/MTGgVTTJytBk6lR8ykzGbWWo5WiSB4qvfoiA65AN0TTdlBA3hVkW3EKyhTzG4sU1KiZAj3LfRpQxjQ28ypa1OdVgGm20pXku1utrqQhZzShxlY12xifScTZasITTEO0VmSTCdlK8KWk5aGGbrTREmFnZTIWlkhc66RpDQBdAC/JJmgaqGo0DWFF05HhdA2VRrSgXkmNAmJppAKOYKqUpduYVw1fIG6R1QC83VLzaVSXQmGrnVRrdKa1lU58XsqnVIFlqRm9NHbTugKgKy9pzQz+RV8U8msutoqy4KltWZFkC+Uw1oBtzRJnx3Wdr/Ipg6DOyYmtO1kzTzWcVLq1pJHiirNUQJNko16lO1RTDojEc0ESooHS6G90YlTdEAi6BROiBQTUFL0Ch6qSgkKGD9FApvdApUO6afeli6qARIVTuYVpsqjdVKrdKz1T+y0OF1nq3JWox0zP0KpPRXPtIVHiukcaEoAIlRaREQOaI6KIgwEbIKbhAyEoayogZokrTT18lnbqujw/CnE4llJoMuMKUeq4BTNLhocRd8la1pdQbQYGMENY0C2iylcq6QCmw0ekM27yRxTUDGIYT+pRXWdrokAHM+RTGbBCDGxWkS23uUvO3vQBN5U0Ez0RHN4h7cf2rLPkVp4gZrj+0LKdUSoUFFEHzlGEEd1oQ9FFFEE8kLIoIIoooCgCYaIKBUFBMhsgHkltBTKFAhUITGPNKgYH3oi6UeCIjVBYOa00Hxqso0TscQbrFjfNb5ndTe6Sm4OaDKf/AHRZdAOhEpdExspE2QVZtbKqobQ6QrS09pbRF4AGq1GK5zvWsmDMgBeYOwCZzRmMCyrIuStua9hBEAKwHKNbqmm4AWPeVg5osWtc4mJTh40lUlEREqY1q6xNrq5uVuWDcqik0m4W+gwMBmPFZrU9raLdJVs3gKun3nEzZXBsC2pXOusK+IlL5WTOb7lNiiqyATdZ69O2kBaN+iqdcgNueSsZrIWtbpclM3Dud3naclqFLKe9qnie771vWMU0qeXXZXlxywqyI81JEyVGp6U17eHVYR3nrbiDKxss8lWJavBLWwq6jyZAUc4RNlS59r/JWRm0KnQpWtBEn3KXNyUWd519AtMLWNkSfBWNpue7KNBdR0OAaFfRZ3hrlIUtWRowdCGZiZJC0NZldLWoYcQwcj0Vs6hcrXfmeikKtzQfBWxJSkKNKgwTdXNyjUpQJ2QLd0F/aNEglA1RJyhVRyRAgnkpgYucegCLRvsoBJuj0koDCh6KWQOiCEpHO8FHFVF0XTER55kqp1Xmle4zqqj8VqRm0zqhgyqi480x5aqtxDStMpN0M0KO5pHHkqyYvIiE2cxKoJTNJhDVt51IRL3DdVSfBSC42kphrTTJJ9YrWwmw6rDSPeAhbmRqpW4uarG7SkF0wnZYrZ9tFCLCER1UmSopVCiUCZMhELsp4olKdEAQ8EUIQHZSymyiIEBQoiIQOioRyrPgrD1VcXVSkOqz1bStLt1kralajn0y1DdVK2pdVrrHKhqeih1RQVRJUlSyiIbZToh4IhBBZEDdQBMBJgIHotzPuvVfZjCxW9IdNtFyeFcOfi67KbBbdev4bQDHkMMtbusdVqRtxQiiSZWCbdV0MXJpunUNK535ZWK2hKah+Jp/3BImpR21O4u4KDrHWDogQYFkx1MkFLIJG/kqgTudETfRCbX5aqGZmNeio5vET98Jt3B8ysa18SkVxOuQeWqyIyhKXZEoIPniiG6Oi0IoooghUU8ECgiiiiCeSkqKbqghQoIoBZRE8kqCKKKIAoiooGaigEUVdQflMLWDKwAxdX0qoiCs2OnNaNQgEzLhI4Fpso0KRx6SFC4jZKXWvYc1WapIOc8ktdgABb8FpyBzZBVYpkmB8VZWbGVuqtaZslqUsokoNMGFploEbp2iTEKprgVc14ICirqcAwdFqYC/Ww5LK17dA23NaqT2yBOyxW+WlggQNFYqs7WgSURUBKxjrKYlI4lrTAJUNS5ASZyZvKuGhsbp6fdSAbu9yuDbaIg5BEnVKW681YJulI15qLihwO6rcYbGiueYmVRUPdO60zWeq7ukjzWWbk2VtW8iSqYJsJnoukYtA31Qcdkzhl1Sa6qsULkxsrKbbxCDWkmB5lXMAFhqd0pFlKmXGy6TKVmuImBAEKiiAxoBC2MuwGdVy6rtxBaABARRJGyXwusOqbobogddUDMoIBzRQFkdkAi6IPNRQAXsgZsXhQg20UFplFDAi1kHIu8VW8mECvMXVL3IuN1WTa61IxaUiSkcLzqnSO3W2KUuAN1U92Z/RM5I1uZ8KoLzoRuq381sd+HNLKNZWM2JafJELZCSChoYKkIizNpmVlMtmZnwVIGYJ2d0wfJDWim5pMhbKbtlhYGzcQVrbAtcFZrXNaWyQrGwEjNJTgaLFdYsCnzSjVHdRUPmlhMeaVEKdVDopugZQQKaqbKIiXmFNVFB5KiEckDqiggQjdKbFObJHBajNVHRZa1itTuizVtFqMdMjxeyQ6J3SUi6OIHWyCKCogCOykI6oiKBSJThhInQIIBJsFpw+Hc+o1jGkvdpCSmABZek4Bw9xca5JzEd1S3FjpcOw7eH4bsQc2Jq2J/TzXbw2GZhaIb6zhdx5lZcHhx6SKr7huk2k81vJDh3TuuTanED7uoYmARK5QOvzXYxFsLUI2aVxRv1UpDSbp6Imuy35gqyR0TUTNemdO8EV2Lzy2Si/wBSiSOclDkqiDVCSLqSYvCKo5XEJ9IE7tlZd1r4l7cX/KsaM1CbIbolKUHz1RTZRbB1U2QUQFQoKIIooogiikFRBJUQR0QEoKI+CBQjCiiCKI7KQgA1TShF0RyUBRba6W6YEHZFaKNXYlaHXCwaaLTQqzYrNjcpiRobhIBmMKxzZCUCLoqBmXRO0CJGqmrZQLRrCIqrU3Oi4hUuoGCbCFrIkQUC3NuFqVLGJsjoFaHAaqx1IEW1VLmuBuCr9s/S+m4kwFpY4NGaeiwNcRufJXtfPM9ExZW0VC8hxsNkweCTBWTtJtpCdtQ2sQs2NTppe+wAT04BhZswI6BWNcCFMXWlveOtlaSLwszXSBCIcQFmxqVoHq3SPeBul7SQVQ9/eKYuo+oM0yqarzlOiV7szhGiSoZiFuRm1USSbnZEW9Qd46lTKUSDG11phS7UqBpJhO1hc6wsN04bGiIQWOUaBW02ntGmLJmUwKeZxIlX0aRlpcL8lLWpFo9V3OVqGgVTGS8k6QrQIsVyrtzBChmUYspErLYeCgE+KhHIIoAQjoVNdkfBBBoojAHklKKknyRQU0CAOMaqmo7zVlQql5klWM0hKEc0YupErbBCq3X30VhVL+SrNAixPRW4WjmBeQqoJgBdXDsDaTQeUoyzOp81ixlINGca7roVXsDozBUvLKjTJmyqVyicwCE2RcMri07Ks/BVnVtIqwXdrdZ2kq1p7wP1Q1ppukQ8ArTTJ0WUes0haaJk/NZrcbGGytabKllx+6tGllzrrDI7IKXlRRSkSjHJQoEOqCZK7VAJvCO2iCm6IOyigR6wqAoVNUCYVQHfBVlObykMyiVU9ZapkQtVTTqslQyTK3HPpnPNI5O4bJCukcqVRFSOaqAma0mx0Ra0xYJmtGYZjPggLQNYlOG5jdTKYv3Qr6NHtCBSaTzlRWrhWEOJxTAB3Z5L2dJraAFGllzRfKPVC5nB6LqVMhrYe4Rm5DovQYWmGUrAAbjUk81z6u1uQPZsOV2YRplKam59xBEDkmABdyGtkZawZiL8lBRinVewe2QBBJsuTHeuTC7VWXUKrjuw/JcYGSYCioACZMyrcPHb07/mHzVU5dNU9A/fs374+aDsaeaUkzFiCmJEa2KTUTebKoJO3NSLWRHmAobgjcoOVxP27eWX91jutnFJFds65fqViVZqaISoUEHz7ZFAKLYN1EEUEUsoogiiiiA3QR8lEAUUUhAZRPNKiEE3Q0KaEIJQQXG0IkJRr0TygEQFEdUSEA1RBshHuUAsopuaItcKIgSirqVb8rlbluDqshF9FZTqupiNQpYsrU0CeihG4spTLXiQZVgZImLLLZDTkSHQfBJlOm/VXCnBsbFTJkOqamKC0zcI9hmC0NDeQhDTSY6rWpjBUoOYZykBVgka7LqlrXth11ir0Mpm/RalZswjXQOqZriTZVtbdWsb1VQ7TaAVopRJzaLNEdVaLKYrQ3mDZGZkCyrYC4XNk7bC91MalHQWVbmue/p4K4AAeKcAclGmYUL6W6ouptiB8loLZNvgrGsgcipq+LA6leACB80lSi4tvA8V03U+QuqzhxqBfqnkngwmk7Llb6u55pqVEDvEWOi1GmdHe5WtpgJelnCltGSHEaKxjbzzVgEbIAag6LGtyCBcoxuERdGwiyy0ESop4ohApEFTVEzEqZSggBEjVSRaQmtKEoojkUDChsgb3sgnNQ2A2Un4oIK3m8Ko3OqtcJKrLYK1GKAHuQMAJ46abJHaKorOsrO8y8q5/qmFQQSYF1qM1bQvWbyFyjjMeQSyna14SsOVjnaQFz3OLnE8ytRztO5zvWJMlIKr2ukOWljmvokVTlytOS2p2lYjYrTK6q/O7PzSaiSo3RTQKAAxKspnbldV7iE0nLcoNNIyASepWyg0iSdyslIS2I1K6FMRbbVZrfK1h2JV7R0VLBe6vAXKusTVFTREBRoN5Sn3pzEJTsgUoHoiUDpKICHRT4qbqiIhAyeiOyCKT8FIUVQpskIhWG6rcqiioSQstRa6mixv11W45dKXEJCmelW3MIlEtPRCYRugYEAItdBkBLeJT02Oc4AC5RDMY6o+G3JXq+DcNAptpsBNY95xAsAk4TwY4eka2KaGkts0iSvTYSkMPShgEm5JWOum5BpYc0Gy+J1gKzMS6XNIF0XObLXOJdtogO9AM8wsNFNMTmiANJKlFge4vkwLXClYuJAGp0Gkq1rRTaGgyYsgrxUjD1AD+U6eC4twQZuuziXfy9QTBLT5WXFmTYeMICYOo20VlAxiGcswlUyModm8k9GTWYJgki/JEdfNmBgdLJgcsGbIgBojbohAN7zKoA1sp5o6GLc0DHK6DmcU9u3+0fMrDstvFPbNkR3Vi+KqVDollE+KBN0R4CEYunjkhC2hYhSE0KbIFhS6YhSECwpc6JoUiPFAsI5UwGxRhAhaiW8k8IgBBUGqQrsvRAtkoK4ULSYVuVMBIQUZChBBWnIgWTaEXVI1UjorsgTBgtZMNUZTEowr8gIRFOSmGs8EH6pgFeKQlEUrphqjWEwAVvYyd03YRumGqAHNOZhIPNaKWKc0w8SOYUFEo9gTsp4tTpoZVpVIyuAPI2T5JMwCsYwx5KxtOq13cc4R1U8Wp20CmQbaKCi7Ye5Br67RcAnqFbTq1jrTEqZV8oq7AgzmgeCJpZrOuFeXP/OwBHOBo0ImxiqYTMIaI6hUdm5jspF112sNQ2ZroAtTeFNqMmoSw9FqX+Us/hxGUKhuWgDqU/ZBonMCOgXap8AruomvSz1KQOWRcz4brE7COExeFvNY1i05+aMTcGPFXOo8/gUvZX0KYspQSRCcC10AMsqSs43KtaQBZWscDos83uTATtN7aLFjcq8mLIJc4jvSFJMzdZxrRIEzyR+SkKAKNAeigF00BQWN1ACJ00RGl0bIAKKinVEmfNGO6grvITSibGwQIQQa9FOpUlRATp1QiETJUMBqKHw8EI5WR80YlBVG6WFaRCBCrNVkb3VTgZV5EqtzbKs1mqtOW26pgiCAtdRmgCpLCdiAtRmjTpF1JzdyFzHsLHFrtZ0Xawd3xqrsRgGVjnAgrUrn1HAlzmgHRtgqXetrK6eJwtRpIaBrZY3UMl6hE9FrWVVwBKJ9VTU6Ji0gIAiBbqSpB2jVMB6oJvMkoNeGbJaNYutzBELJhgJNui2gCFit8npCfFXtEeSrotMSdyrg26511gQiBZECEYtoVGiETogQmPJK5EKZ80h1T7bJTPJUKQpHJMANFIAVQLQoAUdVIIKCAbowiBOyMEbSgQhVuEK8tVNUKxmstbRYqi11islUyFuOXSklLdNIQW2AhMBJUaPcm0NlRALrtcCwJr1+0IGRuhPNclrb3XruC4ek3DNY5wAN3EajosdVZHbw9JrB2kyGjugnXrKvFRppiLu5C6rZhw8wKjgwdQnaAxpa0NJnUrm2gbLpqTAJIATgnWIGyrzhrnBoBd0ug4veSycp3jkgNIdpWdUDiQBAEfFXd0TMeKQOa0ZQLC2ijna5gSdoG6CuuC6g8zo0rkWJG3muxWcTQqWjun5LiesbHXmgLoNgJ3Nk9GG1WkbOGyURY+5Bnddc32RHeO8ackANDFhr0RAudJ3QJjYi6oGpMFSLWUAuL3QJ0Bm6DmcU9q3+1YVu4r7Rh6fVYJVSogTdHZKiPDqaowpC2gKJgEIsgWEYumLdlIQKomhTLZAu6I8UYRhBAiLqQoEDKIIqgqN1UCLQgaFIUCaFQAEYTAQjCBWhWAdEA26YCEBDJT5bIMTi6IgpiyfILAIhMFQOzEJuzadEwTBVC9mEQyxVgRhMChtuie5FgoE7dFPFdBrJMlXMZTbctlLMozsr4mr2PAHcaGrRSaarmsuS6yzMFl2uBUO1rdrAhl/BS8xZa79PCUmcObRLBAAmBusWN4LhauGL6UUqn6tj4rqk/cT/ALqoYdQvdZHhsdwh+HqQBtNjP0XNdSynRfRsQxnoDxkBbGkW1XncTw2nVouq02BkHvFa1vni33HlKlFx0AVTsO6e9ZdmtgalJudzZbzCo7PZMPc+3NFKBqiGkDRbjSaY0SGnyWbys6ZhaCPNMHAmFeae8JTS5BS8L5qwUyhaQbCUwFrA+axeG52Hgj13TZYCIbN1mxqdQm8IeScsBsCiWWWca1X8kRonyj9lIPJDSxKGqaNksTZFS0IgGIhQNk3TwoEgKHkQnCJCBMttEAIKZwvZNAjrugqglSDCtDUqJVRFkC2N1ZlKW+4VZqpzZuqnM52WnKkqglpkrUZrFnLHyNitB4i5jbgHyWSq4B5AGiz1HOm5WsYtX18W55NolY6ji6ZKkyhE6LTNSm28piJcRpCdjICBFyqhYE+G/JFskiLokQCArKDCG5oudOqDTQAkNWxjZF91nw1Il2Yhb20zOkBc7XTkzGkCU8HyTNbZQiCsOkLpspPNFyEKKUpdUztUOqoVL4JzfVCEQsdEAmN0YhUKAjlvJKIuUwjkgDbGEyI6BEAohHX10VNUCJWkjmsld8WGisZrFiCJWJ55q+u4ybrObrrI5Wlj3qBpJuUYKsDSeSrJMsJgL2TZTN4V1KiCALgmyC/h+FfXrgNaTGy9jhKeHZSZTIIqjVxEe4rn8H4e5tHNlBG7tyV2aYLGAEHrC5W63IfIwXFMEjdFrgxlmjxIuq3Na3vNMTfWEpbVeRclvMhRpYa5d3WT1KZrm02y4wN5GvmlAqFoDXBvknbSIElxPkgZtTPdjTA0JEJmg/m5JSHbOTAHmLfNBKgHZOBH5TdcORHgu08kU3SNjvK4dhpeyIYRl0QAl0xI1Kg8o2QFr8jyQd8j/KBv9LoHmbeKmyqJbkoAIU89ULgbwg5vFfXYZm2q566PFhBp9ZXOlVKCCKCI8UEYSZ02YStAo+aEhSRKCQjAKkiUQVRFFJEo+CAQpCO4ujugEKQiEZVACkc0Y0R2QBszCKO6MBBEQVAAiAEDC4ThIN04VBAunACAgnqmAQQC6YAwi1qcNQBvyVo5JQ1PlVMEBOAkDCEwa6dVTD5bIhoQ70QURM6KpghtkwaUBPJOASBZUwAFYxt0Gi0wVfRbKGCGOPgvScFZUpYKo9o1LRouRSY0ua06r0WEov8A4b3TGYyB0ssd1rmT8tzvw58fqg0n0cqOIbh3FxgA7qUyDh3EEEX0WUV13TgaglYaQa7h9aQLXWhxzYav5qjDXwNf+1Hr+PnOP8xTRoUq2CrZ2A+ZWRvCaNei57SW5dbroYL8FXHRDBCcLXE/l+iRv5OZfJwanB8U1pc2k54GuW/wWJ1FzSQQQRzXruGuIZUE9YVx4ZQxDH9oGF5Fn5bj91qX+Xk758a8SWbJSwSu5xHg9ShSdXDmmm2JIEfBcVwg81fthUaYzJS3SCrCTeyBEqYpG2MOum3gIZTr807YWbGpUDYA5owJhT6ojmudjpKUsCGVWZZG6UeCmKTLJ0QyFWwopi6TJGimUp9wiVMXSFsCSUuytgQJUAF4Uw1WOolGB0TZcxuEwaFDSZUrmCJVsRqlIlBTF0CArC2Ermqoqc4NHVZqryQZK0uYVmrAmxC1GawVLu5Kp7TK2OpA6JDTutsYytpnXmmbTErSGRoES20pqYpDe8q3NMxGvJaCDJSBh3F1UqsUhMHXxW/D4YuvsAnwWFL4Osrq06IYIjRY66a55U0KIYAALq7IrBAsgTssOkhCPeUpjzTG6UhRSmB5oFNF7oGFRWAFCmuhHmUCRJUi1k8BECRCIQN8ioGiVYGhHJCBMvNTLOgVoYi1gQK1qOXzVobaYKWo4NaSVUUVnACxXKxNYCQCrMZifyt18VzXuJPit88ufXSPdJKSDCaNSUQBN9F0cyhWMaTfZFlLORlMgq95bTGQDxKIqgAz7gupwrC+kV2hw6lc5jZOYiy9LwShkpZy3vOPPQLPVWPQUmMpUm02Q2BEC6cz+oDmqmaiCLdZThhIuAubqXLTkd2euqYMtLjYbJhA0Gu6JMXkIFAjoiDfoNVJAmFJ3EIJe+iaYHVLm9yI56ygDhLSJ2Oy4RMbgLvOmD11uuBcknREEGRuoTPeU3sLpTIlQegkfsgbeKO5kIbrSDpzSk6xspNpJ0UOnNBzeLRNMeK5x0XS4t6tI+K5hVSogpPJREeFUlAKeK0GlST1QB6qSqGBt1ULillHogcOKMzokBlGQgsDuRRlV5ouiCLIHBKObmkBHNGQgeVJ3CWUZQHMUQUBqjCA5jzUDipCOUTqmgB5TZzKmUKBgV0wwqkaJhXINiq8qmVNMaG4h26sbiRzWTKUctldG4Yidk4xAXOujJG6aOoMQ2LhM2u0QSuVmcnznmro6orsKdtZpN1yBUdzTCo4QArqOyKjHHVOHN0DguM2q8aFOKz1dHaa5oEAhX0SNNlxqDnkrWMTk7jbuTTXbwbM9Wd9vFerYwHBBl4iLLyvBmk1WZtfWPlovTYnEDC8NfVIktGnUmFiqeiM1B7jcknyRDAcPUjum9wvOt4viwSGgBrjMQr28YrGm5k0hOuY3TCNlCpmw1drrPAMhLg/wlcf0/Qrn0+I0H0Xte4U3E2OUlV0OL9nTqMhsObuNVPb2efNlkdTh18NWHRThpmnWH9KwYPi1KlQqlzdQABOqv4bjcM0PzVMuYaFNa66l8v+2vhjZLh0XRw/qlYeEjvuO0LdQ3HRHD57/urh/aPEOZSp0Gkw6XPv7vqvMuI3MLs/aOoPTnNn1bfCVxC5p0K6cz04IXABIXz0QJBOqBIGiqjn802e2iqc6Qqi4ys2Eae1bIurM7TvFlhLkC4qXmNTp0RBRItquZ2jmzBKYYqo2xusXhqdOgNb6qHSFjbjf1BO3GUzrI8lm8r5RoPghfdKMRTP5giajdis2NaaZCJ0ulzA81JGymGnkWRlJKkqYpj0Q3UJtqpN1AHBCALJigeqBXAclQ6mDeFogkoFvkqjG6hJVTqUO0W/L3kXUg46K6mOaaYGyVwhq6BotJkaqo0bxF9ldZYm0ibxJ2V9DCvc8Ai6108ObSAAtbGBoECyWpIlKk1jYaPNMSNlC4+SWVhuDuUEC4DbRI541TF02yW4Sh91A8GwTDRsLn3qRPgmEIxZBXkvZSFZGymXmgqyhMBpZWZUIjkgEKQmjmgSG6lEMAURlDZKz1MXTpjVYa3EpkMCslqXqR1KuIYxtzAXIxeOLyW0zZZKlepUPeJS9hUsS03XSc453pW45kuWSrxQdlMCUHYd7dvctMKDYkSi1slWCkZuFfTpAPvqFUBjezbJ9YqC8AiSVd2ZIzkzyC2YHh767s1QEM8FLVDhuB9JqZnNim3UxqV6TAsa2kMl5uPBU0cP922iwEMG3MLpU2ZWwL81yt1uTDMENFvgmnadVDYITcEyjQzptCkmZjbVLcG0+ShN9EEOnJETGlvmlJvZG/6tbygYdNFLaDZLzRGqA6LgNLgLnbRd4dea4PnpsiCNJ9x5pZcZUiNT7kJnQyUHoTropNtQPNARJgnmEYm0kHRVCxJ1siSByKgFryoImBJvryQc/i8FlMg81yl1OLmWUzG5XLVSgogoUR4MWR8UBZTZbBRQnZRAyiWVAdkDzspKSVJRTyjdVzZHMgsm6OaFVmOimbkguDkQ7VU54RD7oLg5FrvNU9ooHoNGbmpnVIejnEIL86naGLFUB40RDxogv7S19FO0JVEo5hCC/tbI9oqQbIjqqLs4RD9VXFkzW2QWBwKdpG6razqrAydFVOAD5J2gbINplOA1ou4GeSaHbTBiytbTpNEvI8JWY1CLNsq5JMkzKo3moC3LThreQ1Wvh9BsmtU9RnxPJc3CUKlaoGtm634h8Obh6RPZsPvKlJHawpJwles4kCoQwRy6KPxzxQFKm92QbTJWfFVew4fhqDpk98gam6lfA128Kp41tWk0VSMtNpl10mLYsw+GrYqs1gMl3eJGoHmuqz7PluFdUrvAeL2M2XlaVXFYasHd9rx716nhvGMRiMJUp1ac2jOf2VusqKGBp06bWVGZ3ufeeU/suq3heDdTeTQbMWglJhWGq8VCLeqAukBAcBplWLa3L/DgYThWFxRqCCwtFoKyUuD1aznijVBy3ANl2OC+2qhThP4qoPFSWvb8kkvX/WONQdjsE+aedvyXoeDY92LzB7QHNEyNFVhMbg6JfTrVWzNxErj1cR2GMq1MBVcym/TwW5deH5JJ1kZPtS5zOKVx1B+AXnnVnTrZdbjFcYjEuLzJgXJ1sAuS5jdQVuMYU1nIekO5oOaAkLE1MN6TyJQ9JPNVlnRLkJ1CmmVf6SmFcLNkMIZTsqe2rtgUDUadFmg80LzqobWrMNAhmHks4JiLognqour5S5yDAPxVYcZUklRdXCs8CzyPFM3F1h+aVnlC8nmpi+TYMdVGoBTjiBGrT5LnyVJKnjDyrpjH098ysbjaR1dC5IJmN1J+KnjF867TcTTOjh71Y2o0j1lwZ3TB5mziFLwvm7xcOaIK4YrVRo8pm4quNHrPhV847aaLBcUYyuD61/BO3H1xqQfJPCr5x2ABCkDZcxvEKmhaD5q5uNkSRCnjTyjamWMYsFF2K5BMp5RoJgJHVQ0dVmfXc7Syqc8xJKTlPJdUqql1V3MqokzrKV06LWM6sFXmUe3gW81nm6YAxKYmrhiHgjvWVrcWRrcLFzPJSeSeK+TpMxQd/lE4prdYXMzEicyVzjv5KeJ5OmcfTGxVT+Ij8oXOeSNd0kK+J5truIVHTePJUVMU951KpUIERC1OYzeqDnOcLlLfQJwwkwJKsbh3F8NBJVZdn7NcMw+Oc+nXs6JaSu43hdMO7IsHctYxP+Vn+z1EUatN4aZyw5ptPWV3aBBxRAkzNiNlzt9tyPMVuHsBIHPkufiaLMPUyZmkO/LN/JdfjGMZgnloINR05Wk/ErgMrmrTDS5zXZo8ykS4ZtF9ScjZGlzdXN4e5hkgCddV0MDw91Kj2lZxdUdcSYyp6zHjUq2jPhsKxhEsk8yLBdKnBIAGcjkLBUYek147xJ8SuhSAbGUQFm1qHY3Lc3cVbo0DbqkFv8JgYPrKBtiVJtPvKEybhSZAnmiobN3U13Q/KSRKmqCalNoNdUB0UvP0VBgE9R1lGTe/wQuBKkb7ICROnJcAmXEmZk+V13wRK4NUEVX62JRAaDM6+CAvvrzQnrdS4GsEqD0AcCJ/VdMJjUXSUe9QZO7QfgmdFxutIhEIA3gckQZj9kOiDncXuyn4lcsnkurxeOzp7GTquUVUoeCnkgoiPCwpCaNFFsLGykJoupCBUITXUQKomiymU7IFU8k0EKZeiBVNE2VHKgVRHKZRylAqIT5D4SiGbFAnNRWhkphTEoKQmAurQxQNjZNCQi0clZlCNgmhADqnAJ0RkAKZ9k0MG9U4A5qnMUCUGnO1upUNaPVWSSpJCo0ms4j1ilFVw3WeUQ62qI0Cq/mradQuOgWVszqurw3DtDHYisDlZtzVtxXRoTg8KarhD3C3QKjAuOIxbGxdzgFTi8Q51MF7ruM+SbhWPwuFxHa16nqtJaACZKzLquv9pqVTDVsPVcJpVGwyDpESt1GjWx2I4fh6bIp9gKhcOo/wuFxfjtDidClSLawNGchgReP2XQwH2vGCwTadPAtNVlMUw91TUDpH1Vmq7HFOJcP4ZxE0amB7csptbLzvrvPMKylVo4nCsxGHY2m1+rAIgrxnE+M1OJYx+IrYejmdAtmFojmjS49i6WG9Hpimyn0Bke8q4j3tDiHD6RNM4ug1zREF4W2jjcJVkMxVFxI0FQFfJ21TrJndWtrlsQSDzTxaj6Jw99PC1a1SrUblvoZ+AXKOIxVatVGDD2tMk5fWjx2Xj+3IMgm5WijxTG0WllLGV2NOobUIUnLt181u3+XvuG8FonDtqVjnLhIAsAsX2kwTMLTouwzQ0ueZvsAvNYPj2Pwgmni6kDZxzD3FJxL7SY7HlormmWtMhobAB+auPPtVcQJ9JcJ0WN0xYKqtjK1aoXuIkmbaJPSX/wBJWjVhJ2QzuixSHEmbtCnbjkiaYvdzRDzoqzVYdkO0Ymmrs56IdpzEpA5hHrKDKd0NPmBQDmpfAypBUD2UgHdLF0YJQNCIEpYTBQHKCjAOyGqa6InZg7KdmCmBR2QV9kCLKdjfkrAmCuCnsDzQ7FwGi0jomACmJrH2bgpkcNituVHKExdYcpCmUrd2beSIotOoUw1hAhOCZuStgw4Kno3mmGqGGfELZTwznUhUOhQo4UucBC91T4Zk4M2hSAbUyDOQTJGsbSmGvBObHkq9l6nE8AcyiXm7zo0Nv19y4mIwbqJLSCDqBCmLrnlKdbrU6jFy23VVZNTCmGqmt3IRceqfI87JTTIBLplDSWDTulDZ1srMhBuoWzdw10VFeVguSfAJXEF06K3JuPdyQ7ElxgSgqa3O4396jhkHjotTMM4sPU3VgwoLoIJMKaMPZbRJVjMK9xFpnou7hOCV67WPLMtNwkE/mXbHBmsqUdi1twN+X1XLr5pGpy4OH4KTmaRDm2g81vwXC+86lVp5SXCDGhFiu++jTGMZLRmOUH4D6J6oa3G6BsuEW3SdWn0x4agzDYwMG1vFZeJ8VocLL6ru9UkhlOdT+ybjPEKXC6jq1QhzyZYwH1v8LweOxlbHYl9fEOzPcZ6DoFqTUtLicTVxWIdWrvLqjtT+y9BwThv3YxeIaJddrD81g4PwztHtr4lvcnutP5v8L1QsyFq38JCvKx4gXla3GyxYg6rDSzDaLY0wOaw4Y2W1h5XUqxaBOtpTTFiEgJ2CaYKBj1JUNjoLJQYGnxUdoYRU2sidbGYQkh0Qi8EU2uGhPu5IDM8gFNehRfTfTMO02Si5hUGUxMaaJJ801tIRBOkgT0XCqECo+35tV3Jtb3Lh1ie1qcg8/NAhMnpzUjM71igCC4j4KB8Dog79G1BgGzRHVPflbmq8OQcPTJiCwR7lYZhoGvNVE3JQmTMQoRa3khIzQInqgwcW9jTPIkLkldbi3sGWiSuSVUqeaU6opSiPFZUYTRIUHJbCwUYsmEBRQKQpCbZQeSABm4RjdGVC6IQDKpllGYMKboIGhNlG+qWdoRJlA0CVICUGNU0oIY5I2QlSUB6KBCVJ5oDKJQ6qIIpsjCEXVAhQhEKIARCEFNoogXKYUynkn2RAKoryO5I5SNVaGk7JxTJ8VcFIc5ujbqx2KxL6QpF5DJ0AhXsw7ybNKvZhXSA4tBOyDmhrjqCnaw6rrMwjRUDYkrtDgrewFWnlblLQ/MJkmfdt71NWTXk2UnEyAZV7cNVcLMMDVep41Swo4DhnUaVOnXbUy1A0QdCubhuA4vE4T0ttHNSN5VlLMcc0I1c33oFgAnMFsq4bsyQ5l0nZMcBI3VRkY0udYK0MJPQL6Nw37O8JqcOoVHYTvPYC453XPvVx+zPCgx7BQcC782cyFPJY+Zlpbqk01Xtv/wDM4WpinUfSHMaCR3mhZ6/2SzVj6PiGdmN3tN/MLM7jrfis/Lx7idEjtF6Gt9l67HPJxeEkaAPJPuAXPqcHxjWeyk9DMLWuNjlnVK4laa+FqUTlf6w1Cz5XE3BVQsqZjKEETYoXQNKhKUqIGmEQbJEQUQ4JmUQ46JAUwQO2o4bqxtRVamU4AUFoqSma/oqQ0wmAKC6RyTAqkGyaVTVwKcQqAbKxpugttyTAAqtpTgqocMCOTqlCsCCCn1RFMotPJOCgQMcNvcnaDyVjTdOIKYarCZqaAdk7WjdXE11vs/g2YnFS+7WDMeq9a17XaEFcDg1WhhMOXPqsYxwkuJi86Lnni9ZlM08H3cwgvdr5Ba/b1j9z29LjMfhcHRLsQ8SQYYLud0AXmsbj8RxSoKeHwjYYTlhsujqm4dwetjS6riHua3Ul13OWrHYujwvAnD4GG16lpBlzRuT46f8ACnhI1Onmakmo/tgWubYtiIKUj7vMIBKvpYTEYkuNKk951MAkqp1NwJkabKeK+RCC2kHTLnSBCrIy087rklMQdylMmyz4rOiC5k6IPy52sF/3VuVx2Tsw8EFx0U8V106fAX08K3F4zEUqFB4ESS5xnSw196qxGLwdJnZYDCwN61U5nu8tAqyald7WjNUeBlaLkwNAFdU4PXZTZWxJDGvPqAy7fXYLHWcza1zvVyOe19WtUyUmFz3aAbLuYThnoz6NTEPbUqVB6o9UfuriylQwVBtCmGNMkkb+J3WtoD34fkGk/JeD5fnt9R7ePhkm11KgDW0wBbKhiCDUHgpW9Wn/AGpcUQDmNobMlcbdrirxNTJimx0XH49xqlw/EODAH1yAQ3lbdYOP/aBgrGngXZntEGqNPLn4ryrjUrVLlz6jz4kle/4+bntx6psXiq2MxL6+IeX1HmSV1+BcG7WvTr4xv3cy1h/NyPgtPB+B9jiGVce0F8gtpnbxXfcf5zTfcrrb/CSMOI/GO8YhXA2WfEkjGOn9SubcQsNA5Y8QdVrcsWIOqB8MVtYQsGFNltYVKsXNmLJy63Qc0jeZRmfBAxM7e9QmwQB855Ik8wUVL2Fykx7i3C0QCfWm29k4MnWeSsrUxVwIy3dSdmjw/wAIhQ51bB0nOs9sXPI/6ELx0+CSjnOGeSZDRoU4M72n3oIL7W+aaeaEXUBgqhi2xuuHibV6gG73D4ruTfzXCxFq1STJzn5oK5OgHhdCw0mUbwJ8ICkwPDzQd7Dkej04NsgPwVsgjl4KnCfhaUfobbyVtpFrBVB1iLA9ErgIneFPG/0U6mEGHiv4dv8AcuQuvxb8MI/X9Fx1UoIIoHVEeM+SMhVByk3WhbKkqrMVJlBZmupmvZV5lMyCyeakyq5Kk9UDzdNKr8kwEhAwKIQUQPqVJsUkyiCqGkcrIzdIigZFLKmZA6iTPCHacggsKkqrM4phMIHkKbJfFWNY46BVCgGyYMVgYB6zgCmBptNpcgVtPldWtw51Pd8VBVcTDQAOiduZxkklXQ7KDbA3XQwmEpRLm/5VNBhsVva8CG8hJWOq1IpxBa0BjABGqooNz4gDzRqmXEyrMCPXedrSkGjD0zUxYA3K9B6Sytw7E+hNzPiXUybtie8Oey4uFqNoUqtdxjKIB6lc2hja+FxQqNLmuBnXVWezcdziuGc/gVLFPAaQ/KZuXTv0Aj4r0f2VP/Q6Q2BIXn69b+M8PFPCuDKjXZ3UBo4xqP2XovsxSqUOF9lWYWPDiYPIxCuL1dec+2NCjQxzOxYG9pTDiBzkrzzdATzXe+2OLoV+INZReHmmzK4jSZNlwmgdiDp3lYy+l8EqB/B8KR+iEnFuJjABjW089SoCQJs3qVX9nSTwegeYP/8ARV/FaVJ2Bq1H02F7WwHEXHmsjgnE13kudUOY3JAhZ8XXxDaLnZ6j4vlkq5oGxRcLRzVkkL3b9smB4rwl/wCINWm7yIXawz+B1hLMRSPRz4Xi+M8POHf21Mfdu1EaFY8C4iuFcR6D7UcLwj6vpXDsVhScsVaXbCbbiT8F5Z7Q1usk9F1qzc9UDmr8Z9n3mj2lBxdUGrOaLrzt0ANoTvY5j3NeC1zTBB1CCBC20ZUC0ck8IEc0CGm2LIZBPROQjbZBVljQymDU0bQnFNx0EoYrAPJWAQOiOR0zBTQREgqamIAY0RGl1I6IxCaYICIaCbqDqEwMImDlBKYA80B1VjdAmmIGmU4BQCsampgCU4B5KAJ91dT2gmEbiBCYCEwEhNPaA9EwIRATNZ0V1PYZg1TM52micMGsKxjBPNXRbgcDWx1YU6ZAgXLtAuvw2lg8DmrYkiWtJDn2k9BzXEDHuqEMBnkFfS4fi8Qe5TLoG5A+a3O/wxY0P41iMppYUFhdYuiXHwGy5j2PZVLazXNdMuDhBnqtlDA4lzpo0Xlzby06LLUzuruD8xfMHNqrevaTHsuFUmYfhzAAGktDnHxVdetw2rReMTUoPIH6gT8LrhUuFY2qwFuHkRu4furqXBsZVmRTZH6nT8lj0flzMbh8OcQ44RzjTNxmER06rOKDeq9DR4FmY51WuO6NGtW7C8MwdKi8ml2jmiZfdNhOnmKOBr1RNCk53UC3vXUwv2ec6h2uKrZYN2M19677AG4N4aABsAFNcE/+4fRYvTrIpo4ahhcEBh6TaZLrkXJ8SqOKYftuHU3sPea4mOeq2G+DIB0chVH8jTGne/dcupsdeL43Y87iQW4PDtMgiZC6mFpj0Wk87iAk4wMM3h1F9WoymcxInU+W65GN4+44ZmHwVPIGNjtTqfAbbrx9fp+rfT1X9RPHHe4pj8NgqDHYh4nLIYD3j4D6rx/GeOYniRywKVEARTaZ953WKqa1esXPe6pUcdSZJXSw32exBy1MYTSYbho9Y/su/HwTn3Xlvdv042HwdbGVezpNJJ1Ow8V6fB8Ho8Mqs0q1jBLzt0C6NTD0cJ2bKNNrKeQHKBrznmnxYArtfm0bcLrUkJiRlxYM2kJHfjudwrcUP5znpCWpbG+eqiudixGMceqtBslx18USOaZqig43WHEmxWxy5nEHEAwqlX4Q2FlvZoFzMC7uiV0qexKzVi9uh1TDWSRPiq2jknzEEEophc+Cl5iPihJJkzBRE5rWJRR93VOyq5kkbiLqsWUGkSgmYljmNsHOnyRF4EdFOURrohYG5IQMPFGLpbE2+KY6H5KoJ/2FxMXbEPgD1iF2yRv8Vw8WQcVVOgzH3oKs2s6qGc05bc1CZHPdKdhlEj4qI7+GObC0co/7Y+St0BHJVYWPRKFo+7bbyV0bRY6rQHnvtshPVNuBEoC94MSgxcVj0Vpn8+nJcUrtcW/CAf1D5LipEoKKIKo8OUUIUWxLKKIwgCKOWycMBCBIPiiAnyxujACBQEeiKkaoB0UuVLKSEEGqKWeSlzZAymYc/coGEphThAmYypc6q3JOgThkamEFGUlOKfNWwwdVM5HqgBVCtpHQiEwZTae87yCUkuNzKkSoD2gFmsHndHO8n1jCAppxTQLCcBWNp+5Wtpm1kUjGSdNVpo073TMpSFqpUoiVLVh6bcrJ6IizC6bkokHRI/8ASNllVFZ1jeFooNyYdo53WZ7TUe1o1JXXoUM9SlS2CDLxcHD4OhRmM0vPXl9Vrx2BZU4fSfAFTICHDwWni/Cf4j2dfDVWyGBoE90jofNdWngnVOFsa5sOawAg+C3Ga8Rhq1ShVBa4tc06gr09Hi1XH4N2G9IGHrluUPOj+h5Krgv2fbjMZiG4jMGMOo1C5WLwdbC1ajmAmkx5YHxZaTWPF0a9Cu5mIaQ4Hxnz3Rp/h/8A20XXpubjMF6PUykky17rZT+y5bqL6Oam9sOa64TVfRPs2I4Jhx/d/wD0U/GqmTAuZN3EfNJ9mv8A4Sh/7fMqnjb5c1u2YfJY6uNcc+VcoCEwEoAXVjWrWuZKuGbXpmnUAIK8u7BPwePLCDl2K9i0QFzeNUxkov8AzZ48oP7Jo4h/EsH9QXrGiYJXlDHplMRo4L1dMJRk4lwfDcRBc4dlW2qNGviN14/H8PxOAq5MQyJ9Vwu1w8V78G0LFxTF4bDYV3pTRUa6wZE5ioR4PqpCsqAOeXMblBNhOiZlIuIDQTOya1igtk8kQydl2P4NWpYX0nFlmHpkd0PMF/gNSsTmMEhlxsSE8lxlydVpayGxompUHvd3W5o5CVeaRBIKmmMrmpcv/C0ObG8pciaYqyohnJXZLJsiauKAwxoiGA9FoyFHs91NTFIppskq0U04p8k0xSKZ1lMGkbK4MMpxTB2TTFABCYSFcKYTimmmKASAnBVgpzsE3ZdI8E1MIINyrWlQUpTNpRoVdTxM0LThqFVxNRlF1QMEkAT8klGg5xAGq1hvEMHULaba7I/SJBWeu2ueHa4RUw1cdpQospuAhwAuPNXU6QOOqOabmfmvNYfGuw2KNam4Z5OadDOshbaXG306xqOpMdMyASP3XDnnri7y31Oet1q4bLMVUadgR8V5wuFXF5m/nfI8yt9fioBrPbTLXVGuGuk7rmYSqxmLpPqAljXAuA1Xunfk8l+PxezwFWXPZOgVmDqipmvsuBhOKUaNV7n5yHC0Afupg+K08PmzCoZbFgFq8z+XHOt+neomaNX+1Gkfuav9v0XFw/G6dOk9j6T3FzYEQEh485lN7adBozCJc6VmrzxfTu0yPR6qgIGCqEkAAyZ8l5ipxrGGm5jXsYHa5W/usFWvUrH7yo59/wAxlZx142TK9RW4vg6OFczte0qZvVYJ+Oi42L+0GKq0OxotbSZrOrves9DhuMrszsokMH5nd0fFdCj9nh6OauJrGZjLT/c/snqN7XnqtSrXfNR76jzu4klbsPwTF1GtqVx2NN2hdcny/delpYTDYXAg0KTWuzXdqT5pqrpwdMnn+6zev4WT+WfDcPwmBoU3UmDtIJL33d/hXYlwcKZEaaylxJzYWmVXVvTok/pP0XCbu109HxToNKdIgpMX7Vp2yi0IYq/ZAiQWmUuKcc1MiZyrYfFiMQCeUnokqt/mwQbSJS4pxFeegQrOPpDSLzGqozY9pGJdOyVuimNJ9IdKjdLKYaV6w4lodMhb3LFiBIKqEwdl0mazK52E1XQb6u6zWoubrYJzfdVtEaCU4JF1FHeLBEckJjUon4IJHPkoNBt1Q2kIm6KM780c3QJSJ28kRF5IsiDMaGyYcvfCUHWYlEm/+2QEiNvGy4mMn0mq3SD7l2tlx8cZxdSZ1HyVFAMmB5oAkutp0UBgEjfeFOpFo8VEegwsei0QDowDW+icW11VWD/CUR/QrzcQR4LQU20HhZASR+6IdAJuT1QFr7eKDFxW2GH9wXGK7XFvwwm0O0lcUolBBMUFUeJhSLJoUAWwIsiGo5mxqEDUANhKgaNEVWah2sgXE7oLZS5280gBRDeaogeToFJJTtAFoTBoBsgrDSmDJF7J7bozCANZA6pgy+sIyEJQNDZUkA2EpZU6oDmPNRRTdBEQEQE7WhAoanDbpgLqxjZQIGKwU04bCtYy17qBWUxormU42TsYLK5jYTQKbI1Vw7pskmLIE21UUxN0hF1NkwFhKYaXDtz4tg6rsVZoYarVb6wbbzWLhtPNjJ2aFv4k0ehinMZzKfkcPB43EYJ5NGoQCbtNwV6TAcfY9pkmnVynukSHHYLzOIodlWLJneVt4PhjVxjZMNbcrp6Z2vecHpuGENapepWOYmIXD4jFPgWNphoI9Mc09Oq7wx+HpMDGNcQxsAQuZWwVTGYGrSpi+IxPaCbQCDr7lEeNodx99At+KZ6Rh+31e0gOttzW3ivA3YCiKoeHNmLDdYsM4Duu0NiFfSvX/Zr/AOGpDkXfNVcab99T8z8lo4A0s4Y1h/K9wHgqeNGa1NvJs/77ljqa1z14uUBdXMCSmwvqBrYk81TVx1Og5zSQS0xAMqubbCwcYANCmBrmJ+ClPiJrOhtOB1KvrU218ucTGiDzrGTjqc/qC9RSa55DWiSdljbg6PaAtpjMDIKXG8aGHovw+Cae1NnVj+Xw/dFkDHcXoYOu6jlNR7LOykQDyXmcbiKuMrmtV10A2aOSdzS4mTruVBSRqek4fw2vjqwp0mEnc7BevwHDcNw6mOza2pid6puG+Cq4aRR4axlKnkLx337uV0lY+zXH4pwitXrvxDMQajnGSKhv4AriVcPUpOio0tPVewcCqqlJtRuV7Q5p2IQ15PKQiBC7OL4bSafuiWzssRwr2nQnyUalZYMItbdX9l0TCnyF1F1S1qcNkXVopphTvoi6qDByThmtlaKeiYU1NVUGBMKauDEwp9FNFIphEU1oyI5E0ZxT6JsnNaAxEMnZXUZ8nRHJ0WjLdNkTTFAZ0VjWGLBWtprRh6BfUa0C5KmmLOHUwK7C7TMIHNbRXcOJEE2zfRCphzRxdNjDYEXSPpOHE/8A2F/JTrwv/Kt87PqIHNqcRcyq1r2FxEOAK4+Jw9LDYxzuyFWiHEZC4iPcuwKLm8TIm2bXySjDH+JODjLSTPUEJO/j5/Jeeuvw809ge/utME2ErRhuH9rVyOqZHROkrtUMC1nEnCGgZjEDRHDYUN4g+TILnfVSfqOJ+Wb8VcbDYE4iqafbBkTctlDDYB9dzmis1pAm7V2sHhGNx7wTIl1lOHYVjMS8ElwgiPNX/V/Gl/T9OJh8Ga2f77KWtJHdmU+GwdGsyqalV8sbIAIC63D8LSD3tIJlkaqYDD0oqjIDLN1j/XfH+I1f0vXva5eFw2Gdh676lPM5jZbJPIrocIrU6eHqQxrfABPg6NIUcQMgIyXlTCMptweIAaAMs/BZn67nr8L/AKTPy6bHTgqv9yhM4B9/zfssFGsfQ60bJqWJd6DUzbOH0W+f1PNOv03UaHn/AKf/AOypqmMDTPJ37qzMHcOJH6v2VLz/ACIn9S77rhZZcparv5Ok6d/3Qrn7midlKgnAsPJ37papBwtM8jEKAYl0MoxaymJJlhkxl1KNc9ykQdAlxBDW0hIEthVS4gS6mQdWi6mII7Zo6BTEu7zIEHLaAhWtVGbkDJRGbiJHb67JW6I8RP34nklYZagjtVlr7rW5ZK+iBMLqFvYSdFz8L63VdBhUqxeI11TjQADyVYJmd03WFlo2tuagkiSVJm2qh32MIJF4081B1Kk7j/lGb/C6CA+CJN4O6Ak2BEIxBQEGFNtlGnabIiIsgO2x+K4+NH83UMaEfILsSIlcfH/jKviI9wVGaJNyiDJidN0IG3zRPjdRHdwQjB04uMsK420uqcD3sFSgmIVxjS9hclUC2phDQ3BKJnXy1S7xPiqMfFROGudCFxl2uKWwnUuXFKJQKBiVCoVUeHzk6lG/NKACmi62gIxKICIbZFCEd00RqjugUapoUsFJQMDpKIMeKVSboGB5opZspKAyjNkoR10QNN0UoN03JBAmF0AE7QoC0XVjW2QAuFYBZBGNKsaIslboU7VA4arWqsEBO11kVc0wmLuSpD5PJQuHNQWZjKVzjuUpeOaBcFUaWElgT6AoUYNIGEalm+KK6PBWF3aP8lTxKuTiYGgXS4XRNLh5qRZrcx81wcW/NXcTzWefdL6JXqHEYmaQmYAXc4bT9EoZngZjcrncMw7H4xsOzBrcxsutiLYd2U6Cy6Mavo4g1q7KYB77oXosKYflHJeN+z9R1TitIPcSL28ivY4YjtwEJfbJ9pz/ANMH/wD0A+BXj6dTK/SV7P7RMpnhdTPVa0ghwDjrtb3rwuaDIN1Ytr2v2dxrX0Dh3m7Jc0nlusvHuI0G4kNpkPLWwYNt9156nVOWAdlTUc4ugTKVNaKuNqvmHln9phUNv/hXUeHvfDsRUZh6ZBOZ5+ipeKbamWkS5o3O6zo14eGtJ0MWXap+oOa4mFY1zhmldhtRrWyTopoTG1xh8O8ts94hsfNefLQSStOOxBr1yZ7osAs41hTVidm3kEzKYLhZEGVpwlF1auxjRclS1p3HUw2jQY3ZiUMKXHV2YXEdgAXFjQDfz+qzniBPq0wB4qalayzRQUwFi9NqHZo8lPS6p3HuTyRbjaJhvgqsJTIrgwg/EVasZ36CBYJ8PU++bIm6mqPFMMyGvyNBO4Gq5/o0my7/ABBk0NNCucxozaJaMPozhqFBSIsQumGjcKdmDspqub2YTikt4osJ0VzsHSGjjpKluNc83q5HNFNMKa6NbBdkxjg5pDh4IOwr2ta4ts4SLhc/3OW78fUYezTdnZbDhnsAJYYOiBoubGZhE6WWvPn+WfHr+GTs7X0TdmtJpwbgjyR7M8jfonnz/KePX8MvZnkiKa19g+3cdfonOFqNIDwGyJElZ6+XifdanPVZG0yCt9CkcO5uYQ53wTPoNw9RkEuJEyVZjfxDD/SPmvL836j1c/Drxz9f9jiSRjGnwQrWx48lMX+IYegUxIIxjD4Lz99+7/cb5/H9BVMcQ8x8kHn/AKl/7D5KYgEY8W5KVGn+JafmHyCnXV2/2szJ/QAxxI+P0S0TGPd/c76p3NI4lEXkfJBlN38QNj6xTbP/AFdmf4JQP/UXcszvqlwdsa8eKejReOIGx9d31Rw1B4xz7QJck8tnr8reucvv8KsFbEuHQ/NLgPaOH9C0YXD1BjHSIF/mhgsK9uIdNhBHxWZz169fleu+ffv8MuCktrN/oS4UzQxA/o/dbMDhHB7wT+WEMHhO7VBdq3ZOOevXr+V6+Tnb/hjofhq4/pTYak9+DrA2Ei62YXDMZSrA94lv7q6i0ej1QIAhdeOL61nv5p7xS2nHDngD1SPoqss4I9HbLSPwVQHmPoqTAwL+jv2X0/h/4R4vk99KXD+SbGzklWPQ6f8Ad+6d18DbZyV5HojCf1fuurKuqQ2lSI0uEKzjkpcssERunqkdhS8SNJVVZw7GkCJkaoDXJGQwD3ZuEuI9dpi8fVNXPdpanuKquZLMtxkGiCjiJHaAjklYZaFOJTnHKAlpnuhVDOWWvutDrlZq6CvC+sui08/eubhj3/NdFnipVi5pv9VYDN+t1W2x/wAJgd99VFPrpZEDS6FrRv1UEmJUUb+CgspoPopJ6IDPUQiJBHLdAawNhujcCRPyQTlaSmgBKIi/wTDWbeCA7aW1XIx4PpT/AC+QXXGltRyXIx8DFOANzHyVGYibFA3sTPNEnRRwJOmiiO1gCDgaRkgQR43WiDbXwhZ+GnNgadrjN8ytUGeW6oSCbDdSCNtUxuSDayUmTzVGPig/lSd811xSu3xO+EPOZXEKJQKHgigqjxQaBZEKKBbRFJU3hRFGUJQmyhQElQShqggadkZSqIGmyMpbpgLIIjeFACmhQAXKsA0BQDd0wFkBCdqUBWNEBAw0ThKNUQgcdEzTaVXKIKgsBvcol3VVgooLQ6TZSUkwN0wQGZRKmghQgIOjhG5qA6I1GzVZTG5hWYJv8oCmwtPteJU27NMrNV36QDeHYqmBZtMGfNcDD1MG2q70ts0z6xAuujhcUKlTioLhlbROUeC8zVrSYAPNOOfa9WO3wWnmq4p9KXU6bSZ/pnVaajiWOn9BXM4dxA0cHVwjKbQapEvm8TcLeRmpvP8ATC6OeMHDsQ7C4xlVurTvuuu/jmIYXZIbmuSAuK+kafeJWd9UlxEqo6OJ4o+tUdUfTa97tXOuVifWc98kAeAVBdJTAqjuOwX8PoYPF4pzH06zgXU2m+XX5JOIcVp1sQXYTDspUwe6Mtz4rklxsJ0S36qYNFSu+o8ue8k9Sg2oZV+E4bWxDQ8kMYdzqV16HC8KxmVzM5IjM4qYOIKpB1K1ZjToTPeePgkr4Crh6hLxNMXzJJdXeSLDQBS+mueb1c5AOTAyi+jldEmeohKWlo0WZl+nTv4fk4/5RYNV3+BUmUWVcZV9Sm0n6rhYdpq1WsF5K7vF6jcHw6jgWzmfD3RyH+fkni5uVVrPrVn1qhlzzJ81Boqs4JkNy9Ama68KeCatGqcaqAgAEIio6ZmVPBNM1jnGACtmCw7+3DntgNvdZsPW7N8nqrsPWLaovZPA10MZfDlc9nrLo4gg4Y+C5zdUvJq0DmmA3SjUphos+NXUiLq5xkMFrqnbVX0pJpk7OHzWPk2c2u3w9Z0uxVJ3otA6wE+Jpu9HonotNf8ADs8U1T8OzyXz+rd6/p3nyX1/bPiabuwpEXTYmm7sqWXWFdVvRYjV9kxXrn/l/UYnd9KcTTcWUsuoF0cSwuZSjYX', + ); + + herd.value = Herd( + location: Location(lat: 35.825081, lng: 50.948177), + address: 'استان البرز, بخش مرکزی کرج, کرج, منطقه ۵, دهقان ویلا, بلوار سرداران', + image: + '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', + ); + + var s = List.generate( + 10000, + (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: + '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', + ), + ); + livestockList.addAll(s); } @override @@ -60,10 +116,31 @@ class RequestTaggingLogic extends GetxController { super.onClose(); } - void onNext() { + void onNext() async { if (currentIndex.value < maxStep) { - if (currentIndex.value == 0) {} + 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(); } } @@ -75,7 +152,7 @@ class RequestTaggingLogic extends GetxController { void setUpNextButtonListeners() { if (currentIndex.value == 0) { - /* nextButtonEnabled.value = + /* nextButtonEnabled.value = phoneController.text.isNotEmpty && fullNameController.text.isNotEmpty && addressController.text.isNotEmpty && @@ -91,15 +168,15 @@ class RequestTaggingLogic extends GetxController { addressController.addListener(setUpNextButtonListeners); } - Future pickImage() async { - rancherImage.value = await imagePicker.pickImage( + Future pickImage(Rxn file) async { + file.value = await imagePicker.pickImage( source: ImageSource.camera, imageQuality: 60, maxWidth: 1080, maxHeight: 720, ); - getFileSizeInKB(rancherImage.value?.path ?? '', tag: 'Picked'); + getFileSizeInKB(file.value?.path ?? '', tag: 'Picked'); } Future cropImage() async { @@ -117,6 +194,30 @@ class RequestTaggingLogic extends GetxController { 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), @@ -132,7 +233,7 @@ class RequestTaggingLogic extends GetxController { if (result != null) { addressDetails.value = Resource.success(result); buildAddressDetails(result); - addressLocationValue.value = '$latitude - $longitude'; + addressLocationValue.value = LatLng(latitude, longitude); } else { addressDetails.value = Resource.error('Failed to fetch address'); } @@ -160,4 +261,74 @@ class RequestTaggingLogic extends GetxController { 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 livestockBatch = []; + + for (int i = 0; i < livestockList.length; i += 500) { + var tmp = livestockList.sublist(i, min(i + 500, livestockList.length)); + + livestockBatch.add( + safeCall( + call: () => livestockRepository.createTaggingLiveStock( + data: LivestockData(livestock: tmp, herd: herd.value, rancher: rancher.value), + ), + onSuccess: (result) {}, + onError: (error, stackTrace) { + Get.snackbar( + 'Error', + 'Failed to create livestock tagging request: ${error.toString()}', + ); + }, + ), + ); + } + await Future.wait(livestockBatch); + isLoading.value = false; + } + + 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 085d317..b72d4bf 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/view.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -42,12 +42,10 @@ class RequestTaggingPage extends GetView { flex: 2, child: RElevated( height: 40.h, - onPressed: () { - controller.currentIndex.value++; - }, enabled: data.value, - // onPressed: controller.onNext, - child: Text('بعدی'), + onPressed: controller.onNext, + isLoading: controller.isLoading.value, + child: Text(controller.currentIndex.value == 2 ? 'ثبت' : 'بعدی'), backgroundColor: AppColor.blueNormal, ), ), @@ -186,7 +184,7 @@ class RequestTaggingPage extends GetView { ), GestureDetector( onTap: () async { - await controller.pickImage(); + await controller.pickImage(controller.rancherImage); await showCropDialog(); }, child: Container( @@ -284,7 +282,8 @@ class RequestTaggingPage extends GetView { style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor), ), TextSpan( - text: controller.addressLocationValue.string ?? 'N/A', + text: + '${controller.addressLocationValue.value?.latitude} , ${controller.addressLocationValue.value?.longitude}', style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), ], @@ -337,7 +336,7 @@ class RequestTaggingPage extends GetView { ), GestureDetector( onTap: () async { - await controller.pickImage(); + await controller.pickImage(controller.herdImage); await showCropDialog(); }, child: Container( @@ -392,24 +391,11 @@ class RequestTaggingPage extends GetView { _buildSearchWidget(), _buildInfoDetails(), _buildListContent(), - SizedBox(height: 10), - - Padding( - padding: const EdgeInsets.fromLTRB(35, 0, 35, 20), - child: RElevated( - text: 'ثبت نهایی و ارسال به اتحادیه', - textStyle: AppFonts.yekan18, - height: 40, - backgroundColor: AppColor.greenNormal, - onPressed: () {}, - isFullWidth: true, - ), - ), ], ), Positioned( right: 10, - bottom: 75, + bottom: 5, child: RFab.add( onPressed: () { Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); @@ -436,26 +422,28 @@ class RequestTaggingPage extends GetView { Expanded _buildListContent() { return Expanded( - child: RListView.separated( - itemCount: 20, - 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(20, (i) => i)), - separatorBuilder: (BuildContext context, int index) => SizedBox(height: 8.h), - ), + 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), ); } @@ -521,12 +509,13 @@ class RequestTaggingPage extends GetView { Padding( padding: const EdgeInsets.only(top: 8.0), child: RElevated( - text: 'افزودن دام به گله', + text: 'افزودن دام به گله', textStyle: AppFonts.yekan18.copyWith(color: Colors.white), width: Get.width, backgroundColor: AppColor.greenNormal, height: 40, onPressed: () { + controller.addLiveStock(); Get.back(); }, ), @@ -712,45 +701,61 @@ class RequestTaggingPage extends GetView { SizedBox _buildLiveStockImage() { return SizedBox( width: Get.width, - height: 350, - child: Card( - color: Colors.white, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Expanded( - child: Container( - width: Get.width, - decoration: BoxDecoration( - color: AppColor.lightGreyNormal, - borderRadius: BorderRadius.circular(8), - ), - child: Center(child: Assets.images.placeHolder.image(height: 150, width: 200)), + 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), ), ), - SizedBox(height: 15), - Container( + ), + GestureDetector( + onTap: () async { + await controller.pickImage(controller.taggingImage); + await showCropDialog(); + }, + child: Container( width: Get.width, - height: 40, + height: 40.h, clipBehavior: Clip.antiAlias, decoration: ShapeDecoration( color: AppColor.blueNormal, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), child: Padding( - padding: const EdgeInsets.all(10.0), + padding: EdgeInsets.all(10.r), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text('تصویر دام', style: AppFonts.yekan14.copyWith(color: Colors.white)), + Text(' دوربین', style: AppFonts.yekan14.copyWith(color: Colors.white)), Icon(CupertinoIcons.arrow_up_doc, color: Colors.white), ], ), ), ), - ], - ), + ), + ], ), ), ); @@ -760,7 +765,7 @@ class RequestTaggingPage extends GetView { return OverlayDropdownWidget( items: ['نوع پلاک 1', 'نوع پلاک 2', 'نوع پلاک 3'], onChanged: (value) { - print('Selected Breed: $value'); + controller.tagType.value = value; }, itemBuilder: (item) => Text(item), labelBuilder: (item) => Text(item ?? 'نوع پلاک'), @@ -769,6 +774,7 @@ class RequestTaggingPage extends GetView { TextFiledFixedHint _buildTagNumber() { return TextFiledFixedHint( + controller: controller.herdTagController, inputType: InputType.number, hintText: 'پلاک دام', onChanged: (String value) { @@ -779,21 +785,19 @@ class RequestTaggingPage extends GetView { TextFiledFixedHint _buildFatherTagNumber() { return TextFiledFixedHint( + controller: controller.fatherTagNumberController, inputType: InputType.number, hintText: 'پلاک پدر ', - onChanged: (String value) { - eLog('father Tag: $value'); - }, + onChanged: (String value) {}, ); } TextFiledFixedHint _buildMotherTagNumber() { return TextFiledFixedHint( + controller: controller.motherTagNumberController, inputType: InputType.number, hintText: 'پلاک مادر ', - onChanged: (String value) { - eLog('Mother Tag: $value'); - }, + onChanged: (value) {}, ); } @@ -801,7 +805,8 @@ class RequestTaggingPage extends GetView { return OverlayDropdownWidget( items: ['نوع نژاد 1', 'نوع نژاد 2', 'نوع نژاد 3'], onChanged: (value) { - print('Selected Breed: $value'); + controller.breed.value = value; + eLog('Selected Breed: $value'); }, itemBuilder: (item) => Text(item), labelBuilder: (item) => Text(item ?? 'نژاد'), @@ -846,24 +851,39 @@ class RequestTaggingPage extends GetView { ); } - Container _buildLivestockBirthday() { - return 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)), - ], + 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), + ), + ], + ), ), ); } @@ -872,7 +892,7 @@ class RequestTaggingPage extends GetView { return OverlayDropdownWidget( items: ['گوسفند ماده', 'گوسفند نر', 'بز ماده', 'بز نر', 'گوساله ماده', 'گوساله نر'], onChanged: (value) { - print('Selected: $value'); + controller.species.value = value; }, itemBuilder: (item) => Text(item), labelBuilder: (item) => Text(item ?? 'گونه دام'), From aa1b9e899aba4fc333887da19aedf49956133b6e Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 11 Aug 2025 12:56:26 +0330 Subject: [PATCH 13/39] feat : cashing data in local storage and send it --- lib/main.dart | 2 +- packages/core/devtools_options.yaml | 3 + .../data/services/token_storage_service.dart | 2 +- .../core/lib/utils/local/local_utils.dart | 10 +- packages/inspection/devtools_options.yaml | 3 + packages/livestock/devtools_options.yaml | 3 + .../livestock/livestock_remote_imp.dart | 4 +- .../lib/data/model/local/live_tmp/car.dart | 39 ++++ .../lib/data/model/local/live_tmp/car.g.dart | 41 ++++ .../local/live_tmp/livestock_local_model.dart | 97 ++++++++ .../live_tmp/livestock_local_model.g.dart | 217 ++++++++++++++++++ .../service/live_stock_storage_service.dart | 40 ++++ packages/livestock/lib/data/utils/mapper.dart | 106 +++++++++ packages/livestock/lib/hive_registrar.g.dart | 29 +++ .../lib/injection/live_stock_di.dart | 8 +- .../page/request_tagging/logic.dart | 63 ++--- 16 files changed, 635 insertions(+), 32 deletions(-) create mode 100644 packages/core/devtools_options.yaml create mode 100644 packages/inspection/devtools_options.yaml create mode 100644 packages/livestock/devtools_options.yaml create mode 100644 packages/livestock/lib/data/model/local/live_tmp/car.dart create mode 100644 packages/livestock/lib/data/model/local/live_tmp/car.g.dart create mode 100644 packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.dart create mode 100644 packages/livestock/lib/data/model/local/live_tmp/livestock_local_model.g.dart create mode 100644 packages/livestock/lib/data/service/live_stock_storage_service.dart create mode 100644 packages/livestock/lib/data/utils/mapper.dart create mode 100644 packages/livestock/lib/hive_registrar.g.dart 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/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/data/services/token_storage_service.dart b/packages/core/lib/data/services/token_storage_service.dart index ab551c9..6d0f3c3 100644 --- a/packages/core/lib/data/services/token_storage_service.dart +++ b/packages/core/lib/data/services/token_storage_service.dart @@ -21,7 +21,7 @@ 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'); 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/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/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/data_source/remote/livestock/livestock_remote_imp.dart b/packages/livestock/lib/data/data_source/remote/livestock/livestock_remote_imp.dart index 642c3ed..f6cfb01 100644 --- 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 @@ -33,8 +33,8 @@ class LivestockRemoteDataSourceImp implements LivestockRemoteDataSource { try { Dio dio = Dio(); dio.interceptors.add(PrettyDioLogger( - requestBody: true, - responseBody: true, + requestBody: false, + responseBody: false, requestHeader: true, responseHeader: true, error: true, diff --git a/packages/livestock/lib/data/model/local/live_tmp/car.dart b/packages/livestock/lib/data/model/local/live_tmp/car.dart new file mode 100644 index 0000000..19bb320 --- /dev/null +++ b/packages/livestock/lib/data/model/local/live_tmp/car.dart @@ -0,0 +1,39 @@ +import 'package:rasadyar_core/core.dart'; + + +part 'car.g.dart'; + + +@HiveType(typeId: 50) +class CarsLocal extends HiveObject { + @HiveField(0) + String? name; + + @HiveField(1) + String? price; + + CarsLocal({this.name, this.price}); + + factory CarsLocal.fromJson(Map json) { + return CarsLocal(name: json['name'] as String?, price: json['price'] as String?); + } + + Map toJson() { + return {'name': name, 'price': price}; + } +} + +class Cars { + String? name; + String? price; + + Cars({this.name, this.price}); + + factory Cars.fromJson(Map json) { + return Cars(name: json['name'] as String?, price: json['price'] as String?); + } + + Map toJson() { + return {'name': name, 'price': price}; + } +} diff --git a/packages/livestock/lib/data/model/local/live_tmp/car.g.dart b/packages/livestock/lib/data/model/local/live_tmp/car.g.dart new file mode 100644 index 0000000..77d0985 --- /dev/null +++ b/packages/livestock/lib/data/model/local/live_tmp/car.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'car.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class CarsLocalAdapter extends TypeAdapter { + @override + final typeId = 50; + + @override + CarsLocal read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return CarsLocal(name: fields[0] as String?, price: fields[1] as String?); + } + + @override + void write(BinaryWriter writer, CarsLocal obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.name) + ..writeByte(1) + ..write(obj.price); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is CarsLocalAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} 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/service/live_stock_storage_service.dart b/packages/livestock/lib/data/service/live_stock_storage_service.dart new file mode 100644 index 0000000..1d3e60a --- /dev/null +++ b/packages/livestock/lib/data/service/live_stock_storage_service.dart @@ -0,0 +1,40 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/data/model/local/live_tmp/car.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; + late IsolatedBox _carbox; + + @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..715ff9e --- /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/car.dart'; +import 'package:rasadyar_livestock/data/model/local/live_tmp/livestock_local_model.dart'; + +extension HiveRegistrar on HiveInterface { + void registerAdapters() { + registerAdapter(CarsLocalAdapter()); + registerAdapter(HerdLocalAdapter()); + registerAdapter(LivestockLocalAdapter()); + registerAdapter(LivestockLocalModelAdapter()); + registerAdapter(LocationLocalAdapter()); + registerAdapter(RancherLocalAdapter()); + } +} + +extension IsolatedHiveRegistrar on IsolatedHiveInterface { + void registerAdapters() { + registerAdapter(CarsLocalAdapter()); + registerAdapter(HerdLocalAdapter()); + registerAdapter(LivestockLocalAdapter()); + registerAdapter(LivestockLocalModelAdapter()); + registerAdapter(LocationLocalAdapter()); + registerAdapter(RancherLocalAdapter()); + } +} diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index d374105..eb099c9 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -8,14 +8,20 @@ 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/data/service/live_stock_storage_service.dart'; +import 'package:rasadyar_livestock/hive_registrar.g.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; GetIt get diLiveStock => GetIt.instance; Future setupLiveStockDI() async { diLiveStock.registerSingleton(DioErrorHandler()); - + await IsolatedHive.initFlutter(); + IsolatedHive.registerAdapters(); + iLog("Sssssssssssssssssssss"); final tokenService = Get.find(); + Get.put(LiveStockStorageService()); + if (tokenService.baseurl.value == null) { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index 245ae69..0625a2c 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,16 +1,18 @@ import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; 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'; 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; @@ -82,19 +84,17 @@ class RequestTaggingLogic extends GetxController { rancher.value = Rancher( name: 'حسن حسنی', phone: '09121234567', - image: - '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', + image: '/9j/4nd9KcTTcWUsuoF0cSwuZSjYX', ); herd.value = Herd( location: Location(lat: 35.825081, lng: 50.948177), address: 'استان البرز, بخش مرکزی کرج, کرج, منطقه ۵, دهقان ویلا, بلوار سرداران', - image: - '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', + image: '/9j/4QL6RXhpZgAATU0AKgAA', ); var s = List.generate( - 10000, + 10_000, (index) => Livestock( sex: index % 2 == 0 ? 'نر' : 'ماده', tagNumber: index.toString(), @@ -104,8 +104,7 @@ class RequestTaggingLogic extends GetxController { breed: index % 2 == 0 ? 'گوسفند ماده' : 'گاو ماده', tagType: index % 2 == 0 ? 'نوع 1' : 'نوع 2', dateOfBirth: "23/10/2023", - image: - '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', + image: '/9j/4QLmRXhpZgAATU', ), ); livestockList.addAll(s); @@ -282,36 +281,48 @@ class RequestTaggingLogic extends GetxController { } Future createTaggingLiveStock() async { - isLoading.value = true; + // isLoading.value = true; if (livestockList.isEmpty) { Get.snackbar('Error', 'Please fill all required fields'); return; } - var livestockBatch = []; + var batches = chunkedList( + livestockList, + 500, + ).map((e) => LivestockData(rancher: rancher.value, herd: herd.value, livestock: e)); - for (int i = 0; i < livestockList.length; i += 500) { - var tmp = livestockList.sublist(i, min(i + 500, livestockList.length)); + await liveStockStorageService.saveBulkLiveStockData(batches); - livestockBatch.add( - safeCall( - call: () => livestockRepository.createTaggingLiveStock( - data: LivestockData(livestock: tmp, herd: herd.value, rancher: rancher.value), - ), - onSuccess: (result) {}, - onError: (error, stackTrace) { - Get.snackbar( - 'Error', - 'Failed to create livestock tagging request: ${error.toString()}', - ); - }, - ), + 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) {}, ); } - await Future.wait(livestockBatch); + 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( From 9b04c0374bd369e2d2732d3ecbcae088cdc2d16b Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 12 Aug 2025 08:58:54 +0330 Subject: [PATCH 14/39] chore : update some lib and remove unused lib --- packages/core/lib/core.dart | 1 - packages/core/pubspec.lock | 52 ++++++++++++------- packages/core/pubspec.yaml | 11 ++-- .../pages/location_details/view.dart | 5 +- .../page/map/widget/map_widget/view.dart | 3 +- 5 files changed, 45 insertions(+), 27 deletions(-) diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 1539941..624f706 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -13,7 +13,6 @@ 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'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index 936d0e5..e70dda0 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: @@ -185,6 +185,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: @@ -269,10 +285,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: @@ -517,14 +533,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 +633,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: @@ -1005,6 +1013,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" package_config: dependency: transitive description: @@ -1017,18 +1033,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: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 90dd599..1c24c3c 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -14,7 +14,7 @@ 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 @@ -42,7 +42,7 @@ dependencies: #SVG flutter_svg: ^2.2.0 - font_awesome_flutter: ^10.8.0 + #Shimmer shimmer: ^3.0.0 @@ -54,7 +54,7 @@ dependencies: get: ^4.7.2 ##Di - get_it: ^8.0.3 + get_it: ^8.2.0 #other permission_handler: ^12.0.1 @@ -65,7 +65,7 @@ dependencies: intl: ^0.20.2 #INITENT - android_intent_plus: ^5.3.0 + android_intent_plus: ^5.3.1 #Map flutter_map: ^7.0.0 @@ -75,7 +75,8 @@ dependencies: 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 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/livestock/lib/presentation/page/map/widget/map_widget/view.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart index 30c7a42..75eb4b7 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/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_livestock/presentation/routes/app_pages.dart'; @@ -182,7 +183,7 @@ class MapWidget extends GetView { ignoreSafeArea: false, ); }, - icon: FaIcon(FontAwesomeIcons.locationPin, color: AppColor.error), + icon: Icon(CupertinoIcons.location_solid, color: AppColor.error), ), ), ) From 7c3c1280b28030ee1e52e29480f083afbe57e163 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 19 Aug 2025 11:22:34 +0330 Subject: [PATCH 15/39] feat : new injection logic test : some file :) chore : upgrade android gradle --- .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle.kts | 4 +- .../service/app_navigation_observer.dart | 9 +- lib/presentation/pages/modules/logic.dart | 20 +- lib/presentation/pages/splash/logic.dart | 5 +- lib/presentation/routes/app_pages.dart | 12 +- packages/chicken/pubspec.yaml | 2 +- packages/core/.gitignore | 33 +++ .../build/unit_test_assets/AssetManifest.json | 1 - .../lib/assets/flutter_map_logo.png | Bin 2424 -> 0 bytes packages/core/lib/core.dart | 1 + .../lib/data/services/network_status.dart | 24 +++ .../remote/app_interceptor_n.dart | 168 +++++++++++++++ packages/core/lib/injection/di.dart | 6 +- .../lib/utils/network/safe_call_utils.dart | 7 +- packages/core/pubspec.lock | 158 ++++++++++---- packages/core/pubspec.yaml | 9 +- .../remote/app_interceptor_test.dart | 106 +++++++++ .../infrastructure/remote/dio_form_data.dart | 23 -- .../remote/dio_form_data_test.dart | 55 +++++ .../remote/dio_remote_test.dart | 201 ++++++++++++++++++ .../infrastructure/remote/dio_response.dart | 20 -- .../remote/dio_response_test.dart | 60 ++++++ .../remote/interfaces/i_form_data.dart | 6 - .../remote/interfaces/i_http_client.dart | 53 ----- .../remote/interfaces/i_http_response.dart | 6 - .../remote/interfaces/i_remote.dart | 4 - packages/inspection/pubspec.lock | 118 +++++----- packages/inspection/pubspec.yaml | 2 +- .../lib/data/common/checkk_di_middleware.dart | 15 ++ .../local/tmp/tmp_local_data-source.dart | 18 ++ .../lib/data/model/local/live_tmp/car.dart | 39 ---- .../model/local/location/tmp_locations.dart | 16 ++ .../tmp_locations.g.dart} | 20 +- .../livestock/livestock_repository.dart | 5 +- .../livestock/livestock_repository_imp.dart | 36 ++++ .../service/live_stock_storage_service.dart | 3 +- packages/livestock/lib/hive_registrar.g.dart | 6 +- .../lib/injection/live_stock_di.dart | 6 +- .../page/map/widget/map_widget/logic.dart | 34 +-- .../page/map/widget/map_widget/view.dart | 11 + .../lib/presentation/page/root/logic.dart | 51 ++++- .../lib/presentation/page/root/view.dart | 1 + .../lib/presentation/routes/app_pages.dart | 2 + packages/livestock/pubspec.yaml | 4 +- pubspec.lock | 130 ++++++----- pubspec.yaml | 4 +- 47 files changed, 1139 insertions(+), 377 deletions(-) create mode 100644 packages/core/.gitignore delete mode 100644 packages/core/build/unit_test_assets/AssetManifest.json delete mode 100644 packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png create mode 100644 packages/core/lib/data/services/network_status.dart create mode 100644 packages/core/lib/infrastructure/remote/app_interceptor_n.dart create mode 100644 packages/core/test/infrastructure/remote/app_interceptor_test.dart delete mode 100644 packages/core/test/infrastructure/remote/dio_form_data.dart create mode 100644 packages/core/test/infrastructure/remote/dio_form_data_test.dart delete mode 100644 packages/core/test/infrastructure/remote/dio_response.dart create mode 100644 packages/core/test/infrastructure/remote/dio_response_test.dart delete mode 100644 packages/core/test/infrastructure/remote/interfaces/i_form_data.dart delete mode 100644 packages/core/test/infrastructure/remote/interfaces/i_http_client.dart delete mode 100644 packages/core/test/infrastructure/remote/interfaces/i_http_response.dart delete mode 100644 packages/core/test/infrastructure/remote/interfaces/i_remote.dart create mode 100644 packages/livestock/lib/data/common/checkk_di_middleware.dart create mode 100644 packages/livestock/lib/data/data_source/local/tmp/tmp_local_data-source.dart delete mode 100644 packages/livestock/lib/data/model/local/live_tmp/car.dart create mode 100644 packages/livestock/lib/data/model/local/location/tmp_locations.dart rename packages/livestock/lib/data/model/local/{live_tmp/car.g.dart => location/tmp_locations.g.dart} (63%) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..efdcc4a 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.11.1-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/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 3fe440f..9c49563 100644 --- a/lib/infrastructure/service/app_navigation_observer.dart +++ b/lib/infrastructure/service/app_navigation_observer.dart @@ -27,11 +27,10 @@ class CustomNavigationObserver extends NavigatorObserver { await setupInspectionDI(); } else if (!_isWorkDone && (routeName == LiveStockRoutes.init || routeName == LiveStockRoutes.auth)) { - _isWorkDone = true; - await setupLiveStockDI(); + } super.didPush(route, previousRoute); - tLog('CustomNavigationObserver: didPush - $routeName'); + // tLog('CustomNavigationObserver: didPush - $routeName'); } @override @@ -43,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/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 8985caf..a82f9b1 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -1,8 +1,5 @@ -import 'package:rasadyar_chicken/presentation/routes/routes.dart'; +import 'package:rasadyar_app/presentation/routes/app_pages.dart'; import 'package:rasadyar_core/core.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 ModulesLogic extends GetxController { TokenStorageService tokenService = Get.find(); @@ -32,21 +29,20 @@ class ModulesLogic extends GetxController { } Future navigateToModule(Module module) async { - if (module == Module.inspection) { - Get.offAllNamed(InspectionRoutes.init); - } else if (module == Module.liveStocks) { - await setupLiveStockDI(); - Get.offAllNamed(LiveStockRoutes.init); - } else if (module == Module.chicken) { - Get.offAllNamed(ChickenRoutes.init); + var target = getTargetPage(module).entries.first; + + if (target.value != null) { + await target.value; } + + Get.offAllNamed(target.key); } void onTapCard(Module module, int index) async { isLoading.value = true; selectedIndex.value = index; saveModule(module); - await Future.delayed(Duration(milliseconds: 800)); // Simulate loading delay + await Future.delayed(Duration(milliseconds: 500)); // Simulate loading delay navigateToModule(module); } } diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart index a9f1a8d..2250dbe 100644 --- a/lib/presentation/pages/splash/logic.dart +++ b/lib/presentation/pages/splash/logic.dart @@ -155,7 +155,10 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { tokenService.getModule(); final module = tokenService.appModule.value; final target = getTargetPage(module); - Get.offAndToNamed(target); + 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..dbb99f0 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -4,8 +4,10 @@ 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/inspection.dart'; +import 'package:rasadyar_livestock/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; part 'app_paths.dart'; @@ -38,15 +40,15 @@ sealed class AppPages { ]; } -String getTargetPage(Module? value) { +Map?> getTargetPage(Module? value) { switch (value) { case Module.inspection: - return InspectionRoutes.init; + return {InspectionRoutes.init:null}; case Module.liveStocks: - return LiveStockRoutes.init; + return {LiveStockRoutes.init: setupLiveStockDI()}; case Module.chicken: - return ChickenRoutes.init; + return {ChickenRoutes.init : null}; default: - return AppPaths.moduleList; + return {AppPaths.moduleList : null}; } } 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..02b7cc0 --- /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 + +# 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 8603d0a3d2a91580f77171968c7d13e73fd1482a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2424 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 _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/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/injection/di.dart b/packages/core/lib/injection/di.dart index d5bc011..f59ff1d 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -1,15 +1,15 @@ 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/data/services/network_status.dart'; import 'package:rasadyar_core/infrastructure/local/hive_local_storage.dart'; final diCore = GetIt.instance; Future setupAllCoreProvider() async { - await _setUpLogger(); await _setupLocalStorage(); await _setupRemote(); + diCore.registerSingleton(NetworkStatus()..startListening()); await diCore.allReady(); } @@ -23,4 +23,4 @@ Future _setupLocalStorage() async { Future _setupRemote() async { // diCore.registerSingleton(HiveLocalStorage()); -} \ 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/pubspec.lock b/packages/core/pubspec.lock index e70dda0..bbc6b7a 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -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: @@ -153,6 +153,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: @@ -209,6 +217,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: @@ -761,66 +777,66 @@ packages: 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: 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: @@ -889,26 +905,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: @@ -1021,6 +1037,14 @@ packages: 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" package_config: dependency: transitive description: @@ -1161,10 +1185,10 @@ 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: @@ -1285,6 +1309,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: @@ -1322,6 +1362,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.6" + 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: @@ -1378,14 +1434,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: @@ -1454,10 +1526,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: @@ -1498,6 +1570,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: @@ -1555,5 +1635,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 1c24c3c..0168865 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: @@ -17,7 +17,7 @@ dependencies: package_info_plus: ^8.3.1 ##image_picker - image_picker: ^1.1.2 + image_picker: ^1.2.0 image_cropper: ^9.1.0 #UI @@ -58,7 +58,7 @@ dependencies: #other permission_handler: ^12.0.1 - persian_datetime_picker: ^3.1.0 + persian_datetime_picker: ^3.1.1 encrypt: ^5.0.3 #L10N tools @@ -89,10 +89,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 + 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/pubspec.lock b/packages/inspection/pubspec.lock index 126a3f1..c3a0fb6 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: @@ -193,6 +193,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 +301,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: @@ -533,14 +549,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 +649,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: @@ -769,66 +777,66 @@ packages: 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: @@ -897,26 +905,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: @@ -1021,6 +1029,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: @@ -1041,18 +1057,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: @@ -1169,10 +1185,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: @@ -1429,26 +1445,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: @@ -1517,10 +1533,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: @@ -1626,5 +1642,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..52fa6f3 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: 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/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/model/local/live_tmp/car.dart b/packages/livestock/lib/data/model/local/live_tmp/car.dart deleted file mode 100644 index 19bb320..0000000 --- a/packages/livestock/lib/data/model/local/live_tmp/car.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:rasadyar_core/core.dart'; - - -part 'car.g.dart'; - - -@HiveType(typeId: 50) -class CarsLocal extends HiveObject { - @HiveField(0) - String? name; - - @HiveField(1) - String? price; - - CarsLocal({this.name, this.price}); - - factory CarsLocal.fromJson(Map json) { - return CarsLocal(name: json['name'] as String?, price: json['price'] as String?); - } - - Map toJson() { - return {'name': name, 'price': price}; - } -} - -class Cars { - String? name; - String? price; - - Cars({this.name, this.price}); - - factory Cars.fromJson(Map json) { - return Cars(name: json['name'] as String?, price: json['price'] as String?); - } - - Map toJson() { - return {'name': name, 'price': price}; - } -} 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/live_tmp/car.g.dart b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart similarity index 63% rename from packages/livestock/lib/data/model/local/live_tmp/car.g.dart rename to packages/livestock/lib/data/model/local/location/tmp_locations.g.dart index 77d0985..2c70c49 100644 --- a/packages/livestock/lib/data/model/local/live_tmp/car.g.dart +++ b/packages/livestock/lib/data/model/local/location/tmp_locations.g.dart @@ -1,32 +1,34 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'car.dart'; +part of 'tmp_locations.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** -class CarsLocalAdapter extends TypeAdapter { +class TmpLocationsAdapter extends TypeAdapter { @override - final typeId = 50; + final typeId = 100; @override - CarsLocal read(BinaryReader reader) { + TmpLocations read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; - return CarsLocal(name: fields[0] as String?, price: fields[1] as String?); + return TmpLocations() + ..lat = (fields[0] as num?)?.toDouble() + ..long = (fields[1] as num?)?.toDouble(); } @override - void write(BinaryWriter writer, CarsLocal obj) { + void write(BinaryWriter writer, TmpLocations obj) { writer ..writeByte(2) ..writeByte(0) - ..write(obj.name) + ..write(obj.lat) ..writeByte(1) - ..write(obj.price); + ..write(obj.long); } @override @@ -35,7 +37,7 @@ class CarsLocalAdapter extends TypeAdapter { @override bool operator ==(Object other) => identical(this, other) || - other is CarsLocalAdapter && + other is TmpLocationsAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart index 7a1aaca..77b1954 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -1,6 +1,5 @@ +import 'package:rasadyar_core/core.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 'package:rasadyar_livestock/data/model/response/live_tmp/livestock_model.dart'; abstract class LivestockRepository { @@ -11,4 +10,6 @@ abstract class LivestockRepository { 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 index 2911c6c..53d75d1 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -1,4 +1,9 @@ +import 'package:latlong2/latlong.dart'; +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'; @@ -24,4 +29,35 @@ class LivestockRepositoryImp implements LivestockRepository { 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 index 1d3e60a..35b5a3e 100644 --- a/packages/livestock/lib/data/service/live_stock_storage_service.dart +++ b/packages/livestock/lib/data/service/live_stock_storage_service.dart @@ -1,5 +1,4 @@ import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/data/model/local/live_tmp/car.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'; @@ -7,7 +6,7 @@ import 'package:rasadyar_livestock/data/utils/mapper.dart'; class LiveStockStorageService extends GetxService { final String _liveStockBoxName = 'LiveStockBox'; late IsolatedBox _LiveStockbox; - late IsolatedBox _carbox; + @override void onInit() { diff --git a/packages/livestock/lib/hive_registrar.g.dart b/packages/livestock/lib/hive_registrar.g.dart index 715ff9e..a9f8f96 100644 --- a/packages/livestock/lib/hive_registrar.g.dart +++ b/packages/livestock/lib/hive_registrar.g.dart @@ -3,27 +3,27 @@ // Check in to version control import 'package:hive_ce/hive.dart'; -import 'package:rasadyar_livestock/data/model/local/live_tmp/car.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(CarsLocalAdapter()); registerAdapter(HerdLocalAdapter()); registerAdapter(LivestockLocalAdapter()); registerAdapter(LivestockLocalModelAdapter()); registerAdapter(LocationLocalAdapter()); registerAdapter(RancherLocalAdapter()); + registerAdapter(TmpLocationsAdapter()); } } extension IsolatedHiveRegistrar on IsolatedHiveInterface { void registerAdapters() { - registerAdapter(CarsLocalAdapter()); 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 index eb099c9..fad3b19 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -20,7 +20,7 @@ Future setupLiveStockDI() async { IsolatedHive.registerAdapters(); iLog("Sssssssssssssssssssss"); final tokenService = Get.find(); - Get.put(LiveStockStorageService()); + if (tokenService.baseurl.value == null) { @@ -31,7 +31,7 @@ Future setupLiveStockDI() async { diLiveStock.registerLazySingleton( () => AppInterceptor( refreshTokenCallback: () async { - // Use lazy access to avoid circular dependency + /* // Use lazy access to avoid circular dependency final authRepository = diLiveStock.get(); final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { @@ -39,7 +39,7 @@ Future setupLiveStockDI() async { authRequest: {'refresh': tokenService.refreshToken.value}, ); return newToken?.access; - } + }*/ return null; }, saveTokenCallback: (String newToken) async { diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index 53575a7..4638752 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -2,7 +2,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.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/injection/live_stock_di.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; enum ErrorLocationType { serviceDisabled, permissionDenied, none } @@ -11,7 +14,6 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { String tileType = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; RxDouble currentZoom = 15.0.obs; - RxList allMarkers = [].obs; Rx mapController = MapController().obs; RxList errorLocationType = RxList(); @@ -19,19 +21,9 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; - RxList markerLocations = [ - 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), - ].obs; + RxList markerLocations = RxList(); + RootLogic rootLogic = Get.find(); + late LivestockRepository repository ; @override void onInit() { @@ -67,6 +59,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { void onReady() { super.onReady(); determineCurrentPosition(); + // getLoc(); } @override @@ -158,5 +151,14 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { return rawMarkers.where((marker) => distance(center, marker) <= radiusInMeters).toList(); } - +/* Future getLoc() async { + await Future.delayed(Duration(seconds: 3)); + await safeCall( + call: () async => repository.getLocations(), + onSuccess: (result) { + markerLocations.addAll(result); + }, + onError: (error, stackTrace) {}, + ); + }*/ } 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 index 75eb4b7..5bbc67d 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -1,6 +1,7 @@ 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'; @@ -148,6 +149,16 @@ class MapWidget extends GetView { ); }, 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, diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 750671f..c39aa87 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,5 +1,11 @@ +import 'dart:async'; +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.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/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/page/map/view.dart'; import 'package:rasadyar_livestock/presentation/page/profile/view.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; @@ -28,10 +34,49 @@ class RootLogic extends GetxController { ]; RxInt currentIndex = 0.obs; - - TokenStorageService tokenService = Get.find(); + late StreamSubscription> connectivitySubscription; + RxList connectivityResults = [].obs; + + @override + void onInit() { + super.onInit(); + connectivitySubscription = Connectivity().onConnectivityChanged.listen((result) { + if (result.isNotEmpty) { + connectivityResults.assignAll(result); + } + }); + + /* GetIt.instance.allReady().then((value) async { + await diLiveStock.get().addLocations(generateRandomPoints()); + });*/ + } + + List generateRandomPoints() { + final Random random = Random(); + final double centerLat = 35.824891; + final double centerLon = 50.948025; + final double radiusKm = 1.0; + final double kmToDegLat = 1 / 111.0; // 1 km ≈ 0.009° latitude + final double kmToDegLon = 1 / (111.0 * cos(centerLat * pi / 180)); // Adjust for longitude + + List points = []; + for (int i = 0; i < 100; i++) { + // Generate random angle (0 to 2π) and random radius (0 to 1 km, using sqrt for uniform distribution) + double theta = random.nextDouble() * 2 * pi; + double r = + sqrt(random.nextDouble()) * radiusKm; // Square root for uniform distribution in circle + // Convert polar coordinates to Cartesian, then to LatLng + double deltaLat = r * cos(theta) * kmToDegLat; + double deltaLon = r * sin(theta) * kmToDegLon; + double newLat = centerLat + deltaLat; + double newLon = centerLon + deltaLon; + points.add(LatLng(newLat, newLon)); + } + return points; + } + @override void onReady() { // TODO: implement onReady @@ -40,7 +85,7 @@ class RootLogic extends GetxController { @override void onClose() { - // TODO: implement onClose + connectivitySubscription.cancel(); super.onClose(); } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 3544cef..4bba1e0 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -23,6 +23,7 @@ class RootPage extends GetView { final navigatorKey = Get.nestedKey(currentIndex); if (currentIndex.value == 0 && + navigatorKey != null && navigatorKey.currentState != null) { if (navigatorKey.currentState!.canPop()) { diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 411f5c0..6ff7302 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -14,6 +14,8 @@ 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'; sealed class LiveStockPages { diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml index 5b61757..ffa9508 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' # repository: https://github.com/my_org/my_repo environment: - sdk: ^3.8.1 + sdk: ^3.9.0 dependencies: @@ -24,7 +24,7 @@ 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 diff --git a/pubspec.lock b/pubspec.lock index c98f20e..317ee5e 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: @@ -201,6 +201,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 +301,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: @@ -541,14 +557,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 +657,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: @@ -777,66 +785,66 @@ packages: 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: @@ -905,26 +913,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: @@ -1029,6 +1037,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" package_config: dependency: transitive description: @@ -1041,18 +1057,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: @@ -1169,10 +1185,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: @@ -1418,10 +1434,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: @@ -1490,10 +1506,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: @@ -1591,5 +1607,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..8c503e9 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,7 +36,7 @@ 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 From b2f26cdffdb654f618a1648a8fb3fb2b2aae927e Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 19 Aug 2025 11:56:04 +0330 Subject: [PATCH 16/39] feat : local location loading --- .../livestock/livestock_repository.dart | 4 ++-- .../livestock/livestock_repository_imp.dart | 16 ++++++++-------- .../livestock/lib/injection/live_stock_di.dart | 16 ++++++++++------ .../page/map/widget/map_widget/logic.dart | 8 ++++---- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart index 77b1954..2bd095b 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository.dart @@ -10,6 +10,6 @@ abstract class LivestockRepository { Future createTaggingLiveStock({required LivestockData data}); -/* Future> getLocations(); - Future addLocations(List latList);*/ + 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 index 53d75d1..80fb768 100644 --- a/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart +++ b/packages/livestock/lib/data/repository/livestock/livestock_repository_imp.dart @@ -1,4 +1,3 @@ -import 'package:latlong2/latlong.dart'; 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'; @@ -11,8 +10,9 @@ import 'livestock_repository.dart'; class LivestockRepositoryImp implements LivestockRepository { final LivestockRemoteDataSource livestockRemote; + final TmpLocalDataSource tmpLocalDataSource; - LivestockRepositoryImp({required this.livestockRemote}); + LivestockRepositoryImp({required this.livestockRemote,required this.tmpLocalDataSource}); @override Future getLocationDetails({ @@ -29,7 +29,7 @@ class LivestockRepositoryImp implements LivestockRepository { Future createTaggingLiveStock({required LivestockData data}) async { return await livestockRemote.createTaggingLiveStock(data: data); } -/* + @override Future> getLocations() async { if (NetworkStatus().isConnected.value) { @@ -47,17 +47,17 @@ class LivestockRepositoryImp implements LivestockRepository { LatLng(35.832000, 50.956055), ]; } else { - *//*var res = await tmpLocalDataSource.getLocations(); + var res = await tmpLocalDataSource.getLocations(); - return res.map((e) => LatLng(e.lat ?? 0.0, e.long ?? 0.0)).toList();*//* + return res.map((e) => LatLng(e.lat ?? 0.0, e.long ?? 0.0)).toList(); } } @override Future addLocations(List latList) async { - *//* await tmpLocalDataSource.addLocations( + await tmpLocalDataSource.addLocations( latList.map((e) => TmpLocations(lat: e.latitude, long: e.longitude)).toList(), - );*//* + ); iLog("it is done"); - }*/ + } } diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index fad3b19..31481c7 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -8,21 +8,19 @@ 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/data/service/live_stock_storage_service.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(); - iLog("Sssssssssssssssssssss"); final tokenService = Get.find(); - - if (tokenService.baseurl.value == null) { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } @@ -31,7 +29,7 @@ Future setupLiveStockDI() async { diLiveStock.registerLazySingleton( () => AppInterceptor( refreshTokenCallback: () async { - /* // Use lazy access to avoid circular dependency + /* // Use lazy access to avoid circular dependency final authRepository = diLiveStock.get(); final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { @@ -80,8 +78,14 @@ Future setupLiveStockDI() async { diLiveStock.registerLazySingleton( () => LivestockRemoteDataSourceImp(), ); + + diLiveStock.registerLazySingleton(() => TmpLocalDataSource()); + diLiveStock.registerLazySingleton( - () => LivestockRepositoryImp(livestockRemote: diLiveStock.get()), + () => LivestockRepositoryImp( + livestockRemote: diLiveStock.get(), + tmpLocalDataSource: diLiveStock.get(), + ), ); //endregion diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index 4638752..dbd0788 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -23,7 +23,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { RxList markerLocations = RxList(); RootLogic rootLogic = Get.find(); - late LivestockRepository repository ; + LivestockRepository repository = diLiveStock.get(); @override void onInit() { @@ -59,7 +59,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { void onReady() { super.onReady(); determineCurrentPosition(); - // getLoc(); + getLoc(); } @override @@ -151,7 +151,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { return rawMarkers.where((marker) => distance(center, marker) <= radiusInMeters).toList(); } -/* Future getLoc() async { + Future getLoc() async { await Future.delayed(Duration(seconds: 3)); await safeCall( call: () async => repository.getLocations(), @@ -160,5 +160,5 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { }, onError: (error, stackTrace) {}, ); - }*/ + } } From 80e3b0199855abeda0296e22d1545f288b831afd Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 20 Aug 2025 11:05:31 +0330 Subject: [PATCH 17/39] feat : cashing map from internet --- packages/core/lib/core.dart | 3 ++ packages/core/lib/injection/di.dart | 9 ++++ packages/core/pubspec.lock | 32 +++++++++++++++ packages/core/pubspec.yaml | 2 + .../livestock/lib/data/common/constant.dart | 1 + .../lib/injection/live_stock_di.dart | 8 +++- .../page/map/widget/map_widget/logic.dart | 41 ++++++++++++++++++- .../page/map/widget/map_widget/view.dart | 4 +- pubspec.lock | 32 +++++++++++++++ 9 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 packages/livestock/lib/data/common/constant.dart diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 7f243b3..bbce482 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -7,9 +7,12 @@ 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'; + 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'; diff --git a/packages/core/lib/injection/di.dart b/packages/core/lib/injection/di.dart index f59ff1d..e6505b4 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -1,3 +1,4 @@ +import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; import 'package:get_it/get_it.dart'; import 'package:logger/logger.dart'; import 'package:rasadyar_core/data/services/network_status.dart'; @@ -10,6 +11,14 @@ Future setupAllCoreProvider() async { await _setupLocalStorage(); await _setupRemote(); diCore.registerSingleton(NetworkStatus()..startListening()); + + //max 500MB Map Cashing + await diCore.registerSingleton( + FMTCObjectBoxBackend().initialise(maxDatabaseSize: 500 * 1024 * 1024), + ); + + + await diCore.allReady(); } diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index bbc6b7a..f680175 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -385,6 +385,14 @@ 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 @@ -451,6 +459,14 @@ 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: @@ -1045,6 +1061,22 @@ 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" package_config: dependency: transitive description: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 0168865..fbaa949 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -71,6 +71,8 @@ dependencies: 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 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/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index 31481c7..328896d 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -1,4 +1,5 @@ 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'; @@ -25,11 +26,14 @@ Future setupLiveStockDI() async { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } + await FMTCStore(mapStoreKey).manage.create(); + + // First register AppInterceptor with lazy callbacks diLiveStock.registerLazySingleton( () => AppInterceptor( refreshTokenCallback: () async { - /* // Use lazy access to avoid circular dependency + // Use lazy access to avoid circular dependency final authRepository = diLiveStock.get(); final hasAuthenticated = await authRepository.hasAuthenticated(); if (hasAuthenticated) { @@ -37,7 +41,7 @@ Future setupLiveStockDI() async { authRequest: {'refresh': tokenService.refreshToken.value}, ); return newToken?.access; - }*/ + } return null; }, saveTokenCallback: (String newToken) async { diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index dbd0788..d625e6b 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -1,9 +1,10 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.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/data/repository/livestock/livestock_repository_imp.dart'; import 'package:rasadyar_livestock/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; @@ -21,9 +22,11 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; + late FMTCTileProvider tileProvider; + RxList markerLocations = RxList(); RootLogic rootLogic = Get.find(); - LivestockRepository repository = diLiveStock.get(); + LivestockRepository repository = diLiveStock.get(); @override void onInit() { @@ -53,6 +56,10 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { errorLocationType.remove(ErrorLocationType.serviceDisabled); } }); + + tileProvider = FMTCTileProvider(stores: {mapStoreKey: BrowseStoreStrategy.readUpdateCreate}); + + repository.addLocations(generateRandomLocations(currentLocation.value, 10, 100)); } @override @@ -60,6 +67,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { super.onReady(); determineCurrentPosition(); getLoc(); + } @override @@ -156,9 +164,38 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { await safeCall( call: () async => repository.getLocations(), onSuccess: (result) { + iLog("OOOpssss => ${result.length}"); markerLocations.addAll(result); }, onError: (error, stackTrace) {}, ); } + + List generateRandomLocations(LatLng currentPosition, double radiusInKm, int count) { + final random = Random(); + final locations = []; + + 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 index 5bbc67d..b89b725 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -104,6 +104,7 @@ class MapWidget extends GetView { flags: InteractiveFlag.all & ~InteractiveFlag.rotate, ), initialZoom: 15, + onPositionChanged: (camera, hasGesture) { controller.currentZoom.value = camera.zoom; /* controller.debouncedUpdateVisibleMarkers( @@ -117,6 +118,7 @@ class MapWidget extends GetView { TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', userAgentPackageName: 'ir.mnpc.rasadyar', + tileProvider: controller.tileProvider, ), ObxValue((markers) { @@ -153,8 +155,6 @@ class MapWidget extends GetView { top: 15, left: 20, child: ObxValue((status) { - - return Text("Connection: ${status.value}", style: TextStyle(fontSize: 20)); }, NetworkStatus().isConnected), ), diff --git a/pubspec.lock b/pubspec.lock index 317ee5e..74f7cb2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -385,6 +385,14 @@ 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 @@ -459,6 +467,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: @@ -1045,6 +1061,22 @@ packages: 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" package_config: dependency: transitive description: From 3bd3ecbf50305dd54bb361fffebb92c410cf95dc Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 25 Aug 2025 09:56:50 +0330 Subject: [PATCH 18/39] fix : twice back press for exit application on live stock --- .../page/map/widget/map_widget/logic.dart | 6 +-- .../lib/presentation/page/root/logic.dart | 16 ++++--- .../lib/presentation/page/root/view.dart | 47 ++++++++++--------- .../lib/presentation/routes/app_routes.dart | 1 + 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index d625e6b..2c1cbd5 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -67,7 +67,6 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { super.onReady(); determineCurrentPosition(); getLoc(); - } @override @@ -189,13 +188,12 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { final newLat = currentPosition.latitude + (dy / 111000.0); // 1 درجه lon ≈ 111km * cos(lat) - final newLng = currentPosition.longitude + - (dx / (111000.0 * cos(currentPosition.latitude * pi / 180))); + 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/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index c39aa87..5d0805c 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -3,9 +3,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.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/injection/live_stock_di.dart'; import 'package:rasadyar_livestock/presentation/page/map/view.dart'; import 'package:rasadyar_livestock/presentation/page/profile/view.dart'; import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; @@ -14,9 +11,13 @@ import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class RootLogic extends GetxController { List pages = [ - MapPage(), Navigator( key: Get.nestedKey(0), + onGenerateRoute: (settings) => GetPageRoute(page: () => MapPage()), + ), + + Navigator( + key: Get.nestedKey(1), initialRoute: LiveStockRoutes.requests, onGenerateRoute: (settings) { switch (settings.name) { @@ -30,7 +31,10 @@ class RootLogic extends GetxController { }, ), - ProfilePage(), + Navigator( + key: Get.nestedKey(2), + onGenerateRoute: (settings) => GetPageRoute(page: () => ProfilePage()), + ), ]; RxInt currentIndex = 0.obs; @@ -48,7 +52,7 @@ class RootLogic extends GetxController { } }); - /* GetIt.instance.allReady().then((value) async { + /* GetIt.instance.allReady().then((value) async { await diLiveStock.get().addLocations(generateRandomPoints()); });*/ } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 4bba1e0..d0474bb 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -1,40 +1,41 @@ 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}); + + DateTime? _lastBackPressed; @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(); + onPopInvokedWithResult: (didPop, result) async { + final nestedKey = Get.nestedKey(controller.currentIndex.value); + final currentNavigator = nestedKey?.currentState; - /*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 (currentNavigator?.canPop() ?? false) { + currentNavigator?.pop(); + } else { + final now = DateTime.now(); + if (_lastBackPressed == null || + now.difference(_lastBackPressed!) > Duration(seconds: 2)) { + _lastBackPressed = now; + Get.snackbar( + 'خروج از برنامه', + 'برای خروج دوباره بازگشت را بزنید', + snackPosition: SnackPosition.TOP, + duration: Duration(seconds: 2), + backgroundColor: AppColor.warning, + ); + } else { + await SystemNavigator.pop(); } - - if (!didPop) { - return; - } - }*/ + } }, child: Scaffold( diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index 58e206f..3e6c6bb 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -6,6 +6,7 @@ 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'; From 6e8530ec7f0d2b9aecf08c7815bb8c7878cdf6d3 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 25 Aug 2025 10:03:55 +0330 Subject: [PATCH 19/39] chore : refactor root --- .../lib/presentation/page/root/logic.dart | 2 + .../lib/presentation/page/root/view.dart | 51 +++++++++---------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 5d0805c..dbc2e00 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -43,6 +43,8 @@ class RootLogic extends GetxController { late StreamSubscription> connectivitySubscription; RxList connectivityResults = [].obs; + DateTime? lastBackPressed; + @override void onInit() { super.onInit(); diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index d0474bb..ded02db 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -7,7 +7,29 @@ import 'logic.dart'; class RootPage extends GetView { RootPage({super.key}); - DateTime? _lastBackPressed; + // 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) { @@ -15,36 +37,14 @@ class RootPage extends GetView { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) async { - final nestedKey = Get.nestedKey(controller.currentIndex.value); - final currentNavigator = nestedKey?.currentState; - - if (currentNavigator?.canPop() ?? false) { - currentNavigator?.pop(); - } else { - final now = DateTime.now(); - if (_lastBackPressed == null || - now.difference(_lastBackPressed!) > Duration(seconds: 2)) { - _lastBackPressed = now; - Get.snackbar( - 'خروج از برنامه', - 'برای خروج دوباره بازگشت را بزنید', - snackPosition: SnackPosition.TOP, - duration: Duration(seconds: 2), - backgroundColor: AppColor.warning, - ); - } else { - await SystemNavigator.pop(); - } - } + await _handleBackPress(context); }, - child: Scaffold( body: IndexedStack( - children: [...controller.pages], + children: controller.pages, index: currentIndex.value, sizing: StackFit.expand, ), - bottomNavigationBar: RBottomNavigation( mainAxisAlignment: MainAxisAlignment.spaceEvenly, items: [ @@ -66,7 +66,6 @@ class RootPage extends GetView { controller.changePage(1); }, ), - RBottomNavigationItem( label: 'پروفایل', icon: Assets.vec.profileCircleSvg.path, From 8402acbeac8b25f4f6ddc2aaf961fb734ef63798 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 25 Aug 2025 15:44:27 +0330 Subject: [PATCH 20/39] feat : some changes --- packages/core/lib/injection/di.dart | 4 +- .../widget/marquee/r_marquee.dart | 55 ++++++++++++++++ .../core/lib/presentation/widget/widget.dart | 6 +- .../lib/injection/live_stock_di.dart | 2 +- .../page/map/widget/map_widget/logic.dart | 6 +- .../page/map/widget/map_widget/view.dart | 48 ++++++++------ .../lib/presentation/page/root/logic.dart | 65 ++++++------------- .../lib/presentation/page/root/view.dart | 4 +- .../lib/presentation/routes/app_pages.dart | 1 - .../lib/presentation/routes/app_routes.dart | 2 - 10 files changed, 113 insertions(+), 80 deletions(-) create mode 100644 packages/core/lib/presentation/widget/marquee/r_marquee.dart diff --git a/packages/core/lib/injection/di.dart b/packages/core/lib/injection/di.dart index e6505b4..1e31ba5 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -1,8 +1,6 @@ -import 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart'; -import 'package:get_it/get_it.dart'; import 'package:logger/logger.dart'; +import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/data/services/network_status.dart'; -import 'package:rasadyar_core/infrastructure/local/hive_local_storage.dart'; final diCore = GetIt.instance; 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/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 9a8b1a3..32b68cb 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,3 @@ export 'tabs/new_tab.dart'; export 'tabs/r_segment.dart'; export 'tabs/tab.dart'; export 'vec_widget.dart'; - -// other -export 'logo_widget.dart'; diff --git a/packages/livestock/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index 328896d..d7915b2 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -26,7 +26,7 @@ Future setupLiveStockDI() async { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } - await FMTCStore(mapStoreKey).manage.create(); + // First register AppInterceptor with lazy callbacks diff --git a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart index 2c1cbd5..3b02375 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/logic.dart @@ -22,7 +22,9 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Timer? _debounceTimer; RxBool isLoading = false.obs; - late FMTCTileProvider tileProvider; +/* FMTCTileProvider tileProvider = FMTCTileProvider( + stores: {mapStoreKey: BrowseStoreStrategy.readUpdateCreate}, + );*/ RxList markerLocations = RxList(); RootLogic rootLogic = Get.find(); @@ -57,8 +59,6 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { } }); - tileProvider = FMTCTileProvider(stores: {mapStoreKey: BrowseStoreStrategy.readUpdateCreate}); - repository.addLocations(generateRandomLocations(currentLocation.value, 10, 100)); } 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 index b89b725..0eafac7 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -15,6 +15,15 @@ class MapWidget extends GetView { child: Stack( fit: StackFit.expand, children: [ + + Positioned( + top: 10, + right: 0, + left: 0, + child: RMarquee(text: "This is scrolling text from right to left..."), + ), + + ObxValue((errorType) { if (errorType.isNotEmpty) { if (errorType.contains(ErrorLocationType.serviceDisabled)) { @@ -104,7 +113,6 @@ class MapWidget extends GetView { flags: InteractiveFlag.all & ~InteractiveFlag.rotate, ), initialZoom: 15, - onPositionChanged: (camera, hasGesture) { controller.currentZoom.value = camera.zoom; /* controller.debouncedUpdateVisibleMarkers( @@ -118,7 +126,7 @@ class MapWidget extends GetView { TileLayer( urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', userAgentPackageName: 'ir.mnpc.rasadyar', - tileProvider: controller.tileProvider, + // tileProvider: controller.tileProvider, ), ObxValue((markers) { @@ -181,24 +189,26 @@ class MapWidget extends GetView { ); } - 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), - ), - ), + 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(); + .toList(); Widget detailsBottomSheet() { return BaseBottomSheet( diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index dbc2e00..7d0443e 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; @@ -10,15 +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), + key: navigatorKeys[0], onGenerateRoute: (settings) => GetPageRoute(page: () => MapPage()), ), Navigator( - key: Get.nestedKey(1), - initialRoute: LiveStockRoutes.requests, + key: navigatorKeys[1], onGenerateRoute: (settings) { switch (settings.name) { case LiveStockRoutes.requests: @@ -32,7 +37,7 @@ class RootLogic extends GetxController { ), Navigator( - key: Get.nestedKey(2), + key: navigatorKeys[2], onGenerateRoute: (settings) => GetPageRoute(page: () => ProfilePage()), ), ]; @@ -40,60 +45,28 @@ class RootLogic extends GetxController { RxInt currentIndex = 0.obs; TokenStorageService tokenService = Get.find(); - late StreamSubscription> connectivitySubscription; - RxList connectivityResults = [].obs; - - DateTime? lastBackPressed; - @override void onInit() { super.onInit(); - connectivitySubscription = Connectivity().onConnectivityChanged.listen((result) { - if (result.isNotEmpty) { - connectivityResults.assignAll(result); - } - }); - - /* GetIt.instance.allReady().then((value) async { - await diLiveStock.get().addLocations(generateRandomPoints()); - });*/ } - List generateRandomPoints() { - final Random random = Random(); - final double centerLat = 35.824891; - final double centerLon = 50.948025; - final double radiusKm = 1.0; - final double kmToDegLat = 1 / 111.0; // 1 km ≈ 0.009° latitude - final double kmToDegLon = 1 / (111.0 * cos(centerLat * pi / 180)); // Adjust for longitude - - List points = []; - for (int i = 0; i < 100; i++) { - // Generate random angle (0 to 2π) and random radius (0 to 1 km, using sqrt for uniform distribution) - double theta = random.nextDouble() * 2 * pi; - double r = - sqrt(random.nextDouble()) * radiusKm; // Square root for uniform distribution in circle - // Convert polar coordinates to Cartesian, then to LatLng - double deltaLat = r * cos(theta) * kmToDegLat; - double deltaLon = r * sin(theta) * kmToDegLon; - double newLat = centerLat + deltaLat; - double newLon = centerLon + deltaLon; - points.add(LatLng(newLat, newLon)); - } - return points; - } @override void onReady() { - // TODO: implement onReady super.onReady(); } @override void onClose() { - connectivitySubscription.cancel(); 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 ded02db..50d0863 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -16,7 +16,7 @@ class RootPage extends GetView { return; } final now = DateTime.now(); - if (controller.lastBackPressed == null || + /*if (controller.lastBackPressed == null || now.difference(controller.lastBackPressed!) > const Duration(seconds: 2)) { controller.lastBackPressed = now; Get.snackbar( @@ -28,7 +28,7 @@ class RootPage extends GetView { ); } else { await SystemNavigator.pop(); - } + }*/ } @override diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 6ff7302..7aa11b5 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -39,7 +39,6 @@ sealed class LiveStockPages { Get.lazyPut(() => RequestsLogic()); Get.lazyPut(() => MapLogic()); Get.lazyPut(() => ProfileLogic()); - Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); Get.lazyPut(() => BaseLogic()); }), diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index 3e6c6bb..823279b 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -8,8 +8,6 @@ sealed class LiveStockRoutes { 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'; } From e65567ce69a1efb4abde6b979aedaefe6bf933db Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 26 Aug 2025 12:22:43 +0330 Subject: [PATCH 21/39] fix : chicken app login and new module logic --- .../service/app_navigation_observer.dart | 4 +- .../service/token_storage_service.dart | 0 lib/presentation/pages/modules/logic.dart | 21 +++--- lib/presentation/pages/splash/logic.dart | 2 +- lib/presentation/routes/app_pages.dart | 21 +++++- .../remote/chicken/chicken_remote_imp.dart | 1 - packages/chicken/lib/data/di/chicken_di.dart | 75 ++++++++++++++++--- .../chicken/chicken_repository_imp.dart | 8 +- .../lib/presentation/pages/auth/logic.dart | 9 ++- .../lib/presentation/pages/auth/view.dart | 45 +++++------ .../lib/presentation/pages/root/logic.dart | 8 +- .../data/services/token_storage_service.dart | 2 + .../lib/infrastructure/remote/dio_remote.dart | 1 + .../page/map/widget/map_widget/view.dart | 7 -- 14 files changed, 136 insertions(+), 68 deletions(-) delete mode 100644 lib/infrastructure/service/token_storage_service.dart diff --git a/lib/infrastructure/service/app_navigation_observer.dart b/lib/infrastructure/service/app_navigation_observer.dart index 9c49563..83851bd 100644 --- a/lib/infrastructure/service/app_navigation_observer.dart +++ b/lib/infrastructure/service/app_navigation_observer.dart @@ -17,7 +17,7 @@ class CustomNavigationObserver extends NavigatorObserver { @override void didPush(Route route, Route? previousRoute) async { 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 && @@ -28,7 +28,7 @@ class CustomNavigationObserver extends NavigatorObserver { } else if (!_isWorkDone && (routeName == LiveStockRoutes.init || routeName == LiveStockRoutes.auth)) { - } + }*/ super.didPush(route, previousRoute); // tLog('CustomNavigationObserver: didPush - $routeName'); } 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/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index a82f9b1..fb622c6 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -28,21 +28,20 @@ class ModulesLogic extends GetxController { tokenService.appModule.value = module; } + void onTapCard(Module module, int index) async { + isLoading.value = !isLoading.value; + selectedIndex.value = index; + await Future.delayed(Duration(milliseconds: 200)); // Simulate loading delay + navigateToModule(module); + } + Future navigateToModule(Module module) async { - var target = getTargetPage(module).entries.first; + var target = getAuthTargetPage(module).entries.first; if (target.value != null) { await target.value; } - - Get.offAllNamed(target.key); - } - - void onTapCard(Module module, int index) async { - isLoading.value = true; - selectedIndex.value = index; - saveModule(module); - await Future.delayed(Duration(milliseconds: 500)); // Simulate loading delay - navigateToModule(module); + isLoading.value = !isLoading.value; + Get.toNamed(target.key, arguments: module); } } diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart index 2250dbe..562829a 100644 --- a/lib/presentation/pages/splash/logic.dart +++ b/lib/presentation/pages/splash/logic.dart @@ -154,7 +154,7 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { if (isUpdateNeeded) return; tokenService.getModule(); final module = tokenService.appModule.value; - final target = getTargetPage(module); + final target = getTargetModule(module); if (target.values.first != null) { await target.values.first; } diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index dbb99f0..66ab559 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -6,6 +6,7 @@ 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'; @@ -40,14 +41,28 @@ sealed class AppPages { ]; } -Map?> getTargetPage(Module? value) { + +Map?> getTargetModule(Module? value) { switch (value) { case Module.inspection: - return {InspectionRoutes.init:null}; + return {InspectionRoutes.init:setupInspectionDI()}; case Module.liveStocks: return {LiveStockRoutes.init: setupLiveStockDI()}; case Module.chicken: - return {ChickenRoutes.init : null}; + return {ChickenRoutes.init : setupChickenDI()}; + default: + return {AppPaths.moduleList : null}; + } +} + +Map?> getAuthTargetPage(Module? value) { + switch (value) { + case Module.inspection: + return {InspectionRoutes.auth:setupInspectionDI()}; + case Module.liveStocks: + return {LiveStockRoutes.auth: setupLiveStockDI()}; + case Module.chicken: + return {ChickenRoutes.auth : setupChickenDI()}; default: return {AppPaths.moduleList : null}; } 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..402abce 100644 --- a/packages/chicken/lib/data/di/chicken_di.dart +++ b/packages/chicken/lib/data/di/chicken_di.dart @@ -1,19 +1,27 @@ 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; Future setupChickenDI() async { + tLog("setup 1"); diChicken.registerSingleton(DioErrorHandler()); var tokenService = Get.find(); diChicken.registerLazySingleton( () => AppInterceptor( - //فعلا سامانه مرغ برای رفرش توکن چیزی ندارد + // سامانه مرغ فعلاً رفرش توکن ندارد refreshTokenCallback: () async => null, saveTokenCallback: (String newToken) async { await tokenService.saveAccessToken(newToken); @@ -26,24 +34,43 @@ 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( + diChicken.registerLazySingleton( () => AuthRemoteDataSourceImp(diChicken.get()), ); - diChicken.registerLazySingleton( - () => AuthRepositoryImpl(diChicken.get()), + diChicken.registerLazySingleton( + () => AuthRepositoryImpl(diChicken.get()), + instanceName: 'oldRepo', + ); + + 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 +79,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 +90,38 @@ 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(instanceName: 'oldRepo')) { + await diChicken.unregister(instanceName: 'oldRepo'); + diChicken.registerLazySingleton( () => AuthRepositoryImpl(diChicken.get()), + instanceName: 'newRepo', + ); + } + + 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(), + ), ); } } 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..a73a304 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'; @@ -44,7 +45,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { RxInt secondsRemaining = 120.obs; Timer? _timer; - AuthRepositoryImpl authRepository = diChicken.get(); + AuthRepository authRepository = diChicken.get(instanceName: 'oldRepo'); final Module _module = Get.arguments; @@ -64,7 +65,6 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { @override void onReady() { super.onReady(); - } @override @@ -118,7 +118,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { Future submitLoginForm() async { if (!_isFormValid()) return; - AuthRepositoryImpl authTmp = diChicken.get(instanceName: 'newUrl'); + AuthRepository authTmp = diChicken.get(instanceName: 'newRepo'); isLoading.value = true; await safeCall( call: () => authTmp.login( @@ -131,6 +131,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { await tokenStorageService.saveModule(_module); await tokenStorageService.saveAccessToken(result?.accessToken ?? ''); await tokenStorageService.saveRefreshToken(result?.accessToken ?? ''); + Get.offAndToNamed(ChickenRoutes.init); }, onError: (error, stackTrace) { if (error is DioException) { diff --git a/packages/chicken/lib/presentation/pages/auth/view.dart b/packages/chicken/lib/presentation/pages/auth/view.dart index 1700994..2fb0544 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), + ), + ], + ), ), ), ), 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/core/lib/data/services/token_storage_service.dart b/packages/core/lib/data/services/token_storage_service.dart index 6d0f3c3..a5fb162 100644 --- a/packages/core/lib/data/services/token_storage_service.dart +++ b/packages/core/lib/data/services/token_storage_service.dart @@ -56,9 +56,11 @@ class TokenStorageService extends GetxService { } Future saveModule(Module input) async { + eLog("before saveModule = ${appModule.value} ==> $input"); await _localStorage.save(boxName: _tokenBoxName, key: _moduleKey, value: input); appModule.value = input; appModule.refresh(); + eLog("after saveModule = ${appModule.value} ==> $input"); } Module? getModule() { diff --git a/packages/core/lib/infrastructure/remote/dio_remote.dart b/packages/core/lib/infrastructure/remote/dio_remote.dart index 184595a..6e261c0 100644 --- a/packages/core/lib/infrastructure/remote/dio_remote.dart +++ b/packages/core/lib/infrastructure/remote/dio_remote.dart @@ -10,6 +10,7 @@ class DioRemote implements IHttpClient { @override Future init() async { + fLog(baseUrl); dio = Dio(BaseOptions(baseUrl: baseUrl ?? '')); if (interceptors != null) { interceptors!.dio = dio; 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 index 0eafac7..c260bd0 100644 --- a/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart +++ b/packages/livestock/lib/presentation/page/map/widget/map_widget/view.dart @@ -16,13 +16,6 @@ class MapWidget extends GetView { fit: StackFit.expand, children: [ - Positioned( - top: 10, - right: 0, - left: 0, - child: RMarquee(text: "This is scrolling text from right to left..."), - ), - ObxValue((errorType) { if (errorType.isNotEmpty) { From 5ffda97e54998e57dce1003a49dad8d285010d68 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 26 Aug 2025 12:41:21 +0330 Subject: [PATCH 22/39] chore : add smooth_page_indicator lib in core --- packages/core/lib/core.dart | 1 + packages/core/pubspec.lock | 8 ++++++++ packages/core/pubspec.yaml | 1 + 3 files changed, 10 insertions(+) diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index bbce482..4241d93 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -7,6 +7,7 @@ export 'package:device_info_plus/device_info_plus.dart'; export 'package:dio/dio.dart'; //other packages export 'package:flutter_localizations/flutter_localizations.dart'; +export 'package:smooth_page_indicator/smooth_page_indicator.dart'; //map export 'package:flutter_map/flutter_map.dart'; export 'package:flutter_map_animations/flutter_map_animations.dart'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index f680175..875b523 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -1378,6 +1378,14 @@ 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: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index fbaa949..2470cc3 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -26,6 +26,7 @@ dependencies: 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 From d3e5ab7d613a59035886e238e069cf41af738bfb Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 11:56:29 +0330 Subject: [PATCH 23/39] feat : module page --- assets/icons/rasad_ban.svg | 10 + assets/icons/rasad_bar.svg | 6 + assets/icons/rasad_bot.svg | 16 + assets/icons/rasad_dam.svg | 18 + assets/icons/rasad_nan.svg | 507 ++++++++++++++++++ assets/icons/rasad_toyor.svg | 7 + assets/vec/rasad_ban.svg.vec | Bin 0 -> 1153 bytes assets/vec/rasad_bar.svg.vec | Bin 0 -> 1341 bytes assets/vec/rasad_bot.svg.vec | Bin 0 -> 1854 bytes assets/vec/rasad_dam.svg.vec | Bin 0 -> 6020 bytes assets/vec/rasad_nan.svg.vec | Bin 0 -> 81188 bytes assets/vec/rasad_toyor.svg.vec | Bin 0 -> 1124 bytes .../model/response/slider/slider_model.dart | 15 + .../response/slider/slider_model.freezed.dart | 296 ++++++++++ .../model/response/slider/slider_model.g.dart | 15 + lib/presentation/pages/modules/logic.dart | 98 +++- lib/presentation/pages/modules/view.dart | 57 +- lib/presentation/routes/app_pages.dart | 21 +- .../data/model/local/module/module_model.dart | 10 +- .../local/module/module_model.freezed.dart | 55 +- packages/core/lib/injection/di.dart | 5 +- .../lib/presentation/common/app_fonts.dart | 9 + .../lib/presentation/common/assets.gen.dart | 48 ++ .../card/card_with_icon_with_border.dart | 63 ++- .../lib/presentation/widget/slider/logic.dart | 45 ++ .../presentation/widget/slider/slider.dart | 2 + .../lib/presentation/widget/slider/view.dart | 80 +++ .../core/lib/presentation/widget/widget.dart | 1 + packages/core/lib/utils/number_utils.dart | 13 + packages/core/lib/utils/utils.dart | 1 + pubspec.lock | 8 + 31 files changed, 1313 insertions(+), 93 deletions(-) create mode 100644 assets/icons/rasad_ban.svg create mode 100644 assets/icons/rasad_bar.svg create mode 100644 assets/icons/rasad_bot.svg create mode 100644 assets/icons/rasad_dam.svg create mode 100644 assets/icons/rasad_nan.svg create mode 100644 assets/icons/rasad_toyor.svg create mode 100644 assets/vec/rasad_ban.svg.vec create mode 100644 assets/vec/rasad_bar.svg.vec create mode 100644 assets/vec/rasad_bot.svg.vec create mode 100644 assets/vec/rasad_dam.svg.vec create mode 100644 assets/vec/rasad_nan.svg.vec create mode 100644 assets/vec/rasad_toyor.svg.vec create mode 100644 lib/data/model/response/slider/slider_model.dart create mode 100644 lib/data/model/response/slider/slider_model.freezed.dart create mode 100644 lib/data/model/response/slider/slider_model.g.dart create mode 100644 packages/core/lib/presentation/widget/slider/logic.dart create mode 100644 packages/core/lib/presentation/widget/slider/slider.dart create mode 100644 packages/core/lib/presentation/widget/slider/view.dart create mode 100644 packages/core/lib/utils/number_utils.dart 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 0000000000000000000000000000000000000000..53a463188933843caeb1b0d6a1252d7aed9ca1ff GIT binary patch literal 1153 zcma)+Ye*GA6vtVB(=yj?YGyYj?O{bw*7>KQ_BOp>7Fn4QJ?Q-s`jTl6p{OW{ z2>lSG34IWYiUL1`MutRbo87W9Gb&99Q@qJGXK%OYTeC2~nK|eD&)LH;8>gNS$`m2i zLWu2%bfzn&CWL85R@@b)rts=U&2dvxdG(?Do2hAXr7J@C3prF(;h}}|=Hr(Znx6>l zXgE#oa|GXzD7upqWARAC0P+4}bTwW0QAShNI;q%hSnNIimz_hAC^}|Pfjbg=rQSTL z=hf8}MFespMU@{O_UYUrb@d2pmj<-10 zZ!zMlhUq|a21e}qL|>DZ!2fUy1zbx1lXpiK!o_Ab~p@m*T2(Xg^q5gL0g{a2s~)eOv!{x1`RanSSodDf0Om1 z2X0ZGV;sV+)>Ge51m-j}QT}V`7c2c_+}N@v+Sj0?vY?(iUPi#{ugl^*{glmAWub~@ z=dx?A7}UPPNu0;aXHtjHnK^XTVoTRLs{QN(X6J^d#N5LAK;PIv;+5 zTAc-yy7dtCUVKk{{_aSRMYijTkMObjrfA&1|Bti%6DLF)g-rTN9kau*|9ls@96H)p z>?A%PE_GUDyRP_(5uDF+mqK}2dMFw01u1x*un0k`S6RH7y$b5jEF2A5kIGiyX6Jr9 zpy?R-b~9!q+Yz3>4B3do9b};I-c%IFr^2hF%M3v*EbjuhnCE1=cG&@@>%~iAuIW!DwvQLnQ`n#Ru-O4-)4E)Axl@VB{>;X52iVTKUVUc$+@gim zeT5e9R~=ng7gk72j$>wLMS<;cv6)sJGwWm&m=p6d!FDG5GdaHhR1{d(t3S=UIi_h> d1V0*fRsN%d{9}fX;8(+L^VobnHg3IX{sL0LpXdMp literal 0 HcmV?d00001 diff --git a/assets/vec/rasad_bar.svg.vec b/assets/vec/rasad_bar.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..fea5942751ed0c83595acb999b8cf78d6b5389fd GIT binary patch literal 1341 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 MK+4gp&_Txd4;|#KQ2+n{ literal 0 HcmV?d00001 diff --git a/assets/vec/rasad_dam.svg.vec b/assets/vec/rasad_dam.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..d298a1c106d86509af62c676a7e2b3b9ac8b0999 GIT binary patch literal 6020 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 literal 0 HcmV?d00001 diff --git a/assets/vec/rasad_nan.svg.vec b/assets/vec/rasad_nan.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..0452acfd951202d52dbe832812a96ecb276a155f GIT binary patch literal 81188 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 up, + List? down, + }) = _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..ff8f57a --- /dev/null +++ b/lib/data/model/response/slider/slider_model.freezed.dart @@ -0,0 +1,296 @@ +// 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; +/// 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)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(up),const DeepCollectionEquality().hash(down)); + +@override +String toString() { + return 'SliderModel(up: $up, down: $down)'; +} + + +} + +/// @nodoc +abstract mixin class $SliderModelCopyWith<$Res> { + factory $SliderModelCopyWith(SliderModel value, $Res Function(SliderModel) _then) = _$SliderModelCopyWithImpl; +@useResult +$Res call({ + List? up, List? down +}); + + + + +} +/// @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,}) { + 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?, + )); +} + +} + + +/// 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)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that.up,_that.down);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) $default,) {final _that = this; +switch (_that) { +case _SliderModel(): +return $default(_that.up,_that.down);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)? $default,) {final _that = this; +switch (_that) { +case _SliderModel() when $default != null: +return $default(_that.up,_that.down);case _: + return null; + +} +} + +} + +/// @nodoc +@JsonSerializable() + +class _SliderModel implements SliderModel { + const _SliderModel({final List? up, final List? down}): _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); +} + + +/// 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)); +} + +@JsonKey(includeFromJson: false, includeToJson: false) +@override +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_up),const DeepCollectionEquality().hash(_down)); + +@override +String toString() { + return 'SliderModel(up: $up, down: $down)'; +} + + +} + +/// @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 +}); + + + + +} +/// @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,}) { + 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?, + )); +} + + +} + +// 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..bd1d453 --- /dev/null +++ b/lib/data/model/response/slider/slider_model.g.dart @@ -0,0 +1,15 @@ +// 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(), +); + +Map _$SliderModelToJson(_SliderModel instance) => + {'up': instance.up, 'down': instance.down}; diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index fb622c6..362a751 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -1,38 +1,90 @@ +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"); 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(); + void onInit() { + super.onInit(); + getSliders(); } - @override - void onClose() { - super.onClose(); - } void saveModule(Module module) { tokenService.saveModule(module); tokenService.appModule.value = module; } - void onTapCard(Module module, int index) async { - isLoading.value = !isLoading.value; + void onTapCard(Module? module, int index) async { + if (module == null) { + Get.snackbar("بزودی", "این ماژول به زودی اضافه می‌شود", snackPosition: SnackPosition.BOTTOM); + } else { + _goToModule(module, index); + } + } + + void _goToModule(Module module, int index) async { selectedIndex.value = index; - await Future.delayed(Duration(milliseconds: 200)); // Simulate loading delay - navigateToModule(module); + await Future.delayed(Duration(milliseconds: 300)); + selectedIndex.value = null; + saveModule(module); + await navigateToModule(module); } Future navigateToModule(Module module) async { @@ -44,4 +96,24 @@ class ModulesLogic extends GetxController { isLoading.value = !isLoading.value; Get.toNamed(target.key, arguments: module); } + + 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 ?? []); + } + } } diff --git a/lib/presentation/pages/modules/view.dart b/lib/presentation/pages/modules/view.dart index 6ff320a..bba39ed 100644 --- a/lib/presentation/pages/modules/view.dart +++ b/lib/presentation/pages/modules/view.dart @@ -11,7 +11,13 @@ 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, ), @@ -19,23 +25,40 @@ class ModulesPage extends GetView { fit: StackFit.expand, alignment: Alignment.center, children: [ - GridView.builder( - padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), - itemBuilder: (context, index) { - final module = controller.moduleList[index]; - return CardIcon( - title: module.title, - icon: module.icon, - onTap: () => controller.onTapCard(module.module, index), - ); - }, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - mainAxisSpacing: 10, - crossAxisSpacing: 10, + Positioned.fill( + child: Column( + children: [ + SizedBox(height: 24.h), + SliderWidget(widgetTag: "up"), + + 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, + ), + ), + + SliderWidget(height: 160, widgetTag: "down"), + SizedBox(height: 30.h), + ], ), - physics: BouncingScrollPhysics(), - itemCount: controller.moduleList.length, ), ObxValue((loading) { if (!controller.isLoading.value) return SizedBox.shrink(); diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index 66ab559..4a11fb2 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -25,7 +25,12 @@ 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( @@ -35,35 +40,33 @@ sealed class AppPages { ), ...InspectionPages.pages, - ...LiveStockPages.pages, ...ChickenPages.pages, ]; } - Map?> getTargetModule(Module? value) { switch (value) { case Module.inspection: - return {InspectionRoutes.init:setupInspectionDI()}; + return {InspectionRoutes.init: setupInspectionDI()}; case Module.liveStocks: return {LiveStockRoutes.init: setupLiveStockDI()}; case Module.chicken: - return {ChickenRoutes.init : setupChickenDI()}; + return {ChickenRoutes.init: setupChickenDI()}; default: - return {AppPaths.moduleList : null}; + return {AppPaths.moduleList: null}; } } Map?> getAuthTargetPage(Module? value) { switch (value) { case Module.inspection: - return {InspectionRoutes.auth:setupInspectionDI()}; + return {InspectionRoutes.auth: setupInspectionDI()}; case Module.liveStocks: return {LiveStockRoutes.auth: setupLiveStockDI()}; case Module.chicken: - return {ChickenRoutes.auth : setupChickenDI()}; + return {ChickenRoutes.auth: setupChickenDI()}; default: - return {AppPaths.moduleList : null}; + return {AppPaths.moduleList: null}; } } 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/injection/di.dart b/packages/core/lib/injection/di.dart index 1e31ba5..c7bc829 100644 --- a/packages/core/lib/injection/di.dart +++ b/packages/core/lib/injection/di.dart @@ -11,9 +11,8 @@ Future setupAllCoreProvider() async { diCore.registerSingleton(NetworkStatus()..startListening()); //max 500MB Map Cashing - await diCore.registerSingleton( - FMTCObjectBoxBackend().initialise(maxDatabaseSize: 500 * 1024 * 1024), - ); + await FMTCObjectBoxBackend().initialise(); + 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/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/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..ad438be --- /dev/null +++ b/packages/core/lib/presentation/widget/slider/view.dart @@ -0,0 +1,80 @@ +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), + image: DecorationImage(fit: BoxFit.fill, image: NetworkImage(image ?? '')), + ), + ); + }, + ), + ), + 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 32b68cb..2564871 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -32,3 +32,4 @@ export 'tabs/new_tab.dart'; export 'tabs/r_segment.dart'; export 'tabs/tab.dart'; export 'vec_widget.dart'; +export 'slider/slider.dart'; \ No newline at end of file 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 40b6ed5..cbb70e5 100644 --- a/packages/core/lib/utils/utils.dart +++ b/packages/core/lib/utils/utils.dart @@ -11,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/pubspec.lock b/pubspec.lock index 74f7cb2..c9af987 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1390,6 +1390,14 @@ 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: From b1eb767a8b49840dcfdbb644092e280a0c29214b Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 11:59:24 +0330 Subject: [PATCH 24/39] chore : change .gitignore app --- .gitignore | 1 + packages/chicken/.gitignore | 11 ++++------- packages/core/.gitignore | 2 +- packages/inspection/.gitignore | 4 ++++ packages/livestock/.gitignore | 11 ++++------- 5 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 packages/inspection/.gitignore 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/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/core/.gitignore b/packages/core/.gitignore index 02b7cc0..38a41ed 100644 --- a/packages/core/.gitignore +++ b/packages/core/.gitignore @@ -11,7 +11,7 @@ build/ *.iml *.ipr *.iws - +*.lock # VS Code .vscode/ 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/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 From 047c4e49e7856fa24fad998948051f4f7f84367e Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 16:31:01 +0330 Subject: [PATCH 25/39] fix : just single snack bar --- lib/presentation/pages/modules/logic.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 362a751..5064460 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -65,7 +65,6 @@ class ModulesLogic extends GetxController { getSliders(); } - void saveModule(Module module) { tokenService.saveModule(module); tokenService.appModule.value = module; @@ -73,7 +72,13 @@ class ModulesLogic extends GetxController { void onTapCard(Module? module, int index) async { if (module == null) { - Get.snackbar("بزودی", "این ماژول به زودی اضافه می‌شود", snackPosition: SnackPosition.BOTTOM); + if(Get.isSnackbarOpen) return; + Get.snackbar( + "در حال توسعه", + "این ماژول به زودی اضافه می‌شود", + snackPosition: SnackPosition.BOTTOM, + backgroundColor: AppColor.yellowDark, + ); } else { _goToModule(module, index); } From 4ded6a25d5ce1fb8094517c308ef801ebbe70916 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 16:31:49 +0330 Subject: [PATCH 26/39] chore : remove unused switch conditions --- lib/presentation/routes/auth_route_resolver_impl.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 From d7aa51c03365c80772ec09e6532f05ee1f977fde Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 16:53:21 +0330 Subject: [PATCH 27/39] feat : news widget --- lib/presentation/pages/modules/view.dart | 70 +++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/lib/presentation/pages/modules/view.dart b/lib/presentation/pages/modules/view.dart index bba39ed..34fa394 100644 --- a/lib/presentation/pages/modules/view.dart +++ b/lib/presentation/pages/modules/view.dart @@ -54,9 +54,77 @@ class ModulesPage extends GetView { itemCount: controller.moduleList.length, ), ), + SizedBox(height: 24.h), + 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, + ), + ), + Text( + 'اخبار مربوط به جوجه ریزی استان از آخرین روند مطلع شوید اخبار مربوط به جوجه ریزی استان از ', + maxLines: 2, + style: AppFonts.yekan12.copyWith( + color: Color(0xFF5B5B5B), + height: 1.5, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + 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: 24.h), SliderWidget(height: 160, widgetTag: "down"), - SizedBox(height: 30.h), + SizedBox(height: 24.h), ], ), ), From f946129915e2ae80155b945d8c9f54fe0196a1c1 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 27 Aug 2025 16:56:01 +0330 Subject: [PATCH 28/39] feat : news widget --- lib/presentation/pages/modules/view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/presentation/pages/modules/view.dart b/lib/presentation/pages/modules/view.dart index 34fa394..8dda9d2 100644 --- a/lib/presentation/pages/modules/view.dart +++ b/lib/presentation/pages/modules/view.dart @@ -54,7 +54,7 @@ class ModulesPage extends GetView { itemCount: controller.moduleList.length, ), ), - SizedBox(height: 24.h), + Container( height: 107.h, margin: EdgeInsets.symmetric(horizontal: 16.w), @@ -122,9 +122,9 @@ class ModulesPage extends GetView { ), ), - SizedBox(height: 24.h), + SizedBox(height: 12.h), SliderWidget(height: 160, widgetTag: "down"), - SizedBox(height: 24.h), + SizedBox(height: 20.h), ], ), ), From 04d44b2615dbd06a0f7cb64b0403d7d5a6e2920a Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 30 Aug 2025 09:19:53 +0330 Subject: [PATCH 29/39] fix : loading slider widget --- packages/core/lib/core.dart | 6 +- .../lib/presentation/widget/slider/view.dart | 14 +- packages/core/pubspec.lock | 164 ++++++++++++++---- packages/core/pubspec.yaml | 3 +- pubspec.lock | 92 +++++++++- 5 files changed, 231 insertions(+), 48 deletions(-) diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 4241d93..25499a4 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -2,18 +2,17 @@ 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: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'; -export 'package:smooth_page_indicator/smooth_page_indicator.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'; - +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'; @@ -42,6 +41,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:smooth_page_indicator/smooth_page_indicator.dart'; //models export 'data/model/model.dart'; diff --git a/packages/core/lib/presentation/widget/slider/view.dart b/packages/core/lib/presentation/widget/slider/view.dart index ad438be..a7c22de 100644 --- a/packages/core/lib/presentation/widget/slider/view.dart +++ b/packages/core/lib/presentation/widget/slider/view.dart @@ -29,10 +29,16 @@ class SliderWidget extends GetView { String? image = state?[index]; return Container( height: height.h, - margin: EdgeInsets.symmetric(horizontal: 6.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.r), - image: DecorationImage(fit: BoxFit.fill, image: NetworkImage(image ?? '')), + 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)), ), ); }, diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index 875b523..b220691 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -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: @@ -357,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: @@ -398,6 +422,14 @@ packages: 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: @@ -471,10 +503,10 @@ packages: 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: @@ -543,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: @@ -721,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: @@ -737,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: @@ -801,10 +833,10 @@ packages: dependency: transitive description: name: image_picker_android - sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c + sha256: "28f3987ca0ec702d346eae1d90eda59603a2101b52f1e234ded62cff1d5cfa6e" url: "https://pub.dev" source: hosted - version: "0.8.13" + version: "0.8.13+1" image_picker_for_web: dependency: transitive description: @@ -857,10 +889,10 @@ packages: 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: @@ -905,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: @@ -1077,6 +1109,14 @@ packages: 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: @@ -1129,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: @@ -1225,10 +1265,10 @@ packages: 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: @@ -1297,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: @@ -1390,18 +1430,18 @@ packages: 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: @@ -1434,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: @@ -1466,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: @@ -1558,10 +1646,10 @@ 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: @@ -1574,18 +1662,18 @@ packages: 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: @@ -1654,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: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 2470cc3..620200e 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: #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 @@ -43,6 +43,7 @@ dependencies: #SVG flutter_svg: ^2.2.0 + cached_network_image: ^3.4.1 #Shimmer diff --git a/pubspec.lock b/pubspec.lock index c9af987..ad5afc0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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: @@ -398,6 +422,14 @@ packages: 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: @@ -551,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: @@ -1077,6 +1109,14 @@ packages: 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: @@ -1430,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: @@ -1462,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: From 9fab48aee102703cee480561f336ec7b5f35848e Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 31 Aug 2025 10:16:18 +0330 Subject: [PATCH 30/39] feat : remember me for chicken module --- packages/chicken/lib/data/di/chicken_di.dart | 7 +- .../lib/presentation/pages/auth/logic.dart | 26 ++- .../lib/presentation/pages/auth/view.dart | 23 ++- .../lib/presentation/pages/profile/view.dart | 173 +++++++++--------- packages/core/lib/core.dart | 3 +- .../local/user_local/user_local_model.dart | 14 -- .../local/user_local/user_local_model.g.dart | 10 +- .../data/services/token_storage_service.dart | 17 +- .../presentation/utils/list_extensions.dart | 2 +- packages/core/pubspec.lock | 2 +- packages/core/pubspec.yaml | 1 + 11 files changed, 155 insertions(+), 123 deletions(-) diff --git a/packages/chicken/lib/data/di/chicken_di.dart b/packages/chicken/lib/data/di/chicken_di.dart index 402abce..5ceb8b4 100644 --- a/packages/chicken/lib/data/di/chicken_di.dart +++ b/packages/chicken/lib/data/di/chicken_di.dart @@ -15,7 +15,6 @@ import 'package:rasadyar_core/core.dart'; GetIt diChicken = GetIt.instance; Future setupChickenDI() async { - tLog("setup 1"); diChicken.registerSingleton(DioErrorHandler()); var tokenService = Get.find(); @@ -52,7 +51,6 @@ Future setupChickenDI() async { diChicken.registerLazySingleton( () => AuthRepositoryImpl(diChicken.get()), - instanceName: 'oldRepo', ); diChicken.registerLazySingleton( @@ -95,11 +93,10 @@ Future newSetupAuthDI(String newUrl) async { ); } - if (diChicken.isRegistered(instanceName: 'oldRepo')) { - await diChicken.unregister(instanceName: 'oldRepo'); + if (diChicken.isRegistered()) { + await diChicken.unregister(); diChicken.registerLazySingleton( () => AuthRepositoryImpl(diChicken.get()), - instanceName: 'newRepo', ); } diff --git a/packages/chicken/lib/presentation/pages/auth/logic.dart b/packages/chicken/lib/presentation/pages/auth/logic.dart index a73a304..b1cfbe2 100644 --- a/packages/chicken/lib/presentation/pages/auth/logic.dart +++ b/packages/chicken/lib/presentation/pages/auth/logic.dart @@ -23,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; @@ -45,7 +46,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { RxInt secondsRemaining = 120.obs; Timer? _timer; - AuthRepository authRepository = diChicken.get(instanceName: 'oldRepo'); + AuthRepository authRepository = diChicken.get(); final Module _module = Get.arguments; @@ -60,6 +61,8 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { }); textAnimation = CurvedAnimation(parent: _textAnimationController, curve: Curves.easeInOut); + + initUserPassData(); } @override @@ -118,7 +121,7 @@ class AuthLogic extends GetxController with GetTickerProviderStateMixin { Future submitLoginForm() async { if (!_isFormValid()) return; - AuthRepository authTmp = diChicken.get(instanceName: 'newRepo'); + AuthRepository authTmp = diChicken.get(); isLoading.value = true; await safeCall( call: () => authTmp.login( @@ -131,6 +134,16 @@ 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) { @@ -163,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 2fb0544..2f2e85c 100644 --- a/packages/chicken/lib/presentation/pages/auth/view.dart +++ b/packages/chicken/lib/presentation/pages/auth/view.dart @@ -197,7 +197,28 @@ class AuthPage extends GetView { ), SizedBox(height: 26), CaptchaWidget(), - SizedBox(height: 23), + + 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/core/lib/core.dart b/packages/core/lib/core.dart index 25499a4..55eeb79 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -2,7 +2,8 @@ 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: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'; 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/token_storage_service.dart b/packages/core/lib/data/services/token_storage_service.dart index a5fb162..0755272 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 { - 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); @@ -88,4 +89,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/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/pubspec.lock b/packages/core/pubspec.lock index b220691..c191946 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -202,7 +202,7 @@ packages: source: hosted version: "4.10.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 620200e..88331f2 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -62,6 +62,7 @@ dependencies: permission_handler: ^12.0.1 persian_datetime_picker: ^3.1.1 encrypt: ^5.0.3 + collection: ^1.19.1 #L10N tools intl: ^0.20.2 From 6a3bce3397118399e1b3025aad7b0f3e28c56d14 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 31 Aug 2025 11:09:07 +0330 Subject: [PATCH 31/39] feat : remember me for inspection module --- .../lib/presentation/pages/auth/view.dart | 45 ++++--- .../lib/presentation/pages/auth/logic.dart | 12 +- .../lib/presentation/pages/auth/view.dart | 121 ++++++++++-------- 3 files changed, 107 insertions(+), 71 deletions(-) diff --git a/packages/chicken/lib/presentation/pages/auth/view.dart b/packages/chicken/lib/presentation/pages/auth/view.dart index 2f2e85c..ef0d429 100644 --- a/packages/chicken/lib/presentation/pages/auth/view.dart +++ b/packages/chicken/lib/presentation/pages/auth/view.dart @@ -198,26 +198,31 @@ class AuthPage extends GetView { SizedBox(height: 26), CaptchaWidget(), - 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), - ), - ], + 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(() { 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..0b1afda 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 { @@ -42,10 +43,7 @@ class AuthPage extends GetView { ), Obx(() { - final screenHeight = MediaQuery - .of(context) - .size - .height; + final screenHeight = MediaQuery.of(context).size.height; final targetTop = (screenHeight - 676) / 2; return AnimatedPositioned( @@ -129,13 +127,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 +153,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 +227,8 @@ class AuthPage extends GetView { onPressed: controller.isDisabled.value ? null : () async { - await controller.submitLoginForm(); - }, + await controller.submitLoginForm(); + }, width: Get.width, height: 48, ); @@ -308,7 +329,7 @@ class AuthPage extends GetView { ); } -/* + /* Widget sendCodeForm() { return ObxValue((data) { return Form( From e4ceb1c0ace892a722f683dd35ea588a027c08dd Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 31 Aug 2025 11:10:21 +0330 Subject: [PATCH 32/39] feat : remember me for LiveStock module --- .../lib/presentation/page/auth/logic.dart | 11 ++++++++ .../lib/presentation/page/auth/view.dart | 28 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/livestock/lib/presentation/page/auth/logic.dart b/packages/livestock/lib/presentation/page/auth/logic.dart index 755fe07..a7a1eff 100644 --- a/packages/livestock/lib/presentation/page/auth/logic.dart +++ b/packages/livestock/lib/presentation/page/auth/logic.dart @@ -22,6 +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; @@ -127,6 +128,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(LiveStockRoutes.init); }, onError: (error, stackTrace) { diff --git a/packages/livestock/lib/presentation/page/auth/view.dart b/packages/livestock/lib/presentation/page/auth/view.dart index 983d6bc..ea6f953 100644 --- a/packages/livestock/lib/presentation/page/auth/view.dart +++ b/packages/livestock/lib/presentation/page/auth/view.dart @@ -194,7 +194,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( From fa7307b4e9ffca40e5655c7375d895d4b04a284e Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:47:23 +0330 Subject: [PATCH 33/39] fix : StackFit in auth page inspection module --- packages/inspection/lib/presentation/pages/auth/view.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/inspection/lib/presentation/pages/auth/view.dart b/packages/inspection/lib/presentation/pages/auth/view.dart index 0b1afda..9cf400b 100644 --- a/packages/inspection/lib/presentation/pages/auth/view.dart +++ b/packages/inspection/lib/presentation/pages/auth/view.dart @@ -13,6 +13,7 @@ class AuthPage extends GetView { return Scaffold( body: Stack( alignment: Alignment.center, + fit: StackFit.expand, children: [ Assets.vec.bgAuthSvg.svg(fit: BoxFit.fill), From 315d8e112d5d0ce93f5b4761890d5287354ae985 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:47:46 +0330 Subject: [PATCH 34/39] chore : use large heap for android --- android/app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d9e2fba..3a49a4e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ From d8eedd106ac23da6bf0fed9736b80d9b8cbbd67c Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:48:16 +0330 Subject: [PATCH 35/39] chore : upgrade gradle-wrapper.properties --- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index efdcc4a..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.11.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip From 5af5d63a1e066bbfab1594ef9266621b1996cf34 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:50:05 +0330 Subject: [PATCH 36/39] fix : some di remove in module page --- lib/presentation/pages/modules/logic.dart | 18 +- lib/presentation/routes/app_pages.dart | 15 +- packages/chicken/lib/data/di/chicken_di.dart | 31 +++- .../lib/infrastructure/remote/dio_remote.dart | 1 - packages/core/pubspec.yaml | 2 +- .../lib/injection/inspection_di.dart | 47 ++++- packages/inspection/pubspec.lock | 160 ++++++++++++++++-- packages/inspection/pubspec.yaml | 4 +- .../lib/injection/live_stock_di.dart | 33 +++- packages/livestock/pubspec.yaml | 2 +- pubspec.lock | 8 +- pubspec.yaml | 2 +- 12 files changed, 275 insertions(+), 48 deletions(-) diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 5064460..906f7fc 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -72,7 +72,7 @@ class ModulesLogic extends GetxController { void onTapCard(Module? module, int index) async { if (module == null) { - if(Get.isSnackbarOpen) return; + if (Get.isSnackbarOpen) return; Get.snackbar( "در حال توسعه", "این ماژول به زودی اضافه می‌شود", @@ -94,12 +94,18 @@ class ModulesLogic extends GetxController { Future navigateToModule(Module module) async { var target = getAuthTargetPage(module).entries.first; - - if (target.value != null) { - await target.value; + fLog('gooo'); + if (target.value?[0] != null) { + isLoading.value = !isLoading.value; + await target.value?[0]; + isLoading.value = !isLoading.value; + } + + await Get.toNamed(target.key, arguments: module); + fLog('return'); + if (target.value?[1] != null) { + await target.value?[1]; } - isLoading.value = !isLoading.value; - Get.toNamed(target.key, arguments: module); } Future getSliders() async { diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index 4a11fb2..c0a0e8a 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -26,7 +26,6 @@ sealed class AppPages { name: AppPaths.moduleList, page: () => ModulesPage(), binding: BindingsBuilder(() { - Get.lazyPut(() => SliderLogic(), tag: "up"); Get.lazyPut(() => SliderLogic(), tag: "down"); Get.put(ModulesLogic()); @@ -58,14 +57,20 @@ Map?> getTargetModule(Module? value) { } } -Map?> getAuthTargetPage(Module? value) { +Map?>?> getAuthTargetPage(Module? value) { switch (value) { case Module.inspection: - return {InspectionRoutes.auth: setupInspectionDI()}; + return { + InspectionRoutes.auth: [setupInspectionDI(), removeInspectionDI()], + }; case Module.liveStocks: - return {LiveStockRoutes.auth: setupLiveStockDI()}; + return { + LiveStockRoutes.auth: [setupLiveStockDI(), removeLiveStockDI()], + }; case Module.chicken: - return {ChickenRoutes.auth: setupChickenDI()}; + return { + ChickenRoutes.auth: [setupChickenDI(), removeChickenDI()], + }; default: return {AppPaths.moduleList: null}; } diff --git a/packages/chicken/lib/data/di/chicken_di.dart b/packages/chicken/lib/data/di/chicken_di.dart index 5ceb8b4..8f23e29 100644 --- a/packages/chicken/lib/data/di/chicken_di.dart +++ b/packages/chicken/lib/data/di/chicken_di.dart @@ -46,7 +46,7 @@ Future setupChickenDI() async { await dioRemote.init(); diChicken.registerLazySingleton( - () => AuthRemoteDataSourceImp(diChicken.get()), + () => AuthRemoteDataSourceImp(dioRemote), ); diChicken.registerLazySingleton( @@ -122,3 +122,32 @@ Future newSetupAuthDI(String newUrl) async { ); } } + + + +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/core/lib/infrastructure/remote/dio_remote.dart b/packages/core/lib/infrastructure/remote/dio_remote.dart index 6e261c0..184595a 100644 --- a/packages/core/lib/infrastructure/remote/dio_remote.dart +++ b/packages/core/lib/infrastructure/remote/dio_remote.dart @@ -10,7 +10,6 @@ class DioRemote implements IHttpClient { @override Future init() async { - fLog(baseUrl); dio = Dio(BaseOptions(baseUrl: baseUrl ?? '')); if (interceptors != null) { interceptors!.dio = dio; diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 88331f2..8cac455 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -97,7 +97,7 @@ dev_dependencies: 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 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/pubspec.lock b/packages/inspection/pubspec.lock index c3a0fb6..fcb6541 100644 --- a/packages/inspection/pubspec.lock +++ b/packages/inspection/pubspec.lock @@ -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: @@ -385,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: @@ -451,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: @@ -527,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: @@ -889,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: @@ -1045,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: @@ -1353,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: @@ -1401,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: @@ -1433,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: diff --git a/packages/inspection/pubspec.yaml b/packages/inspection/pubspec.yaml index 52fa6f3..1021d3b 100644 --- a/packages/inspection/pubspec.yaml +++ b/packages/inspection/pubspec.yaml @@ -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/lib/injection/live_stock_di.dart b/packages/livestock/lib/injection/live_stock_di.dart index d7915b2..8530104 100644 --- a/packages/livestock/lib/injection/live_stock_di.dart +++ b/packages/livestock/lib/injection/live_stock_di.dart @@ -26,9 +26,6 @@ Future setupLiveStockDI() async { await tokenService.saveBaseUrl('https://api.dam.rasadyar.net/'); } - - - // First register AppInterceptor with lazy callbacks diLiveStock.registerLazySingleton( () => AppInterceptor( @@ -96,3 +93,33 @@ Future setupLiveStockDI() async { 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/pubspec.yaml b/packages/livestock/pubspec.yaml index ffa9508..0bb2b2f 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -27,7 +27,7 @@ dev_dependencies: 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 ad5afc0..3f3cccd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -945,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: @@ -1442,10 +1442,10 @@ packages: 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: diff --git a/pubspec.yaml b/pubspec.yaml index 8c503e9..badb658 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,7 +39,7 @@ dev_dependencies: 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 From c2f5e36fd78de92026c3d8a3a87b16f0c4d48069 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:58:17 +0330 Subject: [PATCH 37/39] feat : latest News in module page --- .../model/response/slider/slider_model.dart | 8 +--- .../response/slider/slider_model.freezed.dart | 43 ++++++++++--------- .../model/response/slider/slider_model.g.dart | 7 ++- lib/presentation/pages/modules/logic.dart | 2 + lib/presentation/pages/modules/view.dart | 19 ++++---- 5 files changed, 44 insertions(+), 35 deletions(-) diff --git a/lib/data/model/response/slider/slider_model.dart b/lib/data/model/response/slider/slider_model.dart index ee7832a..da64c8c 100644 --- a/lib/data/model/response/slider/slider_model.dart +++ b/lib/data/model/response/slider/slider_model.dart @@ -5,11 +5,7 @@ part 'slider_model.g.dart'; @freezed abstract class SliderModel with _$SliderModel { - const factory SliderModel({ - List? up, - List? down, - }) = _SliderModel; + const factory SliderModel({List? up, List? down, String? middle}) = _SliderModel; - factory SliderModel.fromJson(Map json) => - _$SliderModelFromJson(json); + 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 index ff8f57a..225749e 100644 --- a/lib/data/model/response/slider/slider_model.freezed.dart +++ b/lib/data/model/response/slider/slider_model.freezed.dart @@ -15,7 +15,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$SliderModel { - List? get up; List? get down; + 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) @@ -28,16 +28,16 @@ $SliderModelCopyWith get copyWith => _$SliderModelCopyWithImpl Object.hash(runtimeType,const DeepCollectionEquality().hash(up),const DeepCollectionEquality().hash(down)); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(up),const DeepCollectionEquality().hash(down),middle); @override String toString() { - return 'SliderModel(up: $up, down: $down)'; + return 'SliderModel(up: $up, down: $down, middle: $middle)'; } @@ -48,7 +48,7 @@ abstract mixin class $SliderModelCopyWith<$Res> { factory $SliderModelCopyWith(SliderModel value, $Res Function(SliderModel) _then) = _$SliderModelCopyWithImpl; @useResult $Res call({ - List? up, List? down + List? up, List? down, String? middle }); @@ -65,11 +65,12 @@ class _$SliderModelCopyWithImpl<$Res> /// 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,}) { +@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?, +as List?,middle: freezed == middle ? _self.middle : middle // ignore: cast_nullable_to_non_nullable +as String?, )); } @@ -154,10 +155,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( List? up, List? down)? $default,{required TResult orElse(),}) {final _that = this; +@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);case _: +return $default(_that.up,_that.down,_that.middle);case _: return orElse(); } @@ -175,10 +176,10 @@ return $default(_that.up,_that.down);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( List? up, List? down) $default,) {final _that = this; +@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);case _: +return $default(_that.up,_that.down,_that.middle);case _: throw StateError('Unexpected subclass'); } @@ -195,10 +196,10 @@ return $default(_that.up,_that.down);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( List? up, List? down)? $default,) {final _that = this; +@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);case _: +return $default(_that.up,_that.down,_that.middle);case _: return null; } @@ -210,7 +211,7 @@ return $default(_that.up,_that.down);case _: @JsonSerializable() class _SliderModel implements SliderModel { - const _SliderModel({final List? up, final List? down}): _up = up,_down = down; + const _SliderModel({final List? up, final List? down, this.middle}): _up = up,_down = down; factory _SliderModel.fromJson(Map json) => _$SliderModelFromJson(json); final List? _up; @@ -231,6 +232,7 @@ class _SliderModel implements SliderModel { return EqualUnmodifiableListView(value); } +@override final String? middle; /// Create a copy of SliderModel /// with the given fields replaced by the non-null parameter values. @@ -245,16 +247,16 @@ 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)); + 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)); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_up),const DeepCollectionEquality().hash(_down),middle); @override String toString() { - return 'SliderModel(up: $up, down: $down)'; + return 'SliderModel(up: $up, down: $down, middle: $middle)'; } @@ -265,7 +267,7 @@ abstract mixin class _$SliderModelCopyWith<$Res> implements $SliderModelCopyWith factory _$SliderModelCopyWith(_SliderModel value, $Res Function(_SliderModel) _then) = __$SliderModelCopyWithImpl; @override @useResult $Res call({ - List? up, List? down + List? up, List? down, String? middle }); @@ -282,11 +284,12 @@ class __$SliderModelCopyWithImpl<$Res> /// 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,}) { +@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?, +as List?,middle: freezed == middle ? _self.middle : middle // ignore: cast_nullable_to_non_nullable +as String?, )); } diff --git a/lib/data/model/response/slider/slider_model.g.dart b/lib/data/model/response/slider/slider_model.g.dart index bd1d453..3fb67f0 100644 --- a/lib/data/model/response/slider/slider_model.g.dart +++ b/lib/data/model/response/slider/slider_model.g.dart @@ -9,7 +9,12 @@ part of 'slider_model.dart'; _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}; + { + 'up': instance.up, + 'down': instance.down, + 'middle': instance.middle, + }; diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 906f7fc..5efc079 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -7,6 +7,7 @@ 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 = [ @@ -125,6 +126,7 @@ class ModulesLogic extends GetxController { 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 8dda9d2..830bd57 100644 --- a/lib/presentation/pages/modules/view.dart +++ b/lib/presentation/pages/modules/view.dart @@ -84,15 +84,18 @@ class ModulesPage extends GetView { height: 1.90, ), ), - Text( - 'اخبار مربوط به جوجه ریزی استان از آخرین روند مطلع شوید اخبار مربوط به جوجه ریزی استان از ', - maxLines: 2, - - style: AppFonts.yekan12.copyWith( - color: Color(0xFF5B5B5B), - height: 1.5, - overflow: TextOverflow.ellipsis, + ObxValue( + (data) => Text( + data.value ?? + 'اخبار مربوط به جوجه ریزی استان از آخرین روند مطلع شوید...', + maxLines: 2, + style: AppFonts.yekan12.copyWith( + color: Color(0xFF5B5B5B), + height: 1.5, + overflow: TextOverflow.ellipsis, + ), ), + controller.latestNews, ), ], ), From acff86d7ed185b63040c9291ab8792aa30fd889d Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 10:59:32 +0330 Subject: [PATCH 38/39] fix : auth page in inspection --- .../lib/presentation/pages/auth/view.dart | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/inspection/lib/presentation/pages/auth/view.dart b/packages/inspection/lib/presentation/pages/auth/view.dart index 9cf400b..b0c6431 100644 --- a/packages/inspection/lib/presentation/pages/auth/view.dart +++ b/packages/inspection/lib/presentation/pages/auth/view.dart @@ -18,27 +18,29 @@ class AuthPage extends GetView { 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), + ), + ], + ), ), ), ), From d44b9f1f47c103a1466513298eeb2275db75f8ca Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 1 Sep 2025 11:02:03 +0330 Subject: [PATCH 39/39] chore : remove logger --- lib/presentation/pages/modules/logic.dart | 4 ++-- packages/core/lib/data/services/token_storage_service.dart | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/presentation/pages/modules/logic.dart b/lib/presentation/pages/modules/logic.dart index 5efc079..85685ad 100644 --- a/lib/presentation/pages/modules/logic.dart +++ b/lib/presentation/pages/modules/logic.dart @@ -95,7 +95,7 @@ class ModulesLogic extends GetxController { Future navigateToModule(Module module) async { var target = getAuthTargetPage(module).entries.first; - fLog('gooo'); + if (target.value?[0] != null) { isLoading.value = !isLoading.value; await target.value?[0]; @@ -103,7 +103,7 @@ class ModulesLogic extends GetxController { } await Get.toNamed(target.key, arguments: module); - fLog('return'); + if (target.value?[1] != null) { await target.value?[1]; } diff --git a/packages/core/lib/data/services/token_storage_service.dart b/packages/core/lib/data/services/token_storage_service.dart index 0755272..19a19f2 100644 --- a/packages/core/lib/data/services/token_storage_service.dart +++ b/packages/core/lib/data/services/token_storage_service.dart @@ -57,11 +57,9 @@ class TokenStorageService extends GetxService { } Future saveModule(Module input) async { - eLog("before saveModule = ${appModule.value} ==> $input"); await _localStorage.save(boxName: _tokenBoxName, key: _moduleKey, value: input); appModule.value = input; appModule.refresh(); - eLog("after saveModule = ${appModule.value} ==> $input"); } Module? getModule() {