From 7f66476ecaf41f672bca2ab0bd628aeb60c09a7f Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 18 May 2025 11:15:28 +0330 Subject: [PATCH 01/25] feat : add liveStock package --- packages/livestock/.gitignore | 7 ++++ packages/livestock/CHANGELOG.md | 3 ++ packages/livestock/README.md | 39 +++++++++++++++++++ packages/livestock/analysis_options.yaml | 30 ++++++++++++++ .../livestock/example/livestock_example.dart | 6 +++ packages/livestock/lib/livestock.dart | 8 ++++ .../livestock/lib/src/livestock_base.dart | 6 +++ packages/livestock/pubspec.yaml | 35 +++++++++++++++++ packages/livestock/test/livestock_test.dart | 16 ++++++++ tools/package_builder.sh | 2 +- 10 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 packages/livestock/.gitignore create mode 100644 packages/livestock/CHANGELOG.md create mode 100644 packages/livestock/README.md create mode 100644 packages/livestock/analysis_options.yaml create mode 100644 packages/livestock/example/livestock_example.dart create mode 100644 packages/livestock/lib/livestock.dart create mode 100644 packages/livestock/lib/src/livestock_base.dart create mode 100644 packages/livestock/pubspec.yaml create mode 100644 packages/livestock/test/livestock_test.dart diff --git a/packages/livestock/.gitignore b/packages/livestock/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/livestock/.gitignore @@ -0,0 +1,7 @@ +# 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 diff --git a/packages/livestock/CHANGELOG.md b/packages/livestock/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/packages/livestock/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/livestock/README.md b/packages/livestock/README.md new file mode 100644 index 0000000..8831761 --- /dev/null +++ b/packages/livestock/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/livestock/analysis_options.yaml b/packages/livestock/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/packages/livestock/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/packages/livestock/example/livestock_example.dart b/packages/livestock/example/livestock_example.dart new file mode 100644 index 0000000..45f8441 --- /dev/null +++ b/packages/livestock/example/livestock_example.dart @@ -0,0 +1,6 @@ +import 'package:livestock/livestock.dart'; + +void main() { + var awesome = Awesome(); + print('awesome: ${awesome.isAwesome}'); +} diff --git a/packages/livestock/lib/livestock.dart b/packages/livestock/lib/livestock.dart new file mode 100644 index 0000000..850bfa8 --- /dev/null +++ b/packages/livestock/lib/livestock.dart @@ -0,0 +1,8 @@ +/// Support for doing something awesome. +/// +/// More dartdocs go here. +library; + +export 'src/livestock_base.dart'; + +// TODO: Export any libraries intended for clients of this package. diff --git a/packages/livestock/lib/src/livestock_base.dart b/packages/livestock/lib/src/livestock_base.dart new file mode 100644 index 0000000..e8a6f15 --- /dev/null +++ b/packages/livestock/lib/src/livestock_base.dart @@ -0,0 +1,6 @@ +// TODO: Put public facing types in this file. + +/// Checks if you are awesome. Spoiler: you are. +class Awesome { + bool get isAwesome => true; +} diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml new file mode 100644 index 0000000..f591e97 --- /dev/null +++ b/packages/livestock/pubspec.yaml @@ -0,0 +1,35 @@ +name: livestock +description: A starting point for Dart libraries or applications. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.7.2 + + +dependencies: +rasadyar_core: + path: ../core + ##code generation + freezed_annotation: ^3.0.0 + json_annotation: ^4.9.0 +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^5.0.0 + lints: ^5.0.0 + test: ^1.24.0 + ##code generation + build_runner: ^2.4.15 + hive_ce_generator: ^1.9.1 + freezed: ^3.0.6 + json_serializable: ^6.9.4 + + ##test + mocktail: ^1.0.4 + get_test: ^4.0.1 + +flutter: + uses-material-design: true + + diff --git a/packages/livestock/test/livestock_test.dart b/packages/livestock/test/livestock_test.dart new file mode 100644 index 0000000..3104e61 --- /dev/null +++ b/packages/livestock/test/livestock_test.dart @@ -0,0 +1,16 @@ +import 'package:livestock/livestock.dart'; +import 'package:test/test.dart'; + +void main() { + group('A group of tests', () { + final awesome = Awesome(); + + setUp(() { + // Additional setup goes here. + }); + + test('First Test', () { + expect(awesome.isAwesome, isTrue); + }); + }); +} diff --git a/tools/package_builder.sh b/tools/package_builder.sh index c1a8bb6..c14cc59 100644 --- a/tools/package_builder.sh +++ b/tools/package_builder.sh @@ -1,2 +1,2 @@ #!/bin/bash -dart create --template=package ../packages/auth \ No newline at end of file +dart create --template=package ../packages/livestock \ No newline at end of file From 62b23a26df1662c340b4ae1993dba667253f9866 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 18 May 2025 11:50:15 +0330 Subject: [PATCH 02/25] feat : project structure --- packages/livestock/example/livestock_example.dart | 6 ------ packages/livestock/lib/livestock.dart | 2 -- packages/livestock/lib/src/livestock_base.dart | 6 ------ packages/livestock/pubspec.yaml | 6 ++++-- packages/livestock/test/livestock_test.dart | 10 ---------- 5 files changed, 4 insertions(+), 26 deletions(-) delete mode 100644 packages/livestock/example/livestock_example.dart delete mode 100644 packages/livestock/lib/src/livestock_base.dart diff --git a/packages/livestock/example/livestock_example.dart b/packages/livestock/example/livestock_example.dart deleted file mode 100644 index 45f8441..0000000 --- a/packages/livestock/example/livestock_example.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:livestock/livestock.dart'; - -void main() { - var awesome = Awesome(); - print('awesome: ${awesome.isAwesome}'); -} diff --git a/packages/livestock/lib/livestock.dart b/packages/livestock/lib/livestock.dart index 850bfa8..6289ca5 100644 --- a/packages/livestock/lib/livestock.dart +++ b/packages/livestock/lib/livestock.dart @@ -3,6 +3,4 @@ /// More dartdocs go here. library; -export 'src/livestock_base.dart'; -// TODO: Export any libraries intended for clients of this package. diff --git a/packages/livestock/lib/src/livestock_base.dart b/packages/livestock/lib/src/livestock_base.dart deleted file mode 100644 index e8a6f15..0000000 --- a/packages/livestock/lib/src/livestock_base.dart +++ /dev/null @@ -1,6 +0,0 @@ -// TODO: Put public facing types in this file. - -/// Checks if you are awesome. Spoiler: you are. -class Awesome { - bool get isAwesome => true; -} diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml index f591e97..09d7557 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -1,6 +1,7 @@ name: livestock description: A starting point for Dart libraries or applications. version: 1.0.0 +publish_to: 'none' # repository: https://github.com/my_org/my_repo environment: @@ -8,8 +9,9 @@ environment: dependencies: -rasadyar_core: - path: ../core + + rasadyar_core: + path: ../core ##code generation freezed_annotation: ^3.0.0 json_annotation: ^4.9.0 diff --git a/packages/livestock/test/livestock_test.dart b/packages/livestock/test/livestock_test.dart index 3104e61..dbd1d90 100644 --- a/packages/livestock/test/livestock_test.dart +++ b/packages/livestock/test/livestock_test.dart @@ -2,15 +2,5 @@ import 'package:livestock/livestock.dart'; import 'package:test/test.dart'; void main() { - group('A group of tests', () { - final awesome = Awesome(); - setUp(() { - // Additional setup goes here. - }); - - test('First Test', () { - expect(awesome.isAwesome, isTrue); - }); - }); } From 982329a3eba75895c2b983822c49fa8c2882efd6 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 19 May 2025 09:43:11 +0330 Subject: [PATCH 03/25] chore : change for package using --- tools/vecGeneratoe.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/vecGeneratoe.sh b/tools/vecGeneratoe.sh index 4f92558..1b84fb3 100644 --- a/tools/vecGeneratoe.sh +++ b/tools/vecGeneratoe.sh @@ -1,8 +1,20 @@ #!/bin/bash + +# Relative path to the package +PACKAGE_PATH="../packages/core" + +# Get absolute path to the package +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PACKAGE_ABS_PATH="$SCRIPT_DIR/$PACKAGE_PATH" + +echo "🗃️ package path: $PACKAGE_ABS_PATH" + # Directory to read files from -sourcePath="assets/icons" -targetPath="assets/vec" +sourcePath="$PACKAGE_ABS_PATH/assets/icons" +targetPath="$PACKAGE_ABS_PATH/assets/vec" +echo "🗃️ sourcePath path: $sourcePath" +echo "🗃️ targetPath path: $targetPath" if [ ! -e "$targetPath" ]; then From 905e407ccdefb926b0e86c5ca21a0bc62b06e78f Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 19 May 2025 16:16:33 +0330 Subject: [PATCH 04/25] fix : 1 - multi module in Auth select save selected module 2 - add flutter gen for assets builder --- assets/icons/inspection.svg | 1 + assets/icons/liveStock.svg | 1 + assets/vec/inspection.svg.vec | Bin 0 -> 4224 bytes assets/vec/liveStock.svg.vec | Bin 0 -> 5948 bytes lib/infrastructure/service/auth_service.dart | 16 +- lib/presentation/pages/splash/logic.dart | 10 +- lib/presentation/pages/splash/view.dart | 7 +- lib/presentation/routes/app_pages.dart | 17 +- packages/auth/lib/auth.dart | 1 + packages/auth/lib/data/di/auth_di.dart | 1 + .../models/local/module/module_model.dart | 16 + .../local/module/module_model.freezed.dart | 148 ++++++ .../local/user_local/user_local_model.dart | 15 + .../local/user_local/user_local_model.g.dart | 44 +- .../data/services/token_storage_service.dart | 22 +- packages/auth/lib/hive_registrar.g.dart | 2 + .../lib/presentation/pages/auth/logic.dart | 15 +- .../lib/presentation/pages/auth/view.dart | 10 +- .../lib/presentation/pages/modules/logic.dart | 12 + .../lib/presentation/pages/modules/view.dart | 36 +- .../auth/lib/presentation/routes/pages.dart | 7 +- .../lib/presentation/widget/logo_widget.dart | 5 +- packages/core/lib/core.dart | 2 + .../core/lib/presentation/common/assets.dart | 72 --- .../lib/presentation/common/assets.gen.dart | 451 ++++++++++++++++++ .../core/lib/presentation/common/common.dart | 2 +- .../lib/presentation/common/fonts.gen.dart | 15 + .../wave_bottom_navigation.dart | 9 +- .../lib/presentation/widget/buttons/fab.dart | 83 +++- .../widget/buttons/fab_outlined.dart | 426 +++++++++-------- .../card/card_with_icon_with_border.dart | 46 ++ .../lib/presentation/widget/vec_widget.dart | 11 +- .../core/lib/presentation/widget/widget.dart | 1 + packages/core/pubspec.lock | 56 +++ packages/core/pubspec.yaml | 10 + .../lib/presentation/action/view.dart | 37 +- .../add_mobile_inspector/view.dart | 8 +- .../presentation/add_supervision/view.dart | 8 +- .../display_information/view.dart | 8 +- .../lib/presentation/filter/view.dart | 25 +- .../lib/presentation/profile/view.dart | 44 +- .../registration_of_violation/view.dart | 8 +- .../lib/presentation/root/view.dart | 38 +- .../lib/presentation/page/root/logic.dart | 17 + .../lib/presentation/page/root/view.dart | 12 + pubspec.lock | 63 +++ 46 files changed, 1431 insertions(+), 407 deletions(-) create mode 100644 assets/icons/inspection.svg create mode 100644 assets/icons/liveStock.svg create mode 100644 assets/vec/inspection.svg.vec create mode 100644 assets/vec/liveStock.svg.vec create mode 100644 packages/auth/lib/data/models/local/module/module_model.dart create mode 100644 packages/auth/lib/data/models/local/module/module_model.freezed.dart delete mode 100644 packages/core/lib/presentation/common/assets.dart create mode 100644 packages/core/lib/presentation/common/assets.gen.dart create mode 100644 packages/core/lib/presentation/common/fonts.gen.dart create mode 100644 packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart create mode 100644 packages/livestock/lib/presentation/page/root/logic.dart create mode 100644 packages/livestock/lib/presentation/page/root/view.dart diff --git a/assets/icons/inspection.svg b/assets/icons/inspection.svg new file mode 100644 index 0000000..3e49ae8 --- /dev/null +++ b/assets/icons/inspection.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/liveStock.svg b/assets/icons/liveStock.svg new file mode 100644 index 0000000..24b6c5e --- /dev/null +++ b/assets/icons/liveStock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/vec/inspection.svg.vec b/assets/vec/inspection.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..ed9d937f9d3ac204d8e1be8c8e8792016d9641c9 GIT binary patch literal 4224 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 Y5EbD}DbA}3dnM=*LP?U5P|AjX1JC_?(f|Me literal 0 HcmV?d00001 diff --git a/assets/vec/liveStock.svg.vec b/assets/vec/liveStock.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..469f5a140fc70f19d9f9a5abd2b8361412bc51a3 GIT binary patch literal 5948 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 @@ -13,25 +15,19 @@ class AuthService extends GetxService { super.onInit(); ever(tokenService.accessToken, (callback) { - iLog('Access token callback: $callback, value: ${tokenService.accessToken.value}'); accessRes.value = (callback != null); }); ever(tokenService.refreshToken, (callback) { - fLog('Refresh token callback: $callback, value: ${tokenService.refreshToken.value}'); refAccessRes.value = (callback != null); }); - everAll([accessRes, refAccessRes], (_) { if (accessRes.value && refAccessRes.value) { - - Get.offAndToNamed(InspectionRoutes.inspection); - fLog('Both accessToken and refreshToken are available: accessToken=${tokenService.accessToken.value}, refreshToken=${tokenService.refreshToken.value}'); - } else { - fLog('One or both tokens are missing: accessToken=${tokenService.accessToken.value}, refreshToken=${tokenService.refreshToken.value}'); + var targetPage = getTargetPage(tokenService.appModule.value); + Get.offAndToNamed(targetPage); } }); - } + } diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart index 4dd4a4e..8f26018 100644 --- a/lib/presentation/pages/splash/logic.dart +++ b/lib/presentation/pages/splash/logic.dart @@ -1,6 +1,7 @@ import 'package:flutter/animation.dart'; +import 'package:rasadyar_app/presentation/routes/app_pages.dart'; +import 'package:rasadyar_auth/data/services/token_storage_service.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_inspection/inspection.dart'; class SplashLogic extends GetxController with GetTickerProviderStateMixin { late final AnimationController scaleController; @@ -8,6 +9,8 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { Rxn> scaleAnimation = Rxn(); Rxn> rotationAnimation = Rxn(); + var tokenService = Get.find(); + @override void onInit() { super.onInit(); @@ -53,8 +56,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin { @override void onReady() { super.onReady(); - Future.delayed(const Duration(seconds: 1), () { - Get.offAllNamed(InspectionRoutes.inspection); + Future.delayed(const Duration(seconds: 1), () async { + var module = tokenService.appModule.value; + Get.offAndToNamed(getTargetPage(module)); }); } diff --git a/lib/presentation/pages/splash/view.dart b/lib/presentation/pages/splash/view.dart index bffd309..4cd5ce8 100644 --- a/lib/presentation/pages/splash/view.dart +++ b/lib/presentation/pages/splash/view.dart @@ -20,11 +20,10 @@ class SplashPage extends GetView { scale: data.value!, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 1), - child: Image.asset( - Assets.imagesInnerSplash, + child: Assets.images.innerSplash.image( width: 190, height: 190, - ), + ) ), ); }, controller.scaleAnimation), @@ -35,7 +34,7 @@ class SplashPage extends GetView { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 1), - child: Image.asset(Assets.imagesOutterSplash), + child: Assets.images.outterSplash.image() ), ); }, controller.rotationAnimation), diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart index 61effcb..8e5f373 100644 --- a/lib/presentation/routes/app_pages.dart +++ b/lib/presentation/routes/app_pages.dart @@ -1,9 +1,12 @@ 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_auth/auth.dart'; +import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart'; import 'package:rasadyar_auth/presentation/routes/pages.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_inspection/inspection.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; part 'app_paths.dart'; @@ -23,6 +26,18 @@ sealed class AppPages { ...InspectionPages.pages, ...AuthPages.pages, - + ...LiveStockPages.pages, ]; } + +String getTargetPage(Module? value) { + eLog('getTargetPage: $value'); + switch (value) { + case Module.inspection: + return InspectionRoutes.inspection; + case Module.liveStocks: + return LiveStockRoutes.init; + default: + return InspectionRoutes.inspection; + } +} \ No newline at end of file diff --git a/packages/auth/lib/auth.dart b/packages/auth/lib/auth.dart index 9e7c1c4..30c7f5f 100644 --- a/packages/auth/lib/auth.dart +++ b/packages/auth/lib/auth.dart @@ -5,3 +5,4 @@ library; export 'data/services/auth_middelware.dart'; export 'data/di/auth_di.dart'; +export 'data/models/local/module/module_model.dart'; diff --git a/packages/auth/lib/data/di/auth_di.dart b/packages/auth/lib/data/di/auth_di.dart index 3f4771e..190715f 100644 --- a/packages/auth/lib/data/di/auth_di.dart +++ b/packages/auth/lib/data/di/auth_di.dart @@ -11,6 +11,7 @@ GetIt diAuth = GetIt.instance; Future setupAuthDI() async { diAuth.registerLazySingleton(() => DioRemoteManager()); + final manager = diAuth.get(); final dioRemote = await manager.setEnvironment(ApiEnvironment.dam); diAuth.registerCachedFactory( diff --git a/packages/auth/lib/data/models/local/module/module_model.dart b/packages/auth/lib/data/models/local/module/module_model.dart new file mode 100644 index 0000000..f543681 --- /dev/null +++ b/packages/auth/lib/data/models/local/module/module_model.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart'; +import 'package:rasadyar_core/core.dart'; + +part 'module_model.freezed.dart'; + + +@freezed +abstract class ModuleModel with _$ModuleModel{ + const factory ModuleModel({ + required String title, + required String icon, + required Module module, + }) = _ModuleModel; + +} \ No newline at end of file diff --git a/packages/auth/lib/data/models/local/module/module_model.freezed.dart b/packages/auth/lib/data/models/local/module/module_model.freezed.dart new file mode 100644 index 0000000..48feb37 --- /dev/null +++ b/packages/auth/lib/data/models/local/module/module_model.freezed.dart @@ -0,0 +1,148 @@ +// dart format width=80 +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// 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 'module_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ModuleModel { + + String get title; String get icon; Module get module; +/// Create a copy of ModuleModel +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ModuleModelCopyWith get copyWith => _$ModuleModelCopyWithImpl(this as ModuleModel, _$identity); + + + +@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)); +} + + +@override +int get hashCode => Object.hash(runtimeType,title,icon,module); + +@override +String toString() { + return 'ModuleModel(title: $title, icon: $icon, module: $module)'; +} + + +} + +/// @nodoc +abstract mixin class $ModuleModelCopyWith<$Res> { + factory $ModuleModelCopyWith(ModuleModel value, $Res Function(ModuleModel) _then) = _$ModuleModelCopyWithImpl; +@useResult +$Res call({ + String title, String icon, Module module +}); + + + + +} +/// @nodoc +class _$ModuleModelCopyWithImpl<$Res> + implements $ModuleModelCopyWith<$Res> { + _$ModuleModelCopyWithImpl(this._self, this._then); + + final ModuleModel _self; + final $Res Function(ModuleModel) _then; + +/// 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,}) { + 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, + )); +} + +} + + +/// @nodoc + + +class _ModuleModel implements ModuleModel { + const _ModuleModel({required this.title, required this.icon, required this.module}); + + +@override final String title; +@override final String icon; +@override final Module module; + +/// Create a copy of ModuleModel +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ModuleModelCopyWith<_ModuleModel> get copyWith => __$ModuleModelCopyWithImpl<_ModuleModel>(this, _$identity); + + + +@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)); +} + + +@override +int get hashCode => Object.hash(runtimeType,title,icon,module); + +@override +String toString() { + return 'ModuleModel(title: $title, icon: $icon, module: $module)'; +} + + +} + +/// @nodoc +abstract mixin class _$ModuleModelCopyWith<$Res> implements $ModuleModelCopyWith<$Res> { + factory _$ModuleModelCopyWith(_ModuleModel value, $Res Function(_ModuleModel) _then) = __$ModuleModelCopyWithImpl; +@override @useResult +$Res call({ + String title, String icon, Module module +}); + + + + +} +/// @nodoc +class __$ModuleModelCopyWithImpl<$Res> + implements _$ModuleModelCopyWith<$Res> { + __$ModuleModelCopyWithImpl(this._self, this._then); + + final _ModuleModel _self; + final $Res Function(_ModuleModel) _then; + +/// 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,}) { + 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, + )); +} + + +} + +// dart format on diff --git a/packages/auth/lib/data/models/local/user_local/user_local_model.dart b/packages/auth/lib/data/models/local/user_local/user_local_model.dart index 403f762..c14addc 100644 --- a/packages/auth/lib/data/models/local/user_local/user_local_model.dart +++ b/packages/auth/lib/data/models/local/user_local/user_local_model.dart @@ -1,3 +1,4 @@ +import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_core/core.dart'; part 'user_local_model.g.dart'; @@ -15,12 +16,16 @@ class UserLocalModel extends HiveObject { @HiveField(4) String? name; + @HiveField(5) + Module? module; + UserLocalModel({ this.username, this.password, this.token, this.refreshToken, this.name, + this.module, }); UserLocalModel copyWith({ @@ -29,6 +34,7 @@ class UserLocalModel extends HiveObject { String? token, String? refreshToken, String? name, + Module? module, }) { return UserLocalModel( username: username ?? this.username, @@ -36,6 +42,15 @@ class UserLocalModel extends HiveObject { token: token ?? this.token, refreshToken: refreshToken ?? this.refreshToken, name: name ?? this.name, + module: module ?? this.module, ); } } + +@HiveType(typeId: 1) +enum Module { + @HiveField(0) + liveStocks, + @HiveField(1) + inspection, +} diff --git a/packages/auth/lib/data/models/local/user_local/user_local_model.g.dart b/packages/auth/lib/data/models/local/user_local/user_local_model.g.dart index 13f86a8..efaac19 100644 --- a/packages/auth/lib/data/models/local/user_local/user_local_model.g.dart +++ b/packages/auth/lib/data/models/local/user_local/user_local_model.g.dart @@ -22,13 +22,14 @@ class UserLocalModelAdapter extends TypeAdapter { token: fields[2] as String?, refreshToken: fields[3] as String?, name: fields[4] as String?, + module: fields[5] as Module?, ); } @override void write(BinaryWriter writer, UserLocalModel obj) { writer - ..writeByte(5) + ..writeByte(6) ..writeByte(0) ..write(obj.username) ..writeByte(1) @@ -38,7 +39,9 @@ class UserLocalModelAdapter extends TypeAdapter { ..writeByte(3) ..write(obj.refreshToken) ..writeByte(4) - ..write(obj.name); + ..write(obj.name) + ..writeByte(5) + ..write(obj.module); } @override @@ -51,3 +54,40 @@ class UserLocalModelAdapter extends TypeAdapter { runtimeType == other.runtimeType && typeId == other.typeId; } + +class ModuleAdapter extends TypeAdapter { + @override + final typeId = 1; + + @override + Module read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return Module.liveStocks; + case 1: + return Module.inspection; + default: + return Module.liveStocks; + } + } + + @override + void write(BinaryWriter writer, Module obj) { + switch (obj) { + case Module.liveStocks: + writer.writeByte(0); + case Module.inspection: + writer.writeByte(1); + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ModuleAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/packages/auth/lib/data/services/token_storage_service.dart b/packages/auth/lib/data/services/token_storage_service.dart index 78fc35b..39d33dd 100644 --- a/packages/auth/lib/data/services/token_storage_service.dart +++ b/packages/auth/lib/data/services/token_storage_service.dart @@ -1,20 +1,26 @@ import 'dart:convert'; +import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart'; +import 'package:rasadyar_auth/hive_registrar.g.dart'; import 'package:rasadyar_core/core.dart'; class TokenStorageService extends GetxService { static const String _boxName = 'secureBox'; static const String _accessTokenKey = 'accessToken'; static const String _refreshTokenKey = 'refreshToken'; + static const String _moduleKey = 'moduleSelected'; final FlutterSecureStorage _secureStorage = FlutterSecureStorage(); final HiveLocalStorage _localStorage = diCore.get(); - RxnString accessToken = RxnString(); - RxnString refreshToken = RxnString(); - RxnString tsss = RxnString(); + RxnString accessToken = RxnString(); + RxnString refreshToken = RxnString(); + Rxn appModule = Rxn(null); Future init() async { + Hive.registerAdapters(); + IsolatedHive.registerAdapters(); + final String? encryptedKey = await _secureStorage.read(key: 'hive_enc_key'); final encryptionKey = encryptedKey != null @@ -42,6 +48,10 @@ class TokenStorageService extends GetxService { boxName: _boxName, key: _refreshTokenKey, ); + appModule.value = _localStorage.read( + boxName: _boxName, + key: _moduleKey, + ); } Future saveAccessToken(String token) async { @@ -64,6 +74,12 @@ class TokenStorageService extends GetxService { refreshToken.refresh(); } + Future saveModule(Module input) async { + await _localStorage.save(boxName: _boxName, key: _moduleKey, value: input); + appModule.value = input; + appModule.refresh(); + } + Future deleteTokens() async { await _localStorage.clear(_boxName); accessToken.value = null; diff --git a/packages/auth/lib/hive_registrar.g.dart b/packages/auth/lib/hive_registrar.g.dart index b4abe2c..166b5cb 100644 --- a/packages/auth/lib/hive_registrar.g.dart +++ b/packages/auth/lib/hive_registrar.g.dart @@ -7,12 +7,14 @@ import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart extension HiveRegistrar on HiveInterface { void registerAdapters() { + registerAdapter(ModuleAdapter()); registerAdapter(UserLocalModelAdapter()); } } extension IsolatedHiveRegistrar on IsolatedHiveInterface { void registerAdapters() { + registerAdapter(ModuleAdapter()); registerAdapter(UserLocalModelAdapter()); } } diff --git a/packages/auth/lib/presentation/pages/auth/logic.dart b/packages/auth/lib/presentation/pages/auth/logic.dart index eacfb7c..59b8167 100644 --- a/packages/auth/lib/presentation/pages/auth/logic.dart +++ b/packages/auth/lib/presentation/pages/auth/logic.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_auth/data/common/dio_error_handler.dart'; +import 'package:rasadyar_auth/data/models/local/module/module_model.dart'; import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart'; import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; @@ -10,6 +11,8 @@ import 'package:rasadyar_auth/data/services/token_storage_service.dart'; import 'package:rasadyar_auth/presentation/widget/captcha/logic.dart'; import 'package:rasadyar_core/core.dart'; +import '../../../data/models/local/user_local/user_local_model.dart'; + enum AuthType { useAndPass, otp } enum AuthStatus { init } @@ -42,6 +45,8 @@ class AuthLogic extends GetxController { AuthRepositoryImpl authRepository = diAuth.get(); + final Module _module = Get.arguments; + void startTimer() { _timer?.cancel(); secondsRemaining.value = 120; @@ -73,8 +78,8 @@ class AuthLogic extends GetxController { @override void onReady() { - // TODO: implement onReady super.onReady(); + iLog('module111 : ${_module.toString()}'); } @override @@ -106,14 +111,16 @@ class AuthLogic extends GetxController { Future submitLoginForm() async { if (!_isFormValid()) return; - + iLog('module222 : ${_module.toString()}'); final loginRequestModel = _buildLoginRequest(); isLoading.value = true; await safeCall( call: () => authRepository.login(authRequest: loginRequestModel.toJson()), onSuccess: (result) async { - await tokenStorageService.saveRefreshToken(result!.refresh!); - await tokenStorageService.saveAccessToken(result!.access!); + await tokenStorageService.saveModule(_module); + await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); + await tokenStorageService.saveAccessToken(result?.access ?? ''); + //Get.offAndToNamed(Routes.home); }, onError: (error, stackTrace) { diff --git a/packages/auth/lib/presentation/pages/auth/view.dart b/packages/auth/lib/presentation/pages/auth/view.dart index 90f764c..343c050 100644 --- a/packages/auth/lib/presentation/pages/auth/view.dart +++ b/packages/auth/lib/presentation/pages/auth/view.dart @@ -109,7 +109,10 @@ class AuthPage extends GetView { }, prefixIcon: Padding( padding: const EdgeInsets.fromLTRB(0, 8, 6, 8), - child: vecWidget(Assets.vecCallSvg), + child: Assets.vec.callSvg.svg( + width: 12, + height: 12, + ), ), suffixIcon: phoneController.value.text @@ -168,7 +171,10 @@ class AuthPage extends GetView { labelStyle: AppFonts.yekan13, prefixIcon: Padding( padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), - child: vecWidget(Assets.vecKeySvg), + child: Assets.vec.keySvg.svg( + width: 12, + height: 12, + ), ), boxConstraints: const BoxConstraints( maxHeight: 34, diff --git a/packages/auth/lib/presentation/pages/modules/logic.dart b/packages/auth/lib/presentation/pages/modules/logic.dart index 87c35ee..bf9692c 100644 --- a/packages/auth/lib/presentation/pages/modules/logic.dart +++ b/packages/auth/lib/presentation/pages/modules/logic.dart @@ -1,7 +1,16 @@ +import 'package:rasadyar_auth/data/models/local/module/module_model.dart'; +import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart'; import 'package:rasadyar_core/core.dart'; 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), + ]; + + + RxnInt selectedIndex = RxnInt(null); @override @@ -9,6 +18,9 @@ class ModulesLogic extends GetxController { super.onReady(); } + + + @override void onClose() { super.onClose(); diff --git a/packages/auth/lib/presentation/pages/modules/view.dart b/packages/auth/lib/presentation/pages/modules/view.dart index f1c4a0b..e3ebe32 100644 --- a/packages/auth/lib/presentation/pages/modules/view.dart +++ b/packages/auth/lib/presentation/pages/modules/view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:rasadyar_auth/presentation/routes/pages.dart'; +import 'package:rasadyar_core/core.dart'; import 'logic.dart'; @@ -8,8 +9,37 @@ class ModulesPage extends GetView { @override Widget build(BuildContext context) { - final ModulesLogic logic = Get.put(ModulesLogic()); + return Scaffold( + appBar: AppBar( + title: Text( + 'انتخاب سامانه', + style: AppFonts.yekan18.copyWith(color: Colors.white), + ), + centerTitle: true, + backgroundColor: AppColor.blueNormal, + ), + body: GridView.builder( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), - return Container(); + itemBuilder: (context, index) { + final module = controller.moduleList[index]; + return CardIcon( + title: module.title, + icon: module.icon, + onTap: () { + controller.selectedIndex.value = index; + Get.toNamed(AuthPaths.auth, arguments: module.module); + }, + ); + }, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + ), + physics: BouncingScrollPhysics(), + itemCount: controller.moduleList.length, + ), + ); } } diff --git a/packages/auth/lib/presentation/routes/pages.dart b/packages/auth/lib/presentation/routes/pages.dart index 11b8d56..5248b3d 100644 --- a/packages/auth/lib/presentation/routes/pages.dart +++ b/packages/auth/lib/presentation/routes/pages.dart @@ -1,3 +1,5 @@ +import 'package:rasadyar_auth/presentation/pages/modules/logic.dart'; +import 'package:rasadyar_auth/presentation/pages/modules/view.dart'; import 'package:rasadyar_auth/presentation/widget/captcha/logic.dart'; import 'package:rasadyar_core/core.dart'; @@ -12,10 +14,9 @@ sealed class AuthPages { static List pages = [ GetPage( name: AuthPaths.moduleList, - page: () => AuthPage(), + page: () => ModulesPage(), binding: BindingsBuilder(() { - Get.lazyPut(() => AuthLogic()); - Get.lazyPut(() => CaptchaWidgetLogic()); + Get.lazyPut(() => ModulesLogic()); }), ), diff --git a/packages/auth/lib/presentation/widget/logo_widget.dart b/packages/auth/lib/presentation/widget/logo_widget.dart index ea4a5a9..4cf2a26 100644 --- a/packages/auth/lib/presentation/widget/logo_widget.dart +++ b/packages/auth/lib/presentation/widget/logo_widget.dart @@ -9,7 +9,10 @@ class LogoWidget extends StatelessWidget { return Column( children: [ Row(), - Image.asset(Assets.imagesInnerSplash, width: 120, height: 120), + Assets.images.innerSplash.image( + width: 150, + height: 150, + ), Text( 'سامانه رصدیار', style: AppFonts.yekan16.copyWith(color: AppColor.darkGreyNormal), diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 6108fd6..f4318ec 100644 --- a/packages/core/lib/core.dart +++ b/packages/core/lib/core.dart @@ -1,5 +1,6 @@ library; + //other packages export 'package:flutter_localizations/flutter_localizations.dart'; export 'package:flutter_map/flutter_map.dart'; @@ -7,6 +8,7 @@ export 'package:flutter_map_animations/flutter_map_animations.dart'; export 'package:flutter_rating_bar/flutter_rating_bar.dart'; export 'package:flutter_slidable/flutter_slidable.dart'; export 'package:font_awesome_flutter/font_awesome_flutter.dart'; +export 'package:hive_ce_flutter/hive_flutter.dart'; //freezed export 'package:freezed_annotation/freezed_annotation.dart'; export 'package:geolocator/geolocator.dart'; diff --git a/packages/core/lib/presentation/common/assets.dart b/packages/core/lib/presentation/common/assets.dart deleted file mode 100644 index 0e70b14..0000000 --- a/packages/core/lib/presentation/common/assets.dart +++ /dev/null @@ -1,72 +0,0 @@ -///This file is automatically generated. DO NOT EDIT, all your changes would be lost. -class Assets { - Assets._(); - - static const String iconsAdd = 'assets/icons/add.svg'; - static const String iconsArrowLeft = 'assets/icons/arrow_left.svg'; - static const String iconsArrowRight = 'assets/icons/arrow_right.svg'; - static const String iconsBgHeaderUserProfile = 'assets/icons/bg_header_user_profile.svg'; - static const String iconsCalendar = 'assets/icons/calendar.svg'; - static const String iconsCalendarSearch = 'assets/icons/calendar_search.svg'; - static const String iconsCall = 'assets/icons/call.svg'; - static const String iconsDiagram = 'assets/icons/diagram.svg'; - static const String iconsDownload = 'assets/icons/download.svg'; - static const String iconsEdit = 'assets/icons/edit.svg'; - static const String iconsExcelDownload = 'assets/icons/excel_download.svg'; - static const String iconsFilter = 'assets/icons/filter.svg'; - static const String iconsGps = 'assets/icons/gps.svg'; - static const String iconsInformation = 'assets/icons/information.svg'; - static const String iconsKey = 'assets/icons/key.svg'; - static const String iconsLogout = 'assets/icons/logout.svg'; - static const String iconsMap = 'assets/icons/map.svg'; - static const String iconsMapMarker = 'assets/icons/map_marker.svg'; - static const String iconsMessageAdd = 'assets/icons/message_add.svg'; - static const String iconsPdfDownload = 'assets/icons/pdf_download.svg'; - static const String iconsPictureFrame = 'assets/icons/picture_frame.svg'; - static const String iconsProfileCircle = 'assets/icons/profile_circle.svg'; - static const String iconsProfileUser = 'assets/icons/profile_user.svg'; - static const String iconsReceiptDiscount = 'assets/icons/receipt_discount.svg'; - static const String iconsScan = 'assets/icons/scan.svg'; - static const String iconsScanBarcode = 'assets/icons/scan_barcode.svg'; - static const String iconsSecurityTime = 'assets/icons/security_time.svg'; - static const String iconsSetting = 'assets/icons/setting.svg'; - static const String iconsTagUser = 'assets/icons/tag_user.svg'; - static const String iconsTrash = 'assets/icons/trash.svg'; - static const String iconsUser = 'assets/icons/user.svg'; - static const String iconsUserSquare = 'assets/icons/user_square.svg'; - static const String imagesInnerSplash = 'assets/images/inner_splash.webp'; - static const String imagesOutterSplash = 'assets/images/outter_splash.webp'; - static const String vecAddSvg = 'assets/vec/add.svg.vec'; - static const String vecArrowLeftSvg = 'assets/vec/arrow_left.svg.vec'; - static const String vecArrowRightSvg = 'assets/vec/arrow_right.svg.vec'; - static const String vecBgHeaderUserProfileSvg = 'assets/vec/bg_header_user_profile.svg.vec'; - static const String vecCalendarSearchSvg = 'assets/vec/calendar_search.svg.vec'; - static const String vecCalendarSvg = 'assets/vec/calendar.svg.vec'; - static const String vecCallSvg = 'assets/vec/call.svg.vec'; - static const String vecDiagramSvg = 'assets/vec/diagram.svg.vec'; - static const String vecDownloadSvg = 'assets/vec/download.svg.vec'; - static const String vecEditSvg = 'assets/vec/edit.svg.vec'; - static const String vecExcelDownloadSvg = 'assets/vec/excel_download.svg.vec'; - static const String vecFilterSvg = 'assets/vec/filter.svg.vec'; - static const String vecGpsSvg = 'assets/vec/gps.svg.vec'; - static const String vecInformationSvg = 'assets/vec/information.svg.vec'; - static const String vecKeySvg = 'assets/vec/key.svg.vec'; - static const String vecLogoutSvg = 'assets/vec/logout.svg.vec'; - static const String vecMapMarkerSvg = 'assets/vec/map_marker.svg.vec'; - static const String vecMapSvg = 'assets/vec/map.svg.vec'; - static const String vecMessageAddSvg = 'assets/vec/message_add.svg.vec'; - static const String vecPdfDownloadSvg = 'assets/vec/pdf_download.svg.vec'; - static const String vecPictureFrameSvg = 'assets/vec/picture_frame.svg.vec'; - static const String vecProfileCircleSvg = 'assets/vec/profile_circle.svg.vec'; - static const String vecProfileUserSvg = 'assets/vec/profile_user.svg.vec'; - static const String vecReceiptDiscountSvg = 'assets/vec/receipt_discount.svg.vec'; - static const String vecScanBarcodeSvg = 'assets/vec/scan_barcode.svg.vec'; - static const String vecScanSvg = 'assets/vec/scan.svg.vec'; - static const String vecSecurityTimeSvg = 'assets/vec/security_time.svg.vec'; - static const String vecSettingSvg = 'assets/vec/setting.svg.vec'; - static const String vecTagUserSvg = 'assets/vec/tag_user.svg.vec'; - static const String vecTrashSvg = 'assets/vec/trash.svg.vec'; - static const String vecUserSquareSvg = 'assets/vec/user_square.svg.vec'; - static const String vecUserSvg = 'assets/vec/user.svg.vec'; - -} diff --git a/packages/core/lib/presentation/common/assets.gen.dart b/packages/core/lib/presentation/common/assets.gen.dart new file mode 100644 index 0000000..3ae3076 --- /dev/null +++ b/packages/core/lib/presentation/common/assets.gen.dart @@ -0,0 +1,451 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_svg/flutter_svg.dart' as _svg; +import 'package:vector_graphics/vector_graphics.dart' as _vg; + +class $AssetsIconsGen { + const $AssetsIconsGen(); + + /// File path: assets/icons/add.svg + SvgGenImage get add => const SvgGenImage('assets/icons/add.svg'); + + /// File path: assets/icons/arrow_left.svg + SvgGenImage get arrowLeft => const SvgGenImage('assets/icons/arrow_left.svg'); + + /// File path: assets/icons/arrow_right.svg + SvgGenImage get arrowRight => const SvgGenImage('assets/icons/arrow_right.svg'); + + /// File path: assets/icons/bg_header_user_profile.svg + SvgGenImage get bgHeaderUserProfile => const SvgGenImage('assets/icons/bg_header_user_profile.svg'); + + /// File path: assets/icons/calendar.svg + SvgGenImage get calendar => const SvgGenImage('assets/icons/calendar.svg'); + + /// File path: assets/icons/calendar_search.svg + SvgGenImage get calendarSearch => const SvgGenImage('assets/icons/calendar_search.svg'); + + /// File path: assets/icons/call.svg + SvgGenImage get call => const SvgGenImage('assets/icons/call.svg'); + + /// File path: assets/icons/diagram.svg + SvgGenImage get diagram => const SvgGenImage('assets/icons/diagram.svg'); + + /// File path: assets/icons/download.svg + SvgGenImage get download => const SvgGenImage('assets/icons/download.svg'); + + /// File path: assets/icons/edit.svg + SvgGenImage get edit => const SvgGenImage('assets/icons/edit.svg'); + + /// File path: assets/icons/excel_download.svg + SvgGenImage get excelDownload => const SvgGenImage('assets/icons/excel_download.svg'); + + /// File path: assets/icons/filter.svg + SvgGenImage get filter => const SvgGenImage('assets/icons/filter.svg'); + + /// File path: assets/icons/gps.svg + SvgGenImage get gps => const SvgGenImage('assets/icons/gps.svg'); + + /// File path: assets/icons/information.svg + SvgGenImage get information => const SvgGenImage('assets/icons/information.svg'); + + /// File path: assets/icons/inspection.svg + SvgGenImage get inspection => const SvgGenImage('assets/icons/inspection.svg'); + + /// File path: assets/icons/key.svg + SvgGenImage get key => const SvgGenImage('assets/icons/key.svg'); + + /// File path: assets/icons/liveStock.svg + SvgGenImage get liveStock => const SvgGenImage('assets/icons/liveStock.svg'); + + /// File path: assets/icons/logout.svg + SvgGenImage get logout => const SvgGenImage('assets/icons/logout.svg'); + + /// File path: assets/icons/map.svg + SvgGenImage get map => const SvgGenImage('assets/icons/map.svg'); + + /// File path: assets/icons/map_marker.svg + SvgGenImage get mapMarker => const SvgGenImage('assets/icons/map_marker.svg'); + + /// File path: assets/icons/message_add.svg + SvgGenImage get messageAdd => const SvgGenImage('assets/icons/message_add.svg'); + + /// File path: assets/icons/pdf_download.svg + SvgGenImage get pdfDownload => const SvgGenImage('assets/icons/pdf_download.svg'); + + /// File path: assets/icons/picture_frame.svg + SvgGenImage get pictureFrame => const SvgGenImage('assets/icons/picture_frame.svg'); + + /// File path: assets/icons/profile_circle.svg + SvgGenImage get profileCircle => const SvgGenImage('assets/icons/profile_circle.svg'); + + /// File path: assets/icons/profile_user.svg + SvgGenImage get profileUser => const SvgGenImage('assets/icons/profile_user.svg'); + + /// File path: assets/icons/receipt_discount.svg + SvgGenImage get receiptDiscount => const SvgGenImage('assets/icons/receipt_discount.svg'); + + /// File path: assets/icons/scan.svg + SvgGenImage get scan => const SvgGenImage('assets/icons/scan.svg'); + + /// File path: assets/icons/scan_barcode.svg + SvgGenImage get scanBarcode => const SvgGenImage('assets/icons/scan_barcode.svg'); + + /// File path: assets/icons/security_time.svg + SvgGenImage get securityTime => const SvgGenImage('assets/icons/security_time.svg'); + + /// File path: assets/icons/setting.svg + SvgGenImage get setting => const SvgGenImage('assets/icons/setting.svg'); + + /// File path: assets/icons/tag_user.svg + SvgGenImage get tagUser => const SvgGenImage('assets/icons/tag_user.svg'); + + /// File path: assets/icons/trash.svg + SvgGenImage get trash => const SvgGenImage('assets/icons/trash.svg'); + + /// File path: assets/icons/user.svg + SvgGenImage get user => const SvgGenImage('assets/icons/user.svg'); + + /// File path: assets/icons/user_square.svg + SvgGenImage get userSquare => const SvgGenImage('assets/icons/user_square.svg'); + + /// List of all assets + List get values => [ + add, + arrowLeft, + arrowRight, + bgHeaderUserProfile, + calendar, + calendarSearch, + call, + diagram, + download, + edit, + excelDownload, + filter, + gps, + information, + inspection, + key, + liveStock, + logout, + map, + mapMarker, + messageAdd, + pdfDownload, + pictureFrame, + profileCircle, + profileUser, + receiptDiscount, + scan, + scanBarcode, + securityTime, + setting, + tagUser, + trash, + user, + userSquare, + ]; +} + +class $AssetsImagesGen { + const $AssetsImagesGen(); + + /// File path: assets/images/inner_splash.webp + AssetGenImage get innerSplash => const AssetGenImage('assets/images/inner_splash.webp'); + + /// File path: assets/images/outter_splash.webp + AssetGenImage get outterSplash => const AssetGenImage('assets/images/outter_splash.webp'); + + /// List of all assets + List get values => [innerSplash, outterSplash]; +} + +class $AssetsVecGen { + const $AssetsVecGen(); + + /// File path: assets/vec/add.svg.vec + SvgGenImage get addSvg => const SvgGenImage.vec('assets/vec/add.svg.vec'); + + /// File path: assets/vec/arrow_left.svg.vec + SvgGenImage get arrowLeftSvg => const SvgGenImage.vec('assets/vec/arrow_left.svg.vec'); + + /// File path: assets/vec/arrow_right.svg.vec + SvgGenImage get arrowRightSvg => const SvgGenImage.vec('assets/vec/arrow_right.svg.vec'); + + /// File path: assets/vec/bg_header_user_profile.svg.vec + SvgGenImage get bgHeaderUserProfileSvg => const SvgGenImage.vec('assets/vec/bg_header_user_profile.svg.vec'); + + /// File path: assets/vec/calendar.svg.vec + SvgGenImage get calendarSvg => const SvgGenImage.vec('assets/vec/calendar.svg.vec'); + + /// File path: assets/vec/calendar_search.svg.vec + SvgGenImage get calendarSearchSvg => const SvgGenImage.vec('assets/vec/calendar_search.svg.vec'); + + /// File path: assets/vec/call.svg.vec + SvgGenImage get callSvg => const SvgGenImage.vec('assets/vec/call.svg.vec'); + + /// File path: assets/vec/diagram.svg.vec + SvgGenImage get diagramSvg => const SvgGenImage.vec('assets/vec/diagram.svg.vec'); + + /// File path: assets/vec/download.svg.vec + SvgGenImage get downloadSvg => const SvgGenImage.vec('assets/vec/download.svg.vec'); + + /// File path: assets/vec/edit.svg.vec + SvgGenImage get editSvg => const SvgGenImage.vec('assets/vec/edit.svg.vec'); + + /// File path: assets/vec/excel_download.svg.vec + SvgGenImage get excelDownloadSvg => const SvgGenImage.vec('assets/vec/excel_download.svg.vec'); + + /// File path: assets/vec/filter.svg.vec + SvgGenImage get filterSvg => const SvgGenImage.vec('assets/vec/filter.svg.vec'); + + /// File path: assets/vec/gps.svg.vec + SvgGenImage get gpsSvg => const SvgGenImage.vec('assets/vec/gps.svg.vec'); + + /// File path: assets/vec/information.svg.vec + SvgGenImage get informationSvg => const SvgGenImage.vec('assets/vec/information.svg.vec'); + + /// File path: assets/vec/inspection.svg.vec + SvgGenImage get inspectionSvg => const SvgGenImage.vec('assets/vec/inspection.svg.vec'); + + /// File path: assets/vec/key.svg.vec + SvgGenImage get keySvg => const SvgGenImage.vec('assets/vec/key.svg.vec'); + + /// File path: assets/vec/liveStock.svg.vec + SvgGenImage get liveStockSvg => const SvgGenImage.vec('assets/vec/liveStock.svg.vec'); + + /// File path: assets/vec/logout.svg.vec + SvgGenImage get logoutSvg => const SvgGenImage.vec('assets/vec/logout.svg.vec'); + + /// File path: assets/vec/map.svg.vec + SvgGenImage get mapSvg => const SvgGenImage.vec('assets/vec/map.svg.vec'); + + /// File path: assets/vec/map_marker.svg.vec + SvgGenImage get mapMarkerSvg => const SvgGenImage.vec('assets/vec/map_marker.svg.vec'); + + /// File path: assets/vec/message_add.svg.vec + SvgGenImage get messageAddSvg => const SvgGenImage.vec('assets/vec/message_add.svg.vec'); + + /// File path: assets/vec/pdf_download.svg.vec + SvgGenImage get pdfDownloadSvg => const SvgGenImage.vec('assets/vec/pdf_download.svg.vec'); + + /// File path: assets/vec/picture_frame.svg.vec + SvgGenImage get pictureFrameSvg => const SvgGenImage.vec('assets/vec/picture_frame.svg.vec'); + + /// File path: assets/vec/profile_circle.svg.vec + SvgGenImage get profileCircleSvg => const SvgGenImage.vec('assets/vec/profile_circle.svg.vec'); + + /// File path: assets/vec/profile_user.svg.vec + SvgGenImage get profileUserSvg => const SvgGenImage.vec('assets/vec/profile_user.svg.vec'); + + /// File path: assets/vec/receipt_discount.svg.vec + SvgGenImage get receiptDiscountSvg => const SvgGenImage.vec('assets/vec/receipt_discount.svg.vec'); + + /// File path: assets/vec/scan.svg.vec + SvgGenImage get scanSvg => const SvgGenImage.vec('assets/vec/scan.svg.vec'); + + /// File path: assets/vec/scan_barcode.svg.vec + SvgGenImage get scanBarcodeSvg => const SvgGenImage.vec('assets/vec/scan_barcode.svg.vec'); + + /// File path: assets/vec/security_time.svg.vec + SvgGenImage get securityTimeSvg => const SvgGenImage.vec('assets/vec/security_time.svg.vec'); + + /// File path: assets/vec/setting.svg.vec + SvgGenImage get settingSvg => const SvgGenImage.vec('assets/vec/setting.svg.vec'); + + /// File path: assets/vec/tag_user.svg.vec + SvgGenImage get tagUserSvg => const SvgGenImage.vec('assets/vec/tag_user.svg.vec'); + + /// File path: assets/vec/trash.svg.vec + SvgGenImage get trashSvg => const SvgGenImage.vec('assets/vec/trash.svg.vec'); + + /// File path: assets/vec/user.svg.vec + SvgGenImage get userSvg => const SvgGenImage.vec('assets/vec/user.svg.vec'); + + /// File path: assets/vec/user_square.svg.vec + SvgGenImage get userSquareSvg => const SvgGenImage.vec('assets/vec/user_square.svg.vec'); + + /// List of all assets + List get values => [ + addSvg, + arrowLeftSvg, + arrowRightSvg, + bgHeaderUserProfileSvg, + calendarSvg, + calendarSearchSvg, + callSvg, + diagramSvg, + downloadSvg, + editSvg, + excelDownloadSvg, + filterSvg, + gpsSvg, + informationSvg, + inspectionSvg, + keySvg, + liveStockSvg, + logoutSvg, + mapSvg, + mapMarkerSvg, + messageAddSvg, + pdfDownloadSvg, + pictureFrameSvg, + profileCircleSvg, + profileUserSvg, + receiptDiscountSvg, + scanSvg, + scanBarcodeSvg, + securityTimeSvg, + settingSvg, + tagUserSvg, + trashSvg, + userSvg, + userSquareSvg, + ]; +} + +class Assets { + const Assets._(); + + static const $AssetsIconsGen icons = $AssetsIconsGen(); + static const $AssetsImagesGen images = $AssetsImagesGen(); + static const $AssetsVecGen vec = $AssetsVecGen(); +} + +class AssetGenImage { + const AssetGenImage(this._assetName, {this.size, this.flavors = const {}}); + + final String _assetName; + + final Size? size; + final Set flavors; + + Image image({ + Key? key, + AssetBundle? bundle, + ImageFrameBuilder? frameBuilder, + ImageErrorWidgetBuilder? errorBuilder, + String? semanticLabel, + bool excludeFromSemantics = false, + double? scale, + double? width, + double? height, + Color? color, + Animation? opacity, + BlendMode? colorBlendMode, + BoxFit? fit, + AlignmentGeometry alignment = Alignment.center, + ImageRepeat repeat = ImageRepeat.noRepeat, + Rect? centerSlice, + bool matchTextDirection = false, + bool gaplessPlayback = true, + bool isAntiAlias = false, + String? package, + FilterQuality filterQuality = FilterQuality.medium, + int? cacheWidth, + int? cacheHeight, + }) { + return Image.asset( + _assetName, + key: key, + bundle: bundle, + frameBuilder: frameBuilder, + errorBuilder: errorBuilder, + semanticLabel: semanticLabel, + excludeFromSemantics: excludeFromSemantics, + scale: scale, + width: width, + height: height, + color: color, + opacity: opacity, + colorBlendMode: colorBlendMode, + fit: fit, + alignment: alignment, + repeat: repeat, + centerSlice: centerSlice, + matchTextDirection: matchTextDirection, + gaplessPlayback: gaplessPlayback, + isAntiAlias: isAntiAlias, + package: package, + filterQuality: filterQuality, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + ); + } + + ImageProvider provider({AssetBundle? bundle, String? package}) { + return AssetImage(_assetName, bundle: bundle, package: package); + } + + String get path => _assetName; + + String get keyName => _assetName; +} + +class SvgGenImage { + const SvgGenImage(this._assetName, {this.size, this.flavors = const {}}) : _isVecFormat = false; + + const SvgGenImage.vec(this._assetName, {this.size, this.flavors = const {}}) : _isVecFormat = true; + + final String _assetName; + final Size? size; + final Set flavors; + final bool _isVecFormat; + + _svg.SvgPicture svg({ + Key? key, + bool matchTextDirection = false, + AssetBundle? bundle, + String? package, + double? width, + double? height, + BoxFit fit = BoxFit.contain, + AlignmentGeometry alignment = Alignment.center, + bool allowDrawingOutsideViewBox = false, + WidgetBuilder? placeholderBuilder, + String? semanticsLabel, + bool excludeFromSemantics = false, + _svg.SvgTheme? theme, + ColorFilter? colorFilter, + Clip clipBehavior = Clip.hardEdge, + @deprecated Color? color, + @deprecated BlendMode colorBlendMode = BlendMode.srcIn, + @deprecated bool cacheColorFilter = false, + }) { + final _svg.BytesLoader loader; + if (_isVecFormat) { + loader = _vg.AssetBytesLoader(_assetName, assetBundle: bundle, packageName: package); + } else { + loader = _svg.SvgAssetLoader(_assetName, assetBundle: bundle, packageName: package, theme: theme); + } + return _svg.SvgPicture( + loader, + key: key, + matchTextDirection: matchTextDirection, + width: width, + height: height, + fit: fit, + alignment: alignment, + allowDrawingOutsideViewBox: allowDrawingOutsideViewBox, + placeholderBuilder: placeholderBuilder, + semanticsLabel: semanticsLabel, + excludeFromSemantics: excludeFromSemantics, + colorFilter: colorFilter ?? (color == null ? null : ColorFilter.mode(color, colorBlendMode)), + clipBehavior: clipBehavior, + cacheColorFilter: cacheColorFilter, + ); + } + + String get path => _assetName; + + String get keyName => _assetName; +} diff --git a/packages/core/lib/presentation/common/common.dart b/packages/core/lib/presentation/common/common.dart index c3e9fa3..36e4588 100644 --- a/packages/core/lib/presentation/common/common.dart +++ b/packages/core/lib/presentation/common/common.dart @@ -1,3 +1,3 @@ export 'app_color.dart'; export 'app_fonts.dart'; -export 'assets.dart'; +export 'assets.gen.dart'; diff --git a/packages/core/lib/presentation/common/fonts.gen.dart b/packages/core/lib/presentation/common/fonts.gen.dart new file mode 100644 index 0000000..66ad118 --- /dev/null +++ b/packages/core/lib/presentation/common/fonts.gen.dart @@ -0,0 +1,15 @@ +/// GENERATED CODE - DO NOT MODIFY BY HAND +/// ***************************************************** +/// FlutterGen +/// ***************************************************** + +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: directives_ordering,unnecessary_import,implicit_dynamic_list_literal,deprecated_member_use + +class FontFamily { + FontFamily._(); + + /// Font family: yekan + static const String yekan = 'yekan'; +} diff --git a/packages/core/lib/presentation/widget/bottom_navigation/wave_bottom_navigation.dart b/packages/core/lib/presentation/widget/bottom_navigation/wave_bottom_navigation.dart index ddcc71f..f2b50b3 100644 --- a/packages/core/lib/presentation/widget/bottom_navigation/wave_bottom_navigation.dart +++ b/packages/core/lib/presentation/widget/bottom_navigation/wave_bottom_navigation.dart @@ -3,7 +3,7 @@ import 'package:rasadyar_core/core.dart'; class WaveBottomNavigationItem { final String title; - final String icon; + final Widget icon; WaveBottomNavigationItem({required this.title, required this.icon}); } @@ -112,12 +112,7 @@ class _WaveBottomNavigationState extends State { children: [ Tooltip( message: item.title, - child: vecWidget( - item.icon, - color: Colors.white, - width: 32, - height: 32, - ), + child: item.icon ), /* Visibility( diff --git a/packages/core/lib/presentation/widget/buttons/fab.dart b/packages/core/lib/presentation/widget/buttons/fab.dart index 3dfe651..200f0ab 100644 --- a/packages/core/lib/presentation/widget/buttons/fab.dart +++ b/packages/core/lib/presentation/widget/buttons/fab.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; -import 'package:rasadyar_core/presentation/common/assets.dart'; import 'package:rasadyar_core/presentation/utils/color_utils.dart'; -import 'package:rasadyar_core/presentation/widget/vec_widget.dart'; +import '../../common/assets.gen.dart'; class RFab extends StatefulWidget { final VoidCallback? onPressed; @@ -22,7 +21,10 @@ class RFab extends StatefulWidget { RFab.smallAdd({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecAddSvg), + icon: Assets.vec.addSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.greenNormal, key: key, ); @@ -30,7 +32,10 @@ class RFab extends StatefulWidget { RFab.add({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecAddSvg), + icon: Assets.vec.addSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.greenNormal, key: key, ); @@ -41,7 +46,10 @@ class RFab extends StatefulWidget { RFab.smallEdit({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecEditSvg), + icon: Assets.vec.addSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -49,7 +57,10 @@ class RFab extends StatefulWidget { RFab.edit({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecEditSvg), + icon: Assets.vec.addSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -60,7 +71,10 @@ class RFab extends StatefulWidget { RFab.smallDelete({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecTrashSvg), + icon: Assets.vec.trashSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.redNormal, key: key, ); @@ -68,7 +82,10 @@ class RFab extends StatefulWidget { RFab.delete({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecTrashSvg), + icon: Assets.vec.trashSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.redNormal, key: key, ); @@ -79,7 +96,10 @@ class RFab extends StatefulWidget { RFab.smallAction({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecScanSvg), + icon: Assets.vec.scanSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -87,7 +107,10 @@ class RFab extends StatefulWidget { RFab.action({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecScanSvg), + icon: Assets.vec.scanSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -98,7 +121,10 @@ class RFab extends StatefulWidget { RFab.smallFilter({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecFilterSvg), + icon: Assets.vec.scanSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -106,7 +132,10 @@ class RFab extends StatefulWidget { RFab.filter({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecFilterSvg), + icon: Assets.vec.scanSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -117,7 +146,10 @@ class RFab extends StatefulWidget { RFab.smallDownload({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecDownloadSvg), + icon: Assets.vec.downloadSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -125,7 +157,10 @@ class RFab extends StatefulWidget { RFab.download({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecDownloadSvg), + icon: Assets.vec.downloadSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -136,7 +171,10 @@ class RFab extends StatefulWidget { RFab.smallExcel({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecDownloadSvg), + icon: Assets.vec.excelDownloadSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.greenDark, key: key, ); @@ -144,7 +182,10 @@ class RFab extends StatefulWidget { RFab.excel({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecDownloadSvg), + icon: Assets.vec.excelDownloadSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.greenDark, key: key, ); @@ -155,7 +196,10 @@ class RFab extends StatefulWidget { RFab.smallBack({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: vecWidget(Assets.vecArrowLeftSvg), + icon: Assets.vec.arrowLeftSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); @@ -163,7 +207,10 @@ class RFab extends StatefulWidget { RFab.back({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecArrowLeftSvg), + icon: Assets.vec.arrowLeftSvg.svg( + width: 20, + height: 20, + ), backgroundColor: AppColor.blueNormal, key: key, ); diff --git a/packages/core/lib/presentation/widget/buttons/fab_outlined.dart b/packages/core/lib/presentation/widget/buttons/fab_outlined.dart index fc9f209..2b408bd 100644 --- a/packages/core/lib/presentation/widget/buttons/fab_outlined.dart +++ b/packages/core/lib/presentation/widget/buttons/fab_outlined.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; -import 'package:rasadyar_core/presentation/common/assets.dart'; +import 'package:rasadyar_core/presentation/common/assets.gen.dart'; import 'package:rasadyar_core/presentation/utils/color_utils.dart'; -import 'package:rasadyar_core/presentation/widget/vec_widget.dart'; class RFabOutlined extends StatefulWidget { final Widget icon; @@ -69,10 +68,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.greenNormal, borderColor: AppColor.greenNormal, - icon: vecWidget2( - Assets.vecAddSvg, - - color: AppColor.greenNormal, + icon: Assets.vec.addSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -81,12 +83,14 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.greenNormal, - icon: vecWidget( - Assets.vecAddSvg, - color: - onPressed != null - ? AppColor.greenNormal - : AppColor.greenNormal.disabledColor, + + icon: Assets.vec.addSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -96,12 +100,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.greenNormal, borderColor: AppColor.greenNormal, - icon: vecWidget( - Assets.vecAddSvg, - color: - onPressed != null - ? AppColor.greenNormal - : AppColor.greenNormal.disabledColor, + icon: Assets.vec.addSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -110,12 +115,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.greenNormal, - icon: vecWidget( - Assets.vecAddSvg, - color: - onPressed != null - ? AppColor.greenNormal - : AppColor.greenNormal.disabledColor, + icon: Assets.vec.addSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -128,12 +134,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecEditSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.editSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -142,12 +149,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecEditSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.editSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -157,12 +165,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecEditSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.editSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -171,12 +180,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecEditSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.editSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -189,12 +199,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.redNormal, borderColor: AppColor.redNormal, - icon: vecWidget( - Assets.vecTrashSvg, - color: - onPressed != null - ? AppColor.redNormal - : AppColor.redNormal.disabledColor, + icon: Assets.vec.trashSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -203,12 +214,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.redNormal, - icon: vecWidget( - Assets.vecTrashSvg, - color: - onPressed != null - ? AppColor.redNormal - : AppColor.redNormal.disabledColor, + icon: Assets.vec.trashSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -218,12 +230,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.redNormal, borderColor: AppColor.redNormal, - icon: vecWidget( - Assets.vecTrashSvg, - color: - onPressed != null - ? AppColor.redNormal - : AppColor.redNormal.disabledColor, + icon: Assets.vec.trashSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -232,12 +245,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.redNormal, - icon: vecWidget( - Assets.vecTrashSvg, - color: - onPressed != null - ? AppColor.redNormal - : AppColor.redNormal.disabledColor, + icon: Assets.vec.trashSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.redNormal + : AppColor.redNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -250,12 +264,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecScanSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.scanSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -264,12 +279,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecScanSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.scanSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -279,12 +295,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecScanSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.scanSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -293,12 +310,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecScanSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.scanSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -311,12 +329,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecFilterSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.filterSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -325,12 +344,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecFilterSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.filterSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -340,12 +360,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecFilterSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.filterSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -354,12 +375,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecFilterSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.filterSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -372,12 +394,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.downloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -386,12 +409,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.downloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -401,12 +425,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.downloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -415,12 +440,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.downloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -433,12 +459,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.greenDark, borderColor: AppColor.greenDark, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.excelDownloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -447,12 +474,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.greenDark, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.excelDownloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -462,12 +490,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.greenDark, borderColor: AppColor.greenDark, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.excelDownloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -476,12 +505,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.greenDark, - icon: vecWidget( - Assets.vecDownloadSvg, - color: - onPressed != null - ? AppColor.greenDark - : AppColor.greenDark.disabledColor, + icon: Assets.vec.excelDownloadSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.greenNormal + : AppColor.greenNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -494,12 +524,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecArrowLeftSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.arrowLeftSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -508,12 +539,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecArrowLeftSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.arrowLeftSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -523,12 +555,13 @@ class RFabOutlined extends StatefulWidget { onPressed: onPressed, backgroundColor: AppColor.blueNormal, borderColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecArrowLeftSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.arrowLeftSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -537,12 +570,13 @@ class RFabOutlined extends StatefulWidget { key: key, onPressed: onPressed, backgroundColor: AppColor.blueNormal, - icon: vecWidget( - Assets.vecArrowLeftSvg, - color: - onPressed != null - ? AppColor.blueNormal - : AppColor.blueNormal.disabledColor, + icon: Assets.vec.arrowLeftSvg.svg( + colorFilter: ColorFilter.mode( + onPressed != null + ? AppColor.blueNormal + : AppColor.blueNormal.disabledColor, + BlendMode.srcIn, + ), ), ); @@ -550,11 +584,12 @@ class RFabOutlined extends StatefulWidget { } class _RFabOutlinedState extends State { - bool isOnPressed =false; + bool isOnPressed = false; + @override Widget build(BuildContext context) { return OutlinedButton( - onPressed:widget.onPressed , + onPressed: widget.onPressed, style: ButtonStyle( side: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.disabled)) { @@ -598,8 +633,7 @@ class _RFabOutlinedState extends State { ), padding: WidgetStatePropertyAll(EdgeInsets.zero), ), - child: widget.icon + child: widget.icon, ); } } - 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 new file mode 100644 index 0000000..510f146 --- /dev/null +++ b/packages/core/lib/presentation/widget/card/card_with_icon_with_border.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class CardIcon extends StatelessWidget { + const CardIcon({ + super.key, + required this.title, + required this.icon, + this.onTap, + }); + + final String title; + final String icon; + final VoidCallback? onTap; + + @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(16), + 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), + ), + ], + ), + ), + ), + ); + } +} diff --git a/packages/core/lib/presentation/widget/vec_widget.dart b/packages/core/lib/presentation/widget/vec_widget.dart index 4bf8b36..12bcda6 100644 --- a/packages/core/lib/presentation/widget/vec_widget.dart +++ b/packages/core/lib/presentation/widget/vec_widget.dart @@ -22,7 +22,7 @@ SvgPicture vecWidget( } Widget vecWidgetWithOnTap({ - required String assets, + required Widget child, required VoidCallback onTap, double? width, double? height, @@ -31,14 +31,7 @@ Widget vecWidgetWithOnTap({ }) { return InkWell( onTap: onTap, - child: SvgPicture( - AssetBytesLoader(assets), - width: width, - height: height, - fit: fit ?? BoxFit.contain, - colorFilter: - color != null ? ColorFilter.mode(color, BlendMode.srcIn) : null, - ), + child: child ); } diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 7175a76..0f3dc7b 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -14,3 +14,4 @@ export 'pagination/show_more.dart'; export 'tabs/new_tab.dart'; export 'tabs/tab.dart'; export 'vec_widget.dart'; +export 'card/card_with_icon_with_border.dart'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index 467a430..553ad9b 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.4.4" + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" args: dependency: transitive description: @@ -153,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" convert: dependency: transitive description: @@ -262,6 +278,22 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "3eaa2d3d8be58267ac4cd5e215ac965dd23cae0410dc073de2e82e227be32bfc" + url: "https://pub.dev" + source: hosted + version: "5.10.0" + flutter_gen_runner: + dependency: "direct main" + description: + name: flutter_gen_runner + sha256: e74b4ead01df3e8f02e73a26ca856759dbbe8cb3fd60941ba9f4005cd0cd19c9 + url: "https://pub.dev" + source: hosted + version: "5.10.0" flutter_lints: dependency: "direct dev" description: @@ -493,6 +525,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + hashcodes: + dependency: transitive + description: + name: hashcodes + sha256: "80f9410a5b3c8e110c4b7604546034749259f5d6dcca63e0d3c17c9258f1a651" + url: "https://pub.dev" + source: hosted + version: "2.0.0" hive_ce: dependency: "direct main" description: @@ -541,6 +581,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image_size_getter: + dependency: transitive + description: + name: image_size_getter + sha256: "9a299e3af2ebbcfd1baf21456c3c884037ff524316c97d8e56035ea8fdf35653" + url: "https://pub.dev" + source: hosted + version: "2.4.0" intl: dependency: "direct main" description: @@ -885,6 +933,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + posix: + dependency: transitive + description: + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" + source: hosted + version: "6.0.2" pretty_dio_logger: dependency: "direct main" description: diff --git a/packages/core/pubspec.yaml b/packages/core/pubspec.yaml index 1c25b27..a587f74 100644 --- a/packages/core/pubspec.yaml +++ b/packages/core/pubspec.yaml @@ -36,6 +36,9 @@ dependencies: flutter_svg: ^2.0.17 font_awesome_flutter: ^10.8.0 + #Generator + flutter_gen_runner: ^5.10.0 + ##state manger get: ^4.7.2 @@ -76,6 +79,7 @@ dev_dependencies: freezed: ^3.0.3 json_serializable: ^6.9.4 + ##test mocktail: ^1.0.4 get_test: ^4.0.1 @@ -85,3 +89,9 @@ dev_dependencies: flutter: uses-material-design: true + assets: + - assets/ + - assets/vec/ + - assets/icons/ + + diff --git a/packages/inspection/lib/presentation/action/view.dart b/packages/inspection/lib/presentation/action/view.dart index 1889549..a0d2ac5 100644 --- a/packages/inspection/lib/presentation/action/view.dart +++ b/packages/inspection/lib/presentation/action/view.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/presentation/widget/buttons/elevated.dart'; import 'logic.dart'; @@ -113,7 +112,7 @@ class ActionPage extends GetView { children: [ Container( height: 32, - margin: EdgeInsets.symmetric(horizontal: 22,vertical: 10), + margin: EdgeInsets.symmetric(horizontal: 22, vertical: 10), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, @@ -161,13 +160,13 @@ class ActionPage extends GetView { mainAxisAlignment: MainAxisAlignment.end, children: [ vecWidgetWithOnTap( - assets: Assets.vecPdfDownloadSvg, + child: Assets.vec.pdfDownloadSvg.svg(), onTap: () {}, width: 64, height: 64, ), vecWidgetWithOnTap( - assets: Assets.vecExcelDownloadSvg, + child: Assets.vec.excelDownloadSvg.svg(), onTap: () {}, width: 64, height: 64, @@ -220,7 +219,7 @@ class ActionPage extends GetView { } Widget headerWidget({ - required String icon, + required Widget icon, required String title, required VoidCallback onTap, bool isSelected = false, @@ -240,12 +239,7 @@ class ActionPage extends GetView { borderRadius: BorderRadius.circular(8), ), ), - child: vecWidget( - icon, - width: 40, - height: 40, - color: AppColor.blueNormal, - ), + child: icon, ), Text( title, @@ -279,7 +273,10 @@ class ActionPage extends GetView { padding: EdgeInsets.all(16), borderRadius: BorderRadius.circular(8), autoClose: true, - child: vecWidget(Assets.vecTrashSvg, width: 24, height: 24), + child: Assets.vec.trashSvg.svg( + width: 24, + height: 24, + ), ), ], ), @@ -372,7 +369,10 @@ class ActionPage extends GetView { bottomRight: Radius.circular(8), ), autoClose: true, - child: vecWidget(Assets.vecEditSvg, width: 24, height: 24), + child: Assets.vec.trashSvg.svg( + width: 24, + height: 24, + ), ), CustomSlidableAction( onPressed: (context) {}, @@ -384,7 +384,10 @@ class ActionPage extends GetView { bottomLeft: Radius.circular(8), ), autoClose: true, - child: vecWidget(Assets.vecTrashSvg, width: 24, height: 24), + child: Assets.vec.trashSvg.svg( + width: 24, + height: 24, + ), ), ], ), @@ -492,7 +495,7 @@ class ActionPage extends GetView { spacing: 12, children: [ vecWidgetWithOnTap( - assets: Assets.vecEditSvg, + child: Assets.vec.editSvg.svg(), onTap: () {}, width: 24, height: 24, @@ -506,7 +509,7 @@ class ActionPage extends GetView { ), ), vecWidgetWithOnTap( - assets: Assets.vecTrashSvg, + child: Assets.vec.trashSvg.svg(), width: 24, height: 24, color: AppColor.redNormal, @@ -649,7 +652,7 @@ class ActionPage extends GetView { children: [ Row(), Padding( - padding: const EdgeInsets.symmetric(horizontal: 22,vertical: 10), + padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 10), child: Text( title, textAlign: TextAlign.center, diff --git a/packages/inspection/lib/presentation/add_mobile_inspector/view.dart b/packages/inspection/lib/presentation/add_mobile_inspector/view.dart index 61a9aba..c39030c 100644 --- a/packages/inspection/lib/presentation/add_mobile_inspector/view.dart +++ b/packages/inspection/lib/presentation/add_mobile_inspector/view.dart @@ -14,11 +14,13 @@ class AddMobileInspectorPage extends GetView { backgroundColor: AppColor.bgLight, appBar: RAppBar( title: 'افزودن بازرس همراه', - leading: vecWidget( - Assets.vecMessageAddSvg, - color: Colors.white, + leading: Assets.vec.messageAddSvg.svg( width: 16, height: 16, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), ), additionalActions: [ RFab.smallAdd(onPressed: () => controller.countInspector.value++), diff --git a/packages/inspection/lib/presentation/add_supervision/view.dart b/packages/inspection/lib/presentation/add_supervision/view.dart index 46738a1..89fa9bd 100644 --- a/packages/inspection/lib/presentation/add_supervision/view.dart +++ b/packages/inspection/lib/presentation/add_supervision/view.dart @@ -13,11 +13,13 @@ class AddSupervisionPage extends GetView { backgroundColor: AppColor.lightGreyLight, appBar: RAppBar( title: 'ایجاد بازرسی', - leading: vecWidget( - Assets.vecMessageAddSvg, - color: Colors.white, + leading: Assets.vec.messageAddSvg.svg( width: 16, height: 16, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), ), ), body: Column( diff --git a/packages/inspection/lib/presentation/display_information/view.dart b/packages/inspection/lib/presentation/display_information/view.dart index 3adbe1f..33f879a 100644 --- a/packages/inspection/lib/presentation/display_information/view.dart +++ b/packages/inspection/lib/presentation/display_information/view.dart @@ -12,11 +12,13 @@ class DisplayInformationPage extends GetView { backgroundColor: AppColor.bgLight, appBar: RAppBar( title: 'نمایش اطلاعات', - leading: vecWidget( - Assets.vecMessageAddSvg, - color: AppColor.blueNormal, + leading: Assets.vec.messageAddSvg.svg( width: 16, height: 16, + colorFilter: ColorFilter.mode( + AppColor.blueNormal, + BlendMode.srcIn, + ), ), ), diff --git a/packages/inspection/lib/presentation/filter/view.dart b/packages/inspection/lib/presentation/filter/view.dart index c8b2271..3f7ee39 100644 --- a/packages/inspection/lib/presentation/filter/view.dart +++ b/packages/inspection/lib/presentation/filter/view.dart @@ -74,7 +74,7 @@ class SupervisionFilterPage extends GetView { return RFab.small( backgroundColor: AppColor.greenNormal, isLoading: data.value, - icon: vecWidget(Assets.vecGpsSvg), + icon: Assets.vec.gpsSvg.svg(), onPressed: () async { controller.isLoading.value = true; await controller.determineCurrentPosition(); @@ -91,7 +91,7 @@ class SupervisionFilterPage extends GetView { bottom: 30, child: RFab.small( backgroundColor: AppColor.blueNormal, - icon: vecWidget(Assets.vecFilterSvg, width: 24, height: 24), + icon: Assets.vec.filterSvg.svg(width: 24,height: 24), onPressed: () => controller.filterBottomSheetController.toggle(), ), ); @@ -107,7 +107,10 @@ Marker markerWidget({required LatLng marker, required VoidCallback onTap}) { child: SizedBox( width: 36, height: 36, - child: vecWidget(Assets.vecMapMarkerSvg,width: 30,height: 30,), + child:Assets.vec.mapMarkerSvg.svg( + width: 30, + height: 30, + ) ), ), ); @@ -318,7 +321,7 @@ Widget markerDetailsWidget() { ), Spacer(), vecWidgetWithOnTap( - assets: Assets.vecMapSvg, + child: Assets.vec.mapSvg.svg(), onTap: () { Get.toNamed(InspectionRoutes.inspectionLocationDetails); }, @@ -327,7 +330,7 @@ Widget markerDetailsWidget() { color: AppColor.blueNormal, ), vecWidgetWithOnTap( - assets: Assets.vecMessageAddSvg, + child: Assets.vec.messageAddSvg.svg(), width: 24, height: 24, color: AppColor.greenNormal, @@ -337,7 +340,7 @@ Widget markerDetailsWidget() { ), vecWidgetWithOnTap( - assets: Assets.vecSecurityTimeSvg, + child: Assets.vec.securityTimeSvg.svg(), color: AppColor.warning, height: 24, width: 24, @@ -531,7 +534,7 @@ Widget selectedLocationWidget({ bottomRight: Radius.circular(8), topRight: Radius.circular(8), ), - child: vecWidget(Assets.vecMapSvg, width: 24, height: 24), + child: Assets.vec.mapSvg.svg( width: 24, height: 24), ), CustomSlidableAction( onPressed: (context) { @@ -539,7 +542,7 @@ Widget selectedLocationWidget({ }, backgroundColor: AppColor.greenNormal, padding: EdgeInsets.all(16), - child: vecWidget(Assets.vecMessageAddSvg), + child: Assets.vec.messageAddSvg.svg(), ), CustomSlidableAction( onPressed: (context) {}, @@ -549,8 +552,8 @@ Widget selectedLocationWidget({ bottomLeft: Radius.circular(8), topLeft: Radius.circular(8), ), - child: vecWidget(Assets.vecSecurityTimeSvg), - ), + child: Assets.vec.securityTimeSvg.svg()), + ], ), child: GestureDetector( @@ -598,7 +601,7 @@ Widget selectedLocationWidget({ ), ], ), - vecWidget(Assets.vecScanBarcodeSvg), + Assets.vec.scanBarcodeSvg.svg(), ], ), ), diff --git a/packages/inspection/lib/presentation/profile/view.dart b/packages/inspection/lib/presentation/profile/view.dart index c6a321b..b125f1a 100644 --- a/packages/inspection/lib/presentation/profile/view.dart +++ b/packages/inspection/lib/presentation/profile/view.dart @@ -18,8 +18,7 @@ class ProfilePage extends GetView { alignment: Alignment.center, clipBehavior: Clip.none, children: [ - vecWidget(Assets.vecBgHeaderUserProfileSvg, fit: BoxFit.cover), - + Assets.vec.bgHeaderUserProfileSvg.svg(), Positioned( bottom: -20, left: 0, @@ -105,7 +104,7 @@ class ProfilePage extends GetView { onPressed: () { data.value = 0; }, - icon: Assets.vecProfileUserSvg, + icon: Assets.vec.profileUserSvg.path, selected: data.value == 0, ), cardActionWidget( @@ -113,7 +112,7 @@ class ProfilePage extends GetView { onPressed: () { data.value = 1; }, - icon: Assets.vecInformationSvg, + icon: Assets.vec.informationSvg.path, selected: data.value == 1, ), cardActionWidget( @@ -121,7 +120,7 @@ class ProfilePage extends GetView { onPressed: () { data.value = 2; }, - icon: Assets.vecReceiptDiscountSvg, + icon: Assets.vec.receiptDiscountSvg.path, selected: data.value == 2, ), ], @@ -129,9 +128,7 @@ class ProfilePage extends GetView { ); }, controller.selectedInformationType), - SizedBox( - height: 100, - ) + SizedBox(height: 100), ], ), ), @@ -159,34 +156,38 @@ class ProfilePage extends GetView { itemList( title: 'نام و نام خانوادگی', content: 'آیدا گل محمدی', - icon: Assets.vecUserSvg, + icon: Assets.vec.userSvg.path, ), itemList( title: 'موبایل', content: '09302654896', - icon: Assets.vecCallSvg, + icon: Assets.vec.callSvg.path, ), itemList( title: 'کدملی', content: 'نا مشخص', - icon: Assets.vecTagUserSvg, + icon: Assets.vec.tagUserSvg.path, ), itemList( title: 'شماره شناسنامه', content: 'نا مشخص', - icon: Assets.vecUserSquareSvg, + icon: Assets.vec.userSquareSvg.path, ), itemList( title: 'تاریخ تولد', content: '1404/10/12', - icon: Assets.vecCalendarSvg, + icon: Assets.vec.calendarSvg.path, ), itemList( title: 'استان', content: 'لرستان', - icon: Assets.vecPictureFrameSvg, + icon: Assets.vec.pictureFrameSvg.path, + ), + itemList( + title: 'شهر', + content: 'خرم آباد', + icon: Assets.vec.mapSvg.path, ), - itemList(title: 'شهر', content: 'خرم آباد', icon: Assets.vecMapSvg), ], ); } @@ -201,11 +202,10 @@ class ProfilePage extends GetView { if (icon != null) Padding( padding: const EdgeInsets.only(left: 8.0), - child: vecWidget( - icon, + child: SvgGenImage.vec(icon).svg( width: 20, height: 20, - color: AppColor.blueNormal, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), ), ), Text(title, style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal)), @@ -238,11 +238,13 @@ class ProfilePage extends GetView { borderRadius: BorderRadius.circular(8), ), ), - child: vecWidget( - icon, + child: SvgGenImage.vec(icon).svg( width: 40, height: 40, - color: selected ? AppColor.blueNormalActive : AppColor.blueNormal, + colorFilter: ColorFilter.mode( + selected ? AppColor.whiteLight : AppColor.blueNormal, + BlendMode.srcIn, + ), ), ), SizedBox(height: 2), diff --git a/packages/inspection/lib/presentation/registration_of_violation/view.dart b/packages/inspection/lib/presentation/registration_of_violation/view.dart index 9e75e0a..2efa87f 100644 --- a/packages/inspection/lib/presentation/registration_of_violation/view.dart +++ b/packages/inspection/lib/presentation/registration_of_violation/view.dart @@ -15,11 +15,13 @@ class RegistrationOfViolationPage backgroundColor: AppColor.bgLight, appBar: RAppBar( title: 'ثبت تخلف', - leading: vecWidget( - Assets.vecMessageAddSvg, - color: Colors.white, + leading: Assets.vec.messageAddSvg.svg( width: 16, height: 16, + colorFilter: ColorFilter.mode( + Colors.white, + BlendMode.srcIn, + ), ), additionalActions: [ RFab.smallAdd(onPressed: () => controller.countViolation.value++), diff --git a/packages/inspection/lib/presentation/root/view.dart b/packages/inspection/lib/presentation/root/view.dart index 8b7faea..2994617 100644 --- a/packages/inspection/lib/presentation/root/view.dart +++ b/packages/inspection/lib/presentation/root/view.dart @@ -116,30 +116,54 @@ class RootPage extends GetView { ), bottomNavigationBar: WaveBottomNavigation( items: [ - WaveBottomNavigationItem(title: 'خانه', icon: Assets.vecMapSvg), + WaveBottomNavigationItem(title: 'خانه', icon: Assets.vec.mapSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + )), WaveBottomNavigationItem( title: 'عملیات', - icon: Assets.vecUserSvg, + icon: Assets.vec.userSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), ), WaveBottomNavigationItem( title: 'افزودن', - icon: Assets.vecAddSvg, + icon: Assets.vec.addSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), ), WaveBottomNavigationItem( title: 'آمار', - icon: Assets.vecDiagramSvg, + icon: Assets.vec.diagramSvg.svg(width: 32,height: 32,colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn),), ), WaveBottomNavigationItem( title: 'تماس', - icon: Assets.vecCallSvg, + icon: Assets.vec.callSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), ), WaveBottomNavigationItem( title: 'مکان ', - icon: Assets.vecGpsSvg, + icon: Assets.vec.gpsSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), ), WaveBottomNavigationItem( title: 'تاریخ', - icon: Assets.vecCalendarSvg, + icon: Assets.vec.calendarSvg.svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), ), ], onPageChanged: (index) { diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart new file mode 100644 index 0000000..e335077 --- /dev/null +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -0,0 +1,17 @@ + + +import 'package:rasadyar_core/core.dart'; + +class RootLogic extends GetxController { + @override + void onReady() { + // TODO: implement onReady + super.onReady(); + } + + @override + void onClose() { + // TODO: implement onClose + super.onClose(); + } +} diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart new file mode 100644 index 0000000..4725935 --- /dev/null +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'logic.dart'; + +class RootPage extends GetView { + const RootPage({super.key}); + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/pubspec.lock b/pubspec.lock index 82b7839..14ce169 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.4.5" + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" args: dependency: transitive description: @@ -153,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + color: + dependency: transitive + description: + name: color + sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb + url: "https://pub.dev" + source: hosted + version: "3.0.0" convert: dependency: transitive description: @@ -262,6 +278,22 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_gen_core: + dependency: transitive + description: + name: flutter_gen_core + sha256: "3eaa2d3d8be58267ac4cd5e215ac965dd23cae0410dc073de2e82e227be32bfc" + url: "https://pub.dev" + source: hosted + version: "5.10.0" + flutter_gen_runner: + dependency: "direct dev" + description: + name: flutter_gen_runner + sha256: e74b4ead01df3e8f02e73a26ca856759dbbe8cb3fd60941ba9f4005cd0cd19c9 + url: "https://pub.dev" + source: hosted + version: "5.10.0" flutter_lints: dependency: "direct dev" description: @@ -493,6 +525,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + hashcodes: + dependency: transitive + description: + name: hashcodes + sha256: "80f9410a5b3c8e110c4b7604546034749259f5d6dcca63e0d3c17c9258f1a651" + url: "https://pub.dev" + source: hosted + version: "2.0.0" hive_ce: dependency: transitive description: @@ -541,6 +581,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image_size_getter: + dependency: transitive + description: + name: image_size_getter + sha256: "9a299e3af2ebbcfd1baf21456c3c884037ff524316c97d8e56035ea8fdf35653" + url: "https://pub.dev" + source: hosted + version: "2.4.0" intl: dependency: transitive description: @@ -885,6 +933,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + posix: + dependency: transitive + description: + name: posix + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 + url: "https://pub.dev" + source: hosted + version: "6.0.2" pretty_dio_logger: dependency: transitive description: @@ -938,6 +994,13 @@ packages: relative: true source: path version: "1.0.1" + rasadyar_livestock: + dependency: "direct main" + description: + path: "packages/livestock" + relative: true + source: path + version: "1.0.0" rxdart: dependency: transitive description: From 7f72f2c70d3479aa88ca68ea47d62ba475020937 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 19 May 2025 16:17:01 +0330 Subject: [PATCH 05/25] feat : live stock module --- .../lib/presentation/action/logic.dart | 16 ++++++------ .../lib/presentation/routes/app_pages.dart | 25 +++++++++++++++++++ .../lib/presentation/routes/app_routes.dart | 9 +++++++ packages/livestock/pubspec.yaml | 10 ++++---- packages/livestock/test/livestock_test.dart | 3 +-- pubspec.yaml | 16 ++++++++++++ 6 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 packages/livestock/lib/presentation/routes/app_pages.dart create mode 100644 packages/livestock/lib/presentation/routes/app_routes.dart diff --git a/packages/inspection/lib/presentation/action/logic.dart b/packages/inspection/lib/presentation/action/logic.dart index 14cf098..6692de2 100644 --- a/packages/inspection/lib/presentation/action/logic.dart +++ b/packages/inspection/lib/presentation/action/logic.dart @@ -1,6 +1,6 @@ +import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; - class ActionLogic extends GetxController with GetTickerProviderStateMixin { late Rx slidController; bool showSlideHint = true; @@ -15,11 +15,11 @@ class ActionLogic extends GetxController with GetTickerProviderStateMixin { 'خروج از سامانه', ]; - List headersIcons = [ - Assets.vecProfileUserSvg, - Assets.vecCalendarSearchSvg, - Assets.vecDiagramSvg, - Assets.vecLogoutSvg, + List headersIcons = [ + Assets.vec.profileUserSvg.svg(), + Assets.vec.calendarSearchSvg.svg(), + Assets.vec.diagramSvg.svg(), + Assets.vec.logoutSvg.svg(), ]; RxList supervisionHistoryList = [false, false, false, false].obs; @@ -46,7 +46,6 @@ class ActionLogic extends GetxController with GetTickerProviderStateMixin { void onInit() { super.onInit(); slidController = SlidableController(this).obs; - } @override @@ -69,9 +68,8 @@ class ActionLogic extends GetxController with GetTickerProviderStateMixin { showSlideHint = !showSlideHint; } - void updateSelectedIndex(int index) { - if(index == selectedIndex.value) { + if (index == selectedIndex.value) { return; } previousIndex.value = selectedIndex.value; diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart new file mode 100644 index 0000000..c699577 --- /dev/null +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -0,0 +1,25 @@ + +import 'package:rasadyar_auth/auth.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/root/view.dart'; + + +part'app_routes.dart'; + +sealed class LiveStockPages { + LiveStockPages._(); + + static final pages = [ + GetPage( + name: LiveStockRoutes.init, + page: () => RootPage(), + middlewares: [AuthMiddleware()], + binding: BindingsBuilder(() { + + }), + ), + + + ]; +} + diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart new file mode 100644 index 0000000..b563e83 --- /dev/null +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -0,0 +1,9 @@ + +part of 'app_pages.dart'; + +sealed class LiveStockRoutes { + LiveStockRoutes._(); + + static const init = '/liveStockRoutesInit'; + +} diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml index 09d7557..9f8ba58 100644 --- a/packages/livestock/pubspec.yaml +++ b/packages/livestock/pubspec.yaml @@ -1,4 +1,4 @@ -name: livestock +name: rasadyar_livestock description: A starting point for Dart libraries or applications. version: 1.0.0 publish_to: 'none' @@ -9,9 +9,12 @@ environment: dependencies: - + flutter: + sdk: flutter rasadyar_core: path: ../core + rasadyar_auth: + path: ../auth ##code generation freezed_annotation: ^3.0.0 json_annotation: ^4.9.0 @@ -31,7 +34,4 @@ dev_dependencies: mocktail: ^1.0.4 get_test: ^4.0.1 -flutter: - uses-material-design: true - diff --git a/packages/livestock/test/livestock_test.dart b/packages/livestock/test/livestock_test.dart index dbd1d90..534cb37 100644 --- a/packages/livestock/test/livestock_test.dart +++ b/packages/livestock/test/livestock_test.dart @@ -1,5 +1,4 @@ -import 'package:livestock/livestock.dart'; -import 'package:test/test.dart'; + void main() { diff --git a/pubspec.yaml b/pubspec.yaml index 95fc0f1..b8726e5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,6 +24,9 @@ dependencies: rasadyar_auth: path: ./packages/auth + rasadyar_livestock: + path: ./packages/livestock + ##code generation @@ -38,6 +41,7 @@ dev_dependencies: hive_ce_generator: ^1.9.1 freezed: ^3.0.6 json_serializable: ^6.9.4 + flutter_gen_runner: ^5.10.0 ##test mocktail: ^1.0.4 @@ -56,7 +60,19 @@ flutter: - assets/logos/ - assets/vec/ + fonts: - family: yekan fonts: - asset: fonts/iranyekanregularfanum.ttf + + +flutter_gen: + output: packages/core/lib/presentation/common + line_length: 120 + # Optional + integrations: + image: true + flutter_svg: true + rive: false + lottie: false From ed75da4eaa5f47f2348bcdbfa129816ab5fd763d Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 21 May 2025 09:04:21 +0330 Subject: [PATCH 06/25] feat: new pages and with binding ... --- .../lib/presentation/page/action/logic.dart | 5 +++++ .../lib/presentation/page/action/view.dart | 12 ++++++++++++ .../lib/presentation/page/map/logic.dart | 5 +++++ .../lib/presentation/page/map/view.dart | 14 ++++++++++++++ .../lib/presentation/page/profile/logic.dart | 5 +++++ .../lib/presentation/page/profile/view.dart | 13 +++++++++++++ .../lib/presentation/page/root/logic.dart | 9 +++++++-- .../lib/presentation/page/root/view.dart | 10 +++++++++- .../lib/presentation/routes/app_pages.dart | 18 ++++++++++-------- .../lib/presentation/routes/app_routes.dart | 6 ++++-- 10 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 packages/livestock/lib/presentation/page/action/logic.dart create mode 100644 packages/livestock/lib/presentation/page/action/view.dart create mode 100644 packages/livestock/lib/presentation/page/map/logic.dart create mode 100644 packages/livestock/lib/presentation/page/map/view.dart create mode 100644 packages/livestock/lib/presentation/page/profile/logic.dart create mode 100644 packages/livestock/lib/presentation/page/profile/view.dart diff --git a/packages/livestock/lib/presentation/page/action/logic.dart b/packages/livestock/lib/presentation/page/action/logic.dart new file mode 100644 index 0000000..e540e8c --- /dev/null +++ b/packages/livestock/lib/presentation/page/action/logic.dart @@ -0,0 +1,5 @@ +import 'package:rasadyar_core/core.dart'; + +class ActionLogic extends GetxController { + +} diff --git a/packages/livestock/lib/presentation/page/action/view.dart b/packages/livestock/lib/presentation/page/action/view.dart new file mode 100644 index 0000000..3068f47 --- /dev/null +++ b/packages/livestock/lib/presentation/page/action/view.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'logic.dart'; + +class ActionPage extends GetView { + ActionPage({super.key}); + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/packages/livestock/lib/presentation/page/map/logic.dart b/packages/livestock/lib/presentation/page/map/logic.dart new file mode 100644 index 0000000..73d5b78 --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/logic.dart @@ -0,0 +1,5 @@ +import 'package:rasadyar_core/core.dart'; + +class MapLogic extends GetxController { + +} diff --git a/packages/livestock/lib/presentation/page/map/view.dart b/packages/livestock/lib/presentation/page/map/view.dart new file mode 100644 index 0000000..0bb76db --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -0,0 +1,14 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'logic.dart'; + +class MapPage extends GetView { + MapPage({super.key}); + + + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/packages/livestock/lib/presentation/page/profile/logic.dart b/packages/livestock/lib/presentation/page/profile/logic.dart new file mode 100644 index 0000000..811d534 --- /dev/null +++ b/packages/livestock/lib/presentation/page/profile/logic.dart @@ -0,0 +1,5 @@ +import 'package:rasadyar_core/core.dart'; + +class ProfileLogic extends GetxController { + +} diff --git a/packages/livestock/lib/presentation/page/profile/view.dart b/packages/livestock/lib/presentation/page/profile/view.dart new file mode 100644 index 0000000..1819ff5 --- /dev/null +++ b/packages/livestock/lib/presentation/page/profile/view.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'logic.dart'; + +class ProfilePage extends GetView { + ProfilePage({super.key}); + + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index e335077..c6aceec 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,8 +1,13 @@ - - +import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/action/view.dart'; +import 'package:rasadyar_livestock/presentation/page/map/view.dart'; +import 'package:rasadyar_livestock/presentation/page/profile/view.dart'; class RootLogic extends GetxController { + List pages = [ActionPage(), MapPage(), ProfilePage()]; + RxInt indexedPage = 1.obs; + @override void onReady() { // TODO: implement onReady diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 4725935..88d0fc3 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -7,6 +7,14 @@ class RootPage extends GetView { @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + body: ObxValue((data) { + return IndexedStack( + children: controller.pages, + index: data.value, + sizing: StackFit.expand, + ); + }, controller.indexedPage), + ); } } diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index c699577..3795a4b 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,10 +1,11 @@ - import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/action/logic.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/root/logic.dart'; import 'package:rasadyar_livestock/presentation/page/root/view.dart'; - - -part'app_routes.dart'; +part 'app_routes.dart'; sealed class LiveStockPages { LiveStockPages._(); @@ -15,11 +16,12 @@ sealed class LiveStockPages { page: () => RootPage(), middlewares: [AuthMiddleware()], binding: BindingsBuilder(() { - + Get.put(RootLogic()); + BindingsBuilder.put(() => RootLogic()); + Get.lazyPut(() => ActionLogic()); + Get.lazyPut(() => MapLogic()); + Get.lazyPut(() => ProfileLogic()); }), ), - - ]; } - diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index b563e83..4c6eece 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -1,9 +1,11 @@ - part of 'app_pages.dart'; sealed class LiveStockRoutes { LiveStockRoutes._(); - static const init = '/liveStockRoutesInit'; + static const init = '/liveStock'; + static const action = '$init/liveStock'; + static const map = '$init/liveStock'; + static const profile = '$init/profile'; } From b5406a00a06a60f117336420bedb4cab31677699 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 21 May 2025 09:17:37 +0330 Subject: [PATCH 07/25] feat: map widget with controller --- .../core/lib/presentation/widget/map/logic.dart | 5 +++++ packages/core/lib/presentation/widget/map/view.dart | 13 +++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 packages/core/lib/presentation/widget/map/logic.dart create mode 100644 packages/core/lib/presentation/widget/map/view.dart diff --git a/packages/core/lib/presentation/widget/map/logic.dart b/packages/core/lib/presentation/widget/map/logic.dart new file mode 100644 index 0000000..40b1aa4 --- /dev/null +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class MapLogic extends GetxController { + +} diff --git a/packages/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart new file mode 100644 index 0000000..f71f1e0 --- /dev/null +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'logic.dart'; + +class MapPage extends GetView { + const MapPage({super.key}); + + @override + Widget build(BuildContext context) { + return Container(); + } +} From 1ed8e69262fc97be884cc3a040542f2601013656 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 21 May 2025 14:43:26 +0330 Subject: [PATCH 08/25] feat: actions and map page --- assets/icons/search.svg | 6 + assets/vec/search.svg.vec | Bin 0 -> 203 bytes lib/presentations/common/assets.dart | 43 ++++ packages/core/lib/core.dart | 2 +- .../lib/presentation/common/app_fonts.dart | 9 + .../lib/presentation/common/assets.gen.dart | 8 + .../widget/app_bar/r_app_bar.dart | 23 +- .../bottom_navigation_1.dart | 13 +- .../presentation/widget/chips/r_chips.dart | 85 +++++++ .../lib/presentation/widget/map/logic.dart | 80 ++++++- .../lib/presentation/widget/map/view.dart | 69 +++++- .../core/lib/presentation/widget/widget.dart | 1 + .../lib/presentation/page/action/view.dart | 208 +++++++++++++++++- .../lib/presentation/page/map/logic.dart | 3 + .../lib/presentation/page/map/view.dart | 16 +- .../lib/presentation/page/root/logic.dart | 5 +- .../lib/presentation/page/root/view.dart | 40 +++- .../lib/presentation/routes/app_pages.dart | 4 + tools/vecGeneratoe.sh | 4 +- 19 files changed, 586 insertions(+), 33 deletions(-) create mode 100644 assets/icons/search.svg create mode 100644 assets/vec/search.svg.vec create mode 100644 lib/presentations/common/assets.dart create mode 100644 packages/core/lib/presentation/widget/chips/r_chips.dart diff --git a/assets/icons/search.svg b/assets/icons/search.svg new file mode 100644 index 0000000..4a4e42d --- /dev/null +++ b/assets/icons/search.svg @@ -0,0 +1,6 @@ + + + + diff --git a/assets/vec/search.svg.vec b/assets/vec/search.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..da0271d4916ce3d2156595941fc6690f9daf8a0a GIT binary patch literal 203 zcmYe&?O const SvgGenImage('assets/icons/scan_barcode.svg'); + /// File path: assets/icons/search.svg + SvgGenImage get search => const SvgGenImage('assets/icons/search.svg'); + /// File path: assets/icons/security_time.svg SvgGenImage get securityTime => const SvgGenImage('assets/icons/security_time.svg'); @@ -147,6 +150,7 @@ class $AssetsIconsGen { receiptDiscount, scan, scanBarcode, + search, securityTime, setting, tagUser, @@ -256,6 +260,9 @@ class $AssetsVecGen { /// File path: assets/vec/scan_barcode.svg.vec SvgGenImage get scanBarcodeSvg => const SvgGenImage.vec('assets/vec/scan_barcode.svg.vec'); + /// File path: assets/vec/search.svg.vec + SvgGenImage get searchSvg => const SvgGenImage.vec('assets/vec/search.svg.vec'); + /// File path: assets/vec/security_time.svg.vec SvgGenImage get securityTimeSvg => const SvgGenImage.vec('assets/vec/security_time.svg.vec'); @@ -304,6 +311,7 @@ class $AssetsVecGen { receiptDiscountSvg, scanSvg, scanBarcodeSvg, + searchSvg, securityTimeSvg, settingSvg, tagUserSvg, 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 47f7da9..6db58bb 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 @@ -8,6 +8,8 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { final String title; final Color backgroundColor; final Color iconColor; + final bool hasBack; + final bool centerTitle; final TextStyle? titleTextStyle; final VoidCallback? onBackPressed; final List? additionalActions; @@ -22,6 +24,8 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { this.onBackPressed, this.additionalActions, this.leading, + this.hasBack = false, + this.centerTitle = false, }); @override @@ -32,6 +36,7 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { elevation: 0, excludeHeaderSemantics: true, scrolledUnderElevation: 0, + centerTitle: centerTitle, titleTextStyle: titleTextStyle ?? AppFonts.yekan16.copyWith(color:Colors.white), @@ -43,14 +48,18 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { ) : null, actions: [ if (additionalActions != null) ...additionalActions!, - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: IconButton( - onPressed: onBackPressed ?? () => Get.back(), - icon: const Icon(CupertinoIcons.chevron_back), - color: iconColor, + if(hasBack)...{ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: IconButton( + onPressed: onBackPressed ?? () => Get.back(), + icon: const Icon(CupertinoIcons.chevron_back), + color: iconColor, + ), ), - ), + } + + ], ); diff --git a/packages/core/lib/presentation/widget/bottom_navigation/bottom_navigation_1.dart b/packages/core/lib/presentation/widget/bottom_navigation/bottom_navigation_1.dart index 07f98f4..b5c569e 100644 --- a/packages/core/lib/presentation/widget/bottom_navigation/bottom_navigation_1.dart +++ b/packages/core/lib/presentation/widget/bottom_navigation/bottom_navigation_1.dart @@ -60,16 +60,17 @@ class BottomNavigation1Item extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - vecWidget( - icon, - width: 32, - height: 32, - color: isSelected ? AppColor.blueNormal : Colors.white, + SvgGenImage.vec(icon).svg( + width: 32, + height: 32, + colorFilter: ColorFilter.mode( + isSelected ? AppColor.blueNormal : Colors.white, + BlendMode.srcIn) ), const SizedBox(height: 5), Text( label, - style: AppFonts.yekan14.copyWith( + style: AppFonts.yekan10.copyWith( color: isSelected ? AppColor.blueNormal : Colors.white, ), ), diff --git a/packages/core/lib/presentation/widget/chips/r_chips.dart b/packages/core/lib/presentation/widget/chips/r_chips.dart new file mode 100644 index 0000000..a7f7d02 --- /dev/null +++ b/packages/core/lib/presentation/widget/chips/r_chips.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; + +class CustomChip extends StatelessWidget { + final bool isSelected; + final String title; + final int index; + final Function(int) onTap; + final Color selectedColor; + final Color unSelectedColor; + + const CustomChip({ + super.key, + this.isSelected = false, + required this.title, + required this.index, + required this.onTap, + this.selectedColor = AppColor.blueNormal, + this.unSelectedColor = AppColor.whiteGreyNormal, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => onTap.call(index), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: isSelected ? selectedColor : unSelectedColor, + borderRadius: BorderRadius.circular(8), + border: + isSelected + ? Border.fromBorderSide(BorderSide.none) + : Border.all(width: 0.25, color: const Color(0xFFB0B0B0)), + ), + child: Text( + title, + textAlign: TextAlign.center, + style: + isSelected + ? AppFonts.yekan10.copyWith(color: AppColor.whiteLight) + : AppFonts.yekan10, + ), + ), + ); + } +} + +class RFilterChips extends StatelessWidget { + const RFilterChips({ + super.key, + this.isSelected = false, + required this.title, + required this.index, + required this.onTap, + this.selectedColor = AppColor.blueNormal, + this.unSelectedColor = AppColor.whiteGreyNormal, + }); + + final bool isSelected; + final String title; + final int index; + final Function(int) onTap; + final Color selectedColor; + final Color unSelectedColor; + + @override + Widget build(BuildContext context) { + return FilterChip( + labelStyle: isSelected + ? AppFonts.yekan10.copyWith(color: AppColor.mediumGreyDarkActive) + : AppFonts.yekan10, + label: Text( + title, + textAlign: TextAlign.center), + deleteIconColor: Colors.red, + selected: isSelected, + selectedColor: selectedColor, + onSelected: (bool selected) { + onTap.call(index); + }, + ); + } +} diff --git a/packages/core/lib/presentation/widget/map/logic.dart b/packages/core/lib/presentation/widget/map/logic.dart index 40b1aa4..4435248 100644 --- a/packages/core/lib/presentation/widget/map/logic.dart +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -1,5 +1,83 @@ +import 'dart:async'; + +import 'package:flutter/animation.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'; -class MapLogic extends GetxController { +class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { + Rx currentLocation = LatLng(35.824891, 50.948025).obs; + String tileType = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'; + RxList markers = [].obs; + RxList allMarkers = [].obs; + Rx mapController = MapController().obs; + + late final AnimatedMapController animatedMapController; + Timer? _debounceTimer; + RxBool isLoading = false.obs; + + @override + void onInit() { + super.onInit(); + animatedMapController = AnimatedMapController( + vsync: this, + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut, + cancelPreviousAnimations: true, + ); + determineCurrentPosition(); + } + + @override + void onClose() { + super.onClose(); + animatedMapController.dispose(); + mapController.close(); + } + + Future determineCurrentPosition() async { + final position = await Geolocator.getCurrentPosition( + locationSettings: AndroidSettings(accuracy: LocationAccuracy.best), + ); + final latLng = LatLng(position.latitude, position.longitude); + + currentLocation.value = latLng; + markers.add(latLng); + animatedMapController.animateTo( + dest: latLng, + zoom: 18, + curve: Curves.easeInOut, + duration: const Duration(milliseconds: 1500), + ); + } + + void debouncedUpdateVisibleMarkers({required LatLng center}) { + _debounceTimer?.cancel(); + _debounceTimer = Timer(const Duration(milliseconds: 300), () { + final filtered = filterNearbyMarkers({ + 'markers': allMarkers, + 'centerLat': center.latitude, + 'centerLng': center.longitude, + 'radius': 1000.0, + }); + + markers.addAll(filtered); + }); + } + + List filterNearbyMarkers(Map args) { + final List rawMarkers = args['markers']; + final double centerLat = args['centerLat']; + final double centerLng = args['centerLng']; + final double radiusInMeters = args['radius']; + final center = LatLng(centerLat, centerLng); + final distance = Distance(); + + return rawMarkers + .where((marker) => distance(center, marker) <= radiusInMeters) + .toList(); + } } diff --git a/packages/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart index f71f1e0..aa9e2cf 100644 --- a/packages/core/lib/presentation/widget/map/view.dart +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -1,13 +1,76 @@ import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; import 'package:get/get.dart'; +import 'package:rasadyar_core/presentation/common/app_color.dart'; +import 'package:rasadyar_core/presentation/common/assets.gen.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; import 'logic.dart'; -class MapPage extends GetView { - const MapPage({super.key}); +class MapWidget extends GetView { + const MapWidget({super.key}); @override Widget build(BuildContext context) { - return Container(); + return Stack( + children: [_buildMap(), _buildGpsButton(), _buildFilterButton()], + ); + } + + Widget _buildMap() { + return ObxValue((currentLocation) { + return FlutterMap( + mapController: controller.animatedMapController.mapController, + options: MapOptions( + initialCenter: currentLocation.value, + initialZoom: 18, + onPositionChanged: (camera, hasGesture) { + controller.debouncedUpdateVisibleMarkers(center: camera.center); + }, + ), + children: [ + TileLayer(urlTemplate: controller.tileType), + /* ObxValue((markers) { + return MarkerLayer( + markers: + markers + .map((e) => markerWidget(marker: e, onTap: () {})) + .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: () {}, + ), + ); } } diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 0f3dc7b..546efec 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -15,3 +15,4 @@ export 'tabs/new_tab.dart'; export 'tabs/tab.dart'; export 'vec_widget.dart'; export 'card/card_with_icon_with_border.dart'; +export 'chips/r_chips.dart'; diff --git a/packages/livestock/lib/presentation/page/action/view.dart b/packages/livestock/lib/presentation/page/action/view.dart index 3068f47..2f7dfac 100644 --- a/packages/livestock/lib/presentation/page/action/view.dart +++ b/packages/livestock/lib/presentation/page/action/view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; + import 'logic.dart'; class ActionPage extends GetView { @@ -7,6 +8,211 @@ class ActionPage extends GetView { @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + appBar: RAppBar( + title: 'لیست درخواست‌ها', + hasBack: false, + centerTitle: true, + ), + body: Column( + children: [ + SizedBox(height: 16), + _searchWidget(), + SizedBox(height: 16), + SizedBox( + height: 50, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 12), + child: Row( + spacing: 12, + children: [ + CustomChip( + title: 'انتخاب فیلتر', + index: 0, + isSelected: true, + selectedColor: AppColor.blueNormal, + onTap: (index) {}, + ), + + RFilterChips( + title: 'درخواست‌های من', + index: 1, + isSelected: true, + selectedColor: AppColor.yellowNormal, + onTap: (index) {}, + ), + + RFilterChips( + title: 'در انتظار ثبت ', + index: 2, + selectedColor: AppColor.greenLightActive, + isSelected: true, + onTap: (index) {}, + ), + + RFilterChips( + title: 'ارجاع به تعاونی', + index: 3, + selectedColor: AppColor.blueLightHover, + isSelected: true, + onTap: (index) {}, + ), + ], + ), + ), + ), + SizedBox(height: 10), + Expanded( + child: ListView.separated( + itemCount: 10, + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + separatorBuilder: (context, index) => SizedBox(height: 16), + itemBuilder: (context, index) { + return Container( + width: Get.width, + height: 75, + decoration: BoxDecoration( + color: + index < 3 + ? AppColor.yellowNormal + : index < 7 + ? AppColor.greenLightActive + : AppColor.blueLight, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + SizedBox(width: 5), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8), + bottomRight: Radius.circular(8), + ), + ), + child: Row( + children: [ + SizedBox(width: 10), + Text( + 'محمد احمدی', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith( + color: AppColor.blueNormal, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(width: 20), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + + children: [ + Text( + 'پنج شنبه 14 اردیبهشت', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.darkGreyNormal, + ), + ), + Text( + ' همدان - نهاوند - روستای - همدان - نهاوند - روستای ', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.darkGreyNormal, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ], + ), + ), + SizedBox(width: 20), + GestureDetector( + onTap: () { + // controller.onTapMap(); + }, + child: SizedBox( + width: 50, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Assets.vec.mapSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode( + AppColor.blueNormal, + BlendMode.srcIn, + ), + ), + SizedBox(height: 8), + Text( + 'مسیریابی', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + ), + + SizedBox(width: 20), + ], + ), + ), + ), + + Container( + width: 20, + child: Center( + child: RotatedBox( + quarterTurns: 3, + child: Text( + index < 3 + ? ' بازرسی' + : index < 7 + ? 'اطلاعات' + : 'ارجاع به تعاونی', + style: AppFonts.yekan8, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ); + }, + ), + ), + ], + ), + ); + } + + Widget _searchWidget() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + 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(), + ), + ); } } diff --git a/packages/livestock/lib/presentation/page/map/logic.dart b/packages/livestock/lib/presentation/page/map/logic.dart index 73d5b78..c54ed07 100644 --- a/packages/livestock/lib/presentation/page/map/logic.dart +++ b/packages/livestock/lib/presentation/page/map/logic.dart @@ -2,4 +2,7 @@ import 'package:rasadyar_core/core.dart'; class MapLogic extends GetxController { + + + } diff --git a/packages/livestock/lib/presentation/page/map/view.dart b/packages/livestock/lib/presentation/page/map/view.dart index 0bb76db..d05b39f 100644 --- a/packages/livestock/lib/presentation/page/map/view.dart +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -1,14 +1,22 @@ import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' as mt; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/presentation/widget/map/view.dart'; + + import 'logic.dart'; class MapPage extends GetView { MapPage({super.key}); - - @override Widget build(BuildContext context) { - return Container(); + return Scaffold( + body: Stack( + children: [ + MapWidget(), + ], + ), + ); } -} +} \ No newline at end of file diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index c6aceec..843ec7b 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -6,7 +6,7 @@ import 'package:rasadyar_livestock/presentation/page/profile/view.dart'; class RootLogic extends GetxController { List pages = [ActionPage(), MapPage(), ProfilePage()]; - RxInt indexedPage = 1.obs; + RxInt currentIndex = 1.obs; @override void onReady() { @@ -19,4 +19,7 @@ class RootLogic extends GetxController { // TODO: implement onClose super.onClose(); } + + void changePage(int i) => currentIndex.value = i; + } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 88d0fc3..ca4c3ff 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; + import 'logic.dart'; class RootPage extends GetView { @@ -7,14 +8,39 @@ class RootPage extends GetView { @override Widget build(BuildContext context) { - return Scaffold( - body: ObxValue((data) { - return IndexedStack( + return ObxValue((currentIndex) { + return Scaffold( + body: IndexedStack( children: controller.pages, - index: data.value, + index: currentIndex.value, sizing: StackFit.expand, - ); - }, controller.indexedPage), - ); + ), + + bottomNavigationBar: BottomNavigation1( + items: [ + BottomNavigation1Item( + icon: Assets.vec.filterSvg.path, + label: 'درخواست‌ها', + isSelected: currentIndex.value == 0, + onTap: () => controller.changePage(0), + ), + + BottomNavigation1Item( + icon: Assets.vec.mapSvg.path, + label: 'نقشه', + isSelected: currentIndex.value == 1, + onTap: () => controller.changePage(1), + ), + + BottomNavigation1Item( + icon: Assets.vec.profileUserSvg.path, + label: 'پروفایل', + isSelected: currentIndex.value == 2, + onTap: () => controller.changePage(2), + ), + ], + ), + ); + }, controller.currentIndex); } } diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 3795a4b..6570bf8 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,10 +1,12 @@ import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/presentation/widget/map/logic.dart'; import 'package:rasadyar_livestock/presentation/page/action/logic.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/root/logic.dart'; import 'package:rasadyar_livestock/presentation/page/root/view.dart'; + part 'app_routes.dart'; sealed class LiveStockPages { @@ -21,6 +23,8 @@ sealed class LiveStockPages { Get.lazyPut(() => ActionLogic()); Get.lazyPut(() => MapLogic()); Get.lazyPut(() => ProfileLogic()); + Get.lazyPut(() => ProfileLogic()); + Get.lazyPut(() => MapWidgetLogic()); }), ), ]; diff --git a/tools/vecGeneratoe.sh b/tools/vecGeneratoe.sh index 1b84fb3..4c6cf89 100644 --- a/tools/vecGeneratoe.sh +++ b/tools/vecGeneratoe.sh @@ -11,8 +11,8 @@ PACKAGE_ABS_PATH="$SCRIPT_DIR/$PACKAGE_PATH" echo "🗃️ package path: $PACKAGE_ABS_PATH" # Directory to read files from -sourcePath="$PACKAGE_ABS_PATH/assets/icons" -targetPath="$PACKAGE_ABS_PATH/assets/vec" +sourcePath="../assets/icons" +targetPath="../assets/vec" echo "🗃️ sourcePath path: $sourcePath" echo "🗃️ targetPath path: $targetPath" From 10cb9d1f521947328b96b60b11be60f7086c5e3f Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 24 May 2025 09:15:26 +0330 Subject: [PATCH 09/25] fix : map permission and marker --- .../lib/presentation/widget/map/logic.dart | 70 +++++++++- .../lib/presentation/widget/map/view.dart | 121 +++++++++++++++++- 2 files changed, 187 insertions(+), 4 deletions(-) diff --git a/packages/core/lib/presentation/widget/map/logic.dart b/packages/core/lib/presentation/widget/map/logic.dart index 4435248..0824b14 100644 --- a/packages/core/lib/presentation/widget/map/logic.dart +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -6,6 +6,9 @@ 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'; + +enum ErrorLocationType { serviceDisabled, permissionDenied, none } class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Rx currentLocation = LatLng(35.824891, 50.948025).obs; @@ -14,7 +17,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { RxList markers = [].obs; RxList allMarkers = [].obs; Rx mapController = MapController().obs; - + RxList errorLocationType = RxList(); late final AnimatedMapController animatedMapController; Timer? _debounceTimer; RxBool isLoading = false.obs; @@ -28,6 +31,30 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { curve: Curves.easeInOut, cancelPreviousAnimations: true, ); + locationServiceEnabled().then((value) { + if (!value) { + errorLocationType.add(ErrorLocationType.serviceDisabled); + } + }); + + checkPermission().then((value) { + if (!value) { + errorLocationType.add(ErrorLocationType.permissionDenied); + } + }); + + listenToLocationServiceStatus().listen((event) { + if (!event) { + errorLocationType.add(ErrorLocationType.serviceDisabled); + } else { + errorLocationType.remove(ErrorLocationType.serviceDisabled); + } + }); + } + + @override + void onReady() { + super.onReady(); determineCurrentPosition(); } @@ -38,6 +65,47 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { mapController.close(); } + Stream listenToLocationServiceStatus() { + return Geolocator.getServiceStatusStream().map((status) { + return status == ServiceStatus.enabled; + }); + } + + Future locationServiceEnabled() async { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + return false; + } + return true; + } + + Future checkPermission({bool request = false}) async { + try { + final LocationPermission permission = await Geolocator.checkPermission(); + + switch (permission) { + case LocationPermission.denied: + final LocationPermission requestResult = + await Geolocator.requestPermission(); + return requestResult != LocationPermission.denied && + requestResult != LocationPermission.deniedForever; + + case LocationPermission.deniedForever: + return request ? await Geolocator.openAppSettings() : false; + + case LocationPermission.always: + case LocationPermission.whileInUse: + return true; + + default: + return false; + } + } catch (e) { + eLog(e); + return await Geolocator.openLocationSettings(); + } + } + Future determineCurrentPosition() async { final position = await Geolocator.getCurrentPosition( locationSettings: AndroidSettings(accuracy: LocationAccuracy.best), diff --git a/packages/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart index aa9e2cf..8fe6cc2 100644 --- a/packages/core/lib/presentation/widget/map/view.dart +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -1,9 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; +import 'package:latlong2/latlong.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'; @@ -13,7 +18,99 @@ class MapWidget extends GetView { @override Widget build(BuildContext context) { return Stack( - children: [_buildMap(), _buildGpsButton(), _buildFilterButton()], + 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()], ); } @@ -30,14 +127,14 @@ class MapWidget extends GetView { ), children: [ TileLayer(urlTemplate: controller.tileType), - /* ObxValue((markers) { + ObxValue((markers) { return MarkerLayer( markers: markers .map((e) => markerWidget(marker: e, onTap: () {})) .toList(), ); - }, controller.markers),*/ + }, controller.markers), ], ); }, controller.currentLocation); @@ -73,4 +170,22 @@ class MapWidget extends GetView { ), ); } + + 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, + ) + ), + ), + ); + } } From 276c8dd1fe59e23a2c8420d2f045c4c84f49f085 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sat, 24 May 2025 15:12:40 +0330 Subject: [PATCH 10/25] feat : request tagging and fix chips and fix overflow module in auht --- .../card/card_with_icon_with_border.dart | 2 +- .../presentation/widget/chips/r_chips.dart | 33 ++- .../lib/presentation/page/action/logic.dart | 5 - .../lib/presentation/page/action/view.dart | 218 --------------- .../page/request_tagging/logic.dart | 16 ++ .../page/request_tagging/view.dart | 46 ++++ .../lib/presentation/page/requests/logic.dart | 7 + .../lib/presentation/page/requests/view.dart | 255 ++++++++++++++++++ .../lib/presentation/page/root/logic.dart | 24 +- .../lib/presentation/page/root/view.dart | 83 ++++-- .../lib/presentation/routes/app_pages.dart | 18 +- .../lib/presentation/routes/app_routes.dart | 7 +- 12 files changed, 450 insertions(+), 264 deletions(-) delete mode 100644 packages/livestock/lib/presentation/page/action/logic.dart delete mode 100644 packages/livestock/lib/presentation/page/action/view.dart create mode 100644 packages/livestock/lib/presentation/page/request_tagging/logic.dart create mode 100644 packages/livestock/lib/presentation/page/request_tagging/view.dart create mode 100644 packages/livestock/lib/presentation/page/requests/logic.dart create mode 100644 packages/livestock/lib/presentation/page/requests/view.dart 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 510f146..ca7d2b6 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 @@ -23,7 +23,7 @@ class CardIcon extends StatelessWidget { side: const BorderSide(color: AppColor.blueNormal, width: 1), ), child: Container( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(8), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: Colors.white, diff --git a/packages/core/lib/presentation/widget/chips/r_chips.dart b/packages/core/lib/presentation/widget/chips/r_chips.dart index a7f7d02..7788061 100644 --- a/packages/core/lib/presentation/widget/chips/r_chips.dart +++ b/packages/core/lib/presentation/widget/chips/r_chips.dart @@ -1,3 +1,4 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; @@ -55,7 +56,7 @@ class RFilterChips extends StatelessWidget { required this.index, required this.onTap, this.selectedColor = AppColor.blueNormal, - this.unSelectedColor = AppColor.whiteGreyNormal, + this.unSelectedColor = AppColor.whiteGreyDark, }); final bool isSelected; @@ -66,7 +67,7 @@ class RFilterChips extends StatelessWidget { final Color unSelectedColor; @override - Widget build(BuildContext context) { + /* Widget build(BuildContext context) { return FilterChip( labelStyle: isSelected ? AppFonts.yekan10.copyWith(color: AppColor.mediumGreyDarkActive) @@ -74,12 +75,38 @@ class RFilterChips extends StatelessWidget { label: Text( title, textAlign: TextAlign.center), - deleteIconColor: Colors.red, selected: isSelected, + showCheckmark: false, // مخفی‌کردن چک‌مارک پیش‌فرض + avatar: isSelected + ? Icon( + Icons.star, // آیکون دلخواه به‌جای چک‌مارک + size: 18, + color: Colors.orange, + ) + : null, selectedColor: selectedColor, onSelected: (bool selected) { onTap.call(index); }, ); + }*/ + Widget build(BuildContext context) { + return RawChip( + label: Text(title), + labelStyle: isSelected + ? AppFonts.yekan10.copyWith(color: AppColor.mediumGreyDarkActive) + : AppFonts.yekan10, + selected: isSelected, + onSelected: (bool selected) => onTap(index), + backgroundColor: Colors.grey[200], + selectedColor: selectedColor, + showCheckmark: false, + shape: RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + side: BorderSide(width: 1, color: isSelected? selectedColor :unSelectedColor), + ), + deleteIcon: Icon(CupertinoIcons.clear_circled), + onDeleted: isSelected ? () => onTap(index) : null, + ); } } diff --git a/packages/livestock/lib/presentation/page/action/logic.dart b/packages/livestock/lib/presentation/page/action/logic.dart deleted file mode 100644 index e540e8c..0000000 --- a/packages/livestock/lib/presentation/page/action/logic.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:rasadyar_core/core.dart'; - -class ActionLogic extends GetxController { - -} diff --git a/packages/livestock/lib/presentation/page/action/view.dart b/packages/livestock/lib/presentation/page/action/view.dart deleted file mode 100644 index 2f7dfac..0000000 --- a/packages/livestock/lib/presentation/page/action/view.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:rasadyar_core/core.dart'; - -import 'logic.dart'; - -class ActionPage extends GetView { - ActionPage({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: RAppBar( - title: 'لیست درخواست‌ها', - hasBack: false, - centerTitle: true, - ), - body: Column( - children: [ - SizedBox(height: 16), - _searchWidget(), - SizedBox(height: 16), - SizedBox( - height: 50, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - padding: EdgeInsets.symmetric(horizontal: 12), - child: Row( - spacing: 12, - children: [ - CustomChip( - title: 'انتخاب فیلتر', - index: 0, - isSelected: true, - selectedColor: AppColor.blueNormal, - onTap: (index) {}, - ), - - RFilterChips( - title: 'درخواست‌های من', - index: 1, - isSelected: true, - selectedColor: AppColor.yellowNormal, - onTap: (index) {}, - ), - - RFilterChips( - title: 'در انتظار ثبت ', - index: 2, - selectedColor: AppColor.greenLightActive, - isSelected: true, - onTap: (index) {}, - ), - - RFilterChips( - title: 'ارجاع به تعاونی', - index: 3, - selectedColor: AppColor.blueLightHover, - isSelected: true, - onTap: (index) {}, - ), - ], - ), - ), - ), - SizedBox(height: 10), - Expanded( - child: ListView.separated( - itemCount: 10, - physics: BouncingScrollPhysics(), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), - separatorBuilder: (context, index) => SizedBox(height: 16), - itemBuilder: (context, index) { - return Container( - width: Get.width, - height: 75, - decoration: BoxDecoration( - color: - index < 3 - ? AppColor.yellowNormal - : index < 7 - ? AppColor.greenLightActive - : AppColor.blueLight, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - SizedBox(width: 5), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(8), - bottomRight: Radius.circular(8), - ), - ), - child: Row( - children: [ - SizedBox(width: 10), - Text( - 'محمد احمدی', - textAlign: TextAlign.center, - style: AppFonts.yekan12.copyWith( - color: AppColor.blueNormal, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(width: 20), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - - children: [ - Text( - 'پنج شنبه 14 اردیبهشت', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.darkGreyNormal, - ), - ), - Text( - ' همدان - نهاوند - روستای - همدان - نهاوند - روستای ', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.darkGreyNormal, - ), - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ], - ), - ), - SizedBox(width: 20), - GestureDetector( - onTap: () { - // controller.onTapMap(); - }, - child: SizedBox( - width: 50, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Assets.vec.mapSvg.svg( - width: 20, - height: 20, - colorFilter: ColorFilter.mode( - AppColor.blueNormal, - BlendMode.srcIn, - ), - ), - SizedBox(height: 8), - Text( - 'مسیریابی', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.blueNormal, - ), - ), - ], - ), - ), - ), - - SizedBox(width: 20), - ], - ), - ), - ), - - Container( - width: 20, - child: Center( - child: RotatedBox( - quarterTurns: 3, - child: Text( - index < 3 - ? ' بازرسی' - : index < 7 - ? 'اطلاعات' - : 'ارجاع به تعاونی', - style: AppFonts.yekan8, - textAlign: TextAlign.center, - ), - ), - ), - ), - ], - ), - ); - }, - ), - ), - ], - ), - ); - } - - Widget _searchWidget() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - 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(), - ), - ); - } -} diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart new file mode 100644 index 0000000..ee5f9ee --- /dev/null +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -0,0 +1,16 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; + +class RequestTaggingLogic extends GetxController { + + + @override + void onReady() { + super.onReady(); + } + + @override + void onClose() { + super.onClose(); + } +} diff --git a/packages/livestock/lib/presentation/page/request_tagging/view.dart b/packages/livestock/lib/presentation/page/request_tagging/view.dart new file mode 100644 index 0000000..67d773a --- /dev/null +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'logic.dart'; + +class RequestTaggingPage extends GetView { + const RequestTaggingPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Request Tagging'), + centerTitle: true, + actions: [ + IconButton( + icon: const Icon(Icons.search), + onPressed: () { + // Implement search functionality + }, + ), + ], + ), + body: Column( + children: [ + const SizedBox(height: 16), + + const SizedBox(height: 16), + Expanded( + child: ListView.builder( + itemCount: 10, // Replace with your data length + itemBuilder: (context, index) { + return ListTile( + title: Text('Request Item $index'), + onTap: () { + // Handle item tap + }, + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/packages/livestock/lib/presentation/page/requests/logic.dart b/packages/livestock/lib/presentation/page/requests/logic.dart new file mode 100644 index 0000000..9cb9154 --- /dev/null +++ b/packages/livestock/lib/presentation/page/requests/logic.dart @@ -0,0 +1,7 @@ +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; + +class RequestsLogic extends GetxController { + RxList filterSelected = [].obs; + +} diff --git a/packages/livestock/lib/presentation/page/requests/view.dart b/packages/livestock/lib/presentation/page/requests/view.dart new file mode 100644 index 0000000..966ea7c --- /dev/null +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -0,0 +1,255 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; + +import 'logic.dart'; + +class RequestsPage extends GetView { + RequestsPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: RAppBar( + title: 'لیست درخواست‌ها', + hasBack: false, + centerTitle: true, + ), + body: Column( + children: [ + SizedBox(height: 16), + _searchWidget(), + SizedBox(height: 16), + SizedBox( + height: 50, + 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), + ), + ), + SizedBox(height: 10), + Expanded( + child: ListView.separated( + itemCount: 10, + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + separatorBuilder: (context, index) => SizedBox(height: 16), + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + Get.toNamed(LiveStockRoutes.requestTagging,id: 0); + }, + child: Container( + width: Get.width, + height: 75, + decoration: BoxDecoration( + color: + index < 3 + ? AppColor.yellowNormal + : index < 7 + ? AppColor.greenLightActive + : AppColor.blueLight, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + SizedBox(width: 5), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8), + bottomRight: Radius.circular(8), + ), + ), + child: Row( + children: [ + SizedBox(width: 10), + Text( + 'محمد احمدی', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith( + color: AppColor.blueNormal, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(width: 20), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + + children: [ + Text( + 'پنج شنبه 14 اردیبهشت', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.darkGreyNormal, + ), + ), + Text( + ' همدان - نهاوند - روستای - همدان - نهاوند - روستای ', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.darkGreyNormal, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ], + ), + ), + SizedBox(width: 20), + GestureDetector( + onTap: () { + // controller.onTapMap(); + }, + child: SizedBox( + width: 50, + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Assets.vec.mapSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode( + AppColor.blueNormal, + BlendMode.srcIn, + ), + ), + SizedBox(height: 8), + Text( + 'مسیریابی', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith( + color: AppColor.blueNormal, + ), + ), + ], + ), + ), + ), + + SizedBox(width: 20), + ], + ), + ), + ), + + Container( + width: 20, + child: Center( + child: RotatedBox( + quarterTurns: 3, + child: Text( + index < 3 + ? ' بازرسی' + : index < 7 + ? 'اطلاعات' + : 'ارجاع به تعاونی', + style: AppFonts.yekan8, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ), + ), + RElevated( + text: '+ ایجاد درخواست', + width: Get.width - 36, + height: 40, + textStyle: AppFonts.yekan18.copyWith(color: Colors.white), + onPressed: () { + //TODO + }, + ), + SizedBox(height: 10), + ], + ), + ); + } + + Widget _searchWidget() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + 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(), + ), + ); + } +} diff --git a/packages/livestock/lib/presentation/page/root/logic.dart b/packages/livestock/lib/presentation/page/root/logic.dart index 843ec7b..0aed723 100644 --- a/packages/livestock/lib/presentation/page/root/logic.dart +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -1,11 +1,30 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_livestock/presentation/page/action/view.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'; +import 'package:rasadyar_livestock/presentation/page/requests/view.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class RootLogic extends GetxController { - List pages = [ActionPage(), MapPage(), ProfilePage()]; + List pages = [ + Navigator( + key: Get.nestedKey(0), + initialRoute: LiveStockRoutes.requests, + onGenerateRoute: (settings) { + switch (settings.name) { + case LiveStockRoutes.requests: + return GetPageRoute(page: () => RequestsPage()); + case LiveStockRoutes.requestTagging: + return GetPageRoute(page: () => RequestTaggingPage()); + default: + return GetPageRoute(page: () => RequestsPage()); + } + }, + ), + MapPage(), + ProfilePage(), + ]; RxInt currentIndex = 1.obs; @override @@ -21,5 +40,4 @@ class RootLogic extends GetxController { } void changePage(int i) => currentIndex.value = i; - } diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index ca4c3ff..879add1 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -9,36 +9,65 @@ class RootPage extends GetView { @override Widget build(BuildContext context) { return ObxValue((currentIndex) { - return Scaffold( - body: IndexedStack( - children: controller.pages, - index: currentIndex.value, - sizing: StackFit.expand, - ), + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + final navigatorKey = Get.nestedKey(currentIndex); + eLog('Pop invoked with result: $result, didPop: $didPop'); + navigatorKey?.currentState?.pop(); - bottomNavigationBar: BottomNavigation1( - items: [ - BottomNavigation1Item( - icon: Assets.vec.filterSvg.path, - label: 'درخواست‌ها', - isSelected: currentIndex.value == 0, - onTap: () => controller.changePage(0), - ), - BottomNavigation1Item( - icon: Assets.vec.mapSvg.path, - label: 'نقشه', - isSelected: currentIndex.value == 1, - onTap: () => controller.changePage(1), - ), + /*eLog('Pop invoked with result: $result, didPop: $didPop'); + iLog(Get.currentRoute); + iLog(Get.previousRoute); - BottomNavigation1Item( - icon: Assets.vec.profileUserSvg.path, - label: 'پروفایل', - isSelected: currentIndex.value == 2, - onTap: () => controller.changePage(2), - ), - ], + final navigatorKey = Get.nestedKey(currentIndex); + + if (currentIndex.value == 0 && + navigatorKey != null && + navigatorKey.currentState != null) { + if (navigatorKey.currentState!.canPop()) { + navigatorKey.currentState!.pop(); + return; + } + + if (!didPop) { + return; + } + }*/ + }, + + child: Scaffold( + body: IndexedStack( + children: controller.pages, + index: currentIndex.value, + sizing: StackFit.expand, + ), + + bottomNavigationBar: BottomNavigation1( + items: [ + BottomNavigation1Item( + icon: Assets.vec.filterSvg.path, + label: 'درخواست‌ها', + isSelected: currentIndex.value == 0, + onTap: () => controller.changePage(0), + ), + + BottomNavigation1Item( + icon: Assets.vec.mapSvg.path, + label: 'نقشه', + isSelected: currentIndex.value == 1, + onTap: () => controller.changePage(1), + ), + + BottomNavigation1Item( + icon: Assets.vec.profileUserSvg.path, + label: 'پروفایل', + isSelected: currentIndex.value == 2, + onTap: () => controller.changePage(2), + ), + ], + ), ), ); }, controller.currentIndex); diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index 6570bf8..b74d313 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -1,9 +1,11 @@ import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/presentation/widget/map/logic.dart'; -import 'package:rasadyar_livestock/presentation/page/action/logic.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'; +import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; +import 'package:rasadyar_livestock/presentation/page/requests/logic.dart'; import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; import 'package:rasadyar_livestock/presentation/page/root/view.dart'; @@ -19,13 +21,23 @@ sealed class LiveStockPages { middlewares: [AuthMiddleware()], binding: BindingsBuilder(() { Get.put(RootLogic()); - BindingsBuilder.put(() => RootLogic()); - Get.lazyPut(() => ActionLogic()); + Get.lazyPut(() => RequestsLogic()); Get.lazyPut(() => MapLogic()); Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); }), + children: [ + GetPage( + name: LiveStockRoutes.requestTagging, + page: () => RequestTaggingPage(), + middlewares: [AuthMiddleware()], + binding: BindingsBuilder(() { + Get.lazyPut(() => RequestTaggingLogic()); + }), + ), + ] ), + ]; } diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index 4c6eece..616d5ee 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -4,8 +4,7 @@ sealed class LiveStockRoutes { LiveStockRoutes._(); static const init = '/liveStock'; - static const action = '$init/liveStock'; - static const map = '$init/liveStock'; - static const profile = '$init/profile'; - + static const requests = '/requests'; + static const profile = '/profile'; + static const requestTagging = '$init/tagging'; } From 45778a986601dc05c8e15f0c050119a3a1223708 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Sun, 25 May 2025 16:54:43 +0330 Subject: [PATCH 11/25] feat : request and request tagging --- assets/icons/place_holder.svg | 1 + assets/images/place_holder.png | Bin 0 -> 23331 bytes lib/presentation/common/assets.dart | 80 ++++++ .../lib/presentation/common/assets.gen.dart | 9 +- .../widget/app_bar/r_app_bar.dart | 6 +- .../lib/presentation/widget/buttons/fab.dart | 81 ++---- .../widget/buttons/outline_elevated_icon.dart | 4 +- .../draggable_bottom_sheet2.dart | 74 ++++++ .../draggable_bottom_sheet_controller.dart | 7 +- .../widget/map/custom_marker.dart | 10 + .../lib/presentation/widget/map/logic.dart | 27 +- .../lib/presentation/widget/map/view.dart | 62 +++-- .../core/lib/presentation/widget/widget.dart | 1 + .../lib/presentation/page/map/logic.dart | 2 +- .../lib/presentation/page/map/view.dart | 18 +- .../page/request_tagging/logic.dart | 3 +- .../page/request_tagging/view.dart | 123 ++++++--- .../lib/presentation/page/requests/view.dart | 2 +- .../lib/presentation/page/root/view.dart | 6 +- .../lib/presentation/page/tagging/logic.dart | 15 ++ .../lib/presentation/page/tagging/view.dart | 239 ++++++++++++++++++ .../lib/presentation/routes/app_pages.dart | 25 +- .../lib/presentation/routes/app_routes.dart | 5 +- 23 files changed, 655 insertions(+), 145 deletions(-) create mode 100644 assets/icons/place_holder.svg create mode 100644 assets/images/place_holder.png create mode 100644 lib/presentation/common/assets.dart create mode 100644 packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet2.dart create mode 100644 packages/core/lib/presentation/widget/map/custom_marker.dart create mode 100644 packages/livestock/lib/presentation/page/tagging/logic.dart create mode 100644 packages/livestock/lib/presentation/page/tagging/view.dart diff --git a/assets/icons/place_holder.svg b/assets/icons/place_holder.svg new file mode 100644 index 0000000..cfd772b --- /dev/null +++ b/assets/icons/place_holder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/place_holder.png b/assets/images/place_holder.png new file mode 100644 index 0000000000000000000000000000000000000000..fe12c5a005e81ec1e5d1acb2da3ee323980a0a75 GIT binary patch literal 23331 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 literal 0 HcmV?d00001 diff --git a/lib/presentation/common/assets.dart b/lib/presentation/common/assets.dart new file mode 100644 index 0000000..295cf2d --- /dev/null +++ b/lib/presentation/common/assets.dart @@ -0,0 +1,80 @@ +///This file is automatically generated. DO NOT EDIT, all your changes would be lost. +class Assets { + Assets._(); + + static const String iconsAdd = 'assets/icons/add.svg'; + static const String iconsArrowLeft = 'assets/icons/arrow_left.svg'; + static const String iconsArrowRight = 'assets/icons/arrow_right.svg'; + static const String iconsBgHeaderUserProfile = 'assets/icons/bg_header_user_profile.svg'; + static const String iconsCalendar = 'assets/icons/calendar.svg'; + static const String iconsCalendarSearch = 'assets/icons/calendar_search.svg'; + static const String iconsCall = 'assets/icons/call.svg'; + static const String iconsDiagram = 'assets/icons/diagram.svg'; + static const String iconsDownload = 'assets/icons/download.svg'; + static const String iconsEdit = 'assets/icons/edit.svg'; + static const String iconsExcelDownload = 'assets/icons/excel_download.svg'; + static const String iconsFilter = 'assets/icons/filter.svg'; + static const String iconsGps = 'assets/icons/gps.svg'; + static const String iconsInformation = 'assets/icons/information.svg'; + static const String iconsInspection = 'assets/icons/inspection.svg'; + static const String iconsKey = 'assets/icons/key.svg'; + static const String iconsLiveStock = 'assets/icons/liveStock.svg'; + static const String iconsLogout = 'assets/icons/logout.svg'; + static const String iconsMap = 'assets/icons/map.svg'; + static const String iconsMapMarker = 'assets/icons/map_marker.svg'; + static const String iconsMessageAdd = 'assets/icons/message_add.svg'; + static const String iconsPdfDownload = 'assets/icons/pdf_download.svg'; + static const String iconsPictureFrame = 'assets/icons/picture_frame.svg'; + static const String iconsPlaceHolder = 'assets/icons/place_holder.svg'; + static const String iconsProfileCircle = 'assets/icons/profile_circle.svg'; + static const String iconsProfileUser = 'assets/icons/profile_user.svg'; + static const String iconsReceiptDiscount = 'assets/icons/receipt_discount.svg'; + static const String iconsScan = 'assets/icons/scan.svg'; + static const String iconsScanBarcode = 'assets/icons/scan_barcode.svg'; + static const String iconsSearch = 'assets/icons/search.svg'; + static const String iconsSecurityTime = 'assets/icons/security_time.svg'; + static const String iconsSetting = 'assets/icons/setting.svg'; + static const String iconsTagUser = 'assets/icons/tag_user.svg'; + static const String iconsTrash = 'assets/icons/trash.svg'; + static const String iconsUser = 'assets/icons/user.svg'; + static const String iconsUserSquare = 'assets/icons/user_square.svg'; + static const String imagesInnerSplash = 'assets/images/inner_splash.webp'; + static const String imagesOutterSplash = 'assets/images/outter_splash.webp'; + static const String imagesPlaceHolder = 'assets/images/place_holder.png'; + static const String vecAddSvg = 'assets/vec/add.svg.vec'; + static const String vecArrowLeftSvg = 'assets/vec/arrow_left.svg.vec'; + static const String vecArrowRightSvg = 'assets/vec/arrow_right.svg.vec'; + static const String vecBgHeaderUserProfileSvg = 'assets/vec/bg_header_user_profile.svg.vec'; + static const String vecCalendarSearchSvg = 'assets/vec/calendar_search.svg.vec'; + static const String vecCalendarSvg = 'assets/vec/calendar.svg.vec'; + static const String vecCallSvg = 'assets/vec/call.svg.vec'; + static const String vecDiagramSvg = 'assets/vec/diagram.svg.vec'; + static const String vecDownloadSvg = 'assets/vec/download.svg.vec'; + static const String vecEditSvg = 'assets/vec/edit.svg.vec'; + static const String vecExcelDownloadSvg = 'assets/vec/excel_download.svg.vec'; + static const String vecFilterSvg = 'assets/vec/filter.svg.vec'; + static const String vecGpsSvg = 'assets/vec/gps.svg.vec'; + static const String vecInformationSvg = 'assets/vec/information.svg.vec'; + static const String vecInspectionSvg = 'assets/vec/inspection.svg.vec'; + static const String vecKeySvg = 'assets/vec/key.svg.vec'; + static const String vecLiveStockSvg = 'assets/vec/liveStock.svg.vec'; + static const String vecLogoutSvg = 'assets/vec/logout.svg.vec'; + static const String vecMapMarkerSvg = 'assets/vec/map_marker.svg.vec'; + static const String vecMapSvg = 'assets/vec/map.svg.vec'; + static const String vecMessageAddSvg = 'assets/vec/message_add.svg.vec'; + static const String vecPdfDownloadSvg = 'assets/vec/pdf_download.svg.vec'; + static const String vecPictureFrameSvg = 'assets/vec/picture_frame.svg.vec'; + static const String vecProfileCircleSvg = 'assets/vec/profile_circle.svg.vec'; + static const String vecProfileUserSvg = 'assets/vec/profile_user.svg.vec'; + static const String vecReceiptDiscountSvg = 'assets/vec/receipt_discount.svg.vec'; + static const String vecScanBarcodeSvg = 'assets/vec/scan_barcode.svg.vec'; + static const String vecScanSvg = 'assets/vec/scan.svg.vec'; + static const String vecSearchSvg = 'assets/vec/search.svg.vec'; + static const String vecSecurityTimeSvg = 'assets/vec/security_time.svg.vec'; + static const String vecSettingSvg = 'assets/vec/setting.svg.vec'; + static const String vecTagUserSvg = 'assets/vec/tag_user.svg.vec'; + static const String vecTrashSvg = 'assets/vec/trash.svg.vec'; + static const String vecUserSquareSvg = 'assets/vec/user_square.svg.vec'; + static const String vecUserSvg = 'assets/vec/user.svg.vec'; + +} diff --git a/packages/core/lib/presentation/common/assets.gen.dart b/packages/core/lib/presentation/common/assets.gen.dart index 815f89f..7604588 100644 --- a/packages/core/lib/presentation/common/assets.gen.dart +++ b/packages/core/lib/presentation/common/assets.gen.dart @@ -84,6 +84,9 @@ class $AssetsIconsGen { /// File path: assets/icons/picture_frame.svg SvgGenImage get pictureFrame => const SvgGenImage('assets/icons/picture_frame.svg'); + /// File path: assets/icons/place_holder.svg + SvgGenImage get placeHolder => const SvgGenImage('assets/icons/place_holder.svg'); + /// File path: assets/icons/profile_circle.svg SvgGenImage get profileCircle => const SvgGenImage('assets/icons/profile_circle.svg'); @@ -145,6 +148,7 @@ class $AssetsIconsGen { messageAdd, pdfDownload, pictureFrame, + placeHolder, profileCircle, profileUser, receiptDiscount, @@ -169,8 +173,11 @@ class $AssetsImagesGen { /// File path: assets/images/outter_splash.webp AssetGenImage get outterSplash => const AssetGenImage('assets/images/outter_splash.webp'); + /// File path: assets/images/place_holder.png + AssetGenImage get placeHolder => const AssetGenImage('assets/images/place_holder.png'); + /// List of all assets - List get values => [innerSplash, outterSplash]; + List get values => [innerSplash, outterSplash, placeHolder]; } class $AssetsVecGen { 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 6db58bb..67bec05 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 @@ -13,6 +13,7 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { final TextStyle? titleTextStyle; final VoidCallback? onBackPressed; final List? additionalActions; + final int? leadingWidth; final Widget? leading; const RAppBar({ @@ -24,8 +25,9 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { this.onBackPressed, this.additionalActions, this.leading, - this.hasBack = false, + this.hasBack = true, this.centerTitle = false, + this.leadingWidth }); @override @@ -41,11 +43,13 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { titleTextStyle ?? AppFonts.yekan16.copyWith(color:Colors.white), title: Text(title), + leadingWidth: leadingWidth?.toDouble(), leading:leading!=null ? Padding( padding: const EdgeInsets.only(right: 16), child: leading, ) : null, + titleSpacing: 8, actions: [ if (additionalActions != null) ...additionalActions!, if(hasBack)...{ diff --git a/packages/core/lib/presentation/widget/buttons/fab.dart b/packages/core/lib/presentation/widget/buttons/fab.dart index 200f0ab..3a33df7 100644 --- a/packages/core/lib/presentation/widget/buttons/fab.dart +++ b/packages/core/lib/presentation/widget/buttons/fab.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; import 'package:rasadyar_core/presentation/utils/color_utils.dart'; + import '../../common/assets.gen.dart'; class RFab extends StatefulWidget { @@ -21,10 +22,7 @@ class RFab extends StatefulWidget { RFab.smallAdd({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.addSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.addSvg.svg(width: 20, height: 20), backgroundColor: AppColor.greenNormal, key: key, ); @@ -32,10 +30,7 @@ class RFab extends StatefulWidget { RFab.add({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.addSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.addSvg.svg(width: 40, height: 40), backgroundColor: AppColor.greenNormal, key: key, ); @@ -46,10 +41,7 @@ class RFab extends StatefulWidget { RFab.smallEdit({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.addSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.addSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -57,10 +49,7 @@ class RFab extends StatefulWidget { RFab.edit({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.addSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.addSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -71,10 +60,7 @@ class RFab extends StatefulWidget { RFab.smallDelete({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.trashSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.trashSvg.svg(width: 20, height: 20), backgroundColor: AppColor.redNormal, key: key, ); @@ -82,10 +68,7 @@ class RFab extends StatefulWidget { RFab.delete({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.trashSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.trashSvg.svg(width: 20, height: 20), backgroundColor: AppColor.redNormal, key: key, ); @@ -96,10 +79,7 @@ class RFab extends StatefulWidget { RFab.smallAction({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.scanSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.scanSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -107,10 +87,7 @@ class RFab extends StatefulWidget { RFab.action({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.scanSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.scanSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -121,10 +98,7 @@ class RFab extends StatefulWidget { RFab.smallFilter({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.scanSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.scanSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -132,10 +106,7 @@ class RFab extends StatefulWidget { RFab.filter({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.scanSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.scanSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -146,10 +117,7 @@ class RFab extends StatefulWidget { RFab.smallDownload({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.downloadSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.downloadSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -157,10 +125,7 @@ class RFab extends StatefulWidget { RFab.download({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.downloadSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.downloadSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -171,10 +136,7 @@ class RFab extends StatefulWidget { RFab.smallExcel({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.excelDownloadSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.excelDownloadSvg.svg(width: 20, height: 20), backgroundColor: AppColor.greenDark, key: key, ); @@ -182,10 +144,7 @@ class RFab extends StatefulWidget { RFab.excel({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.excelDownloadSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.excelDownloadSvg.svg(width: 20, height: 20), backgroundColor: AppColor.greenDark, key: key, ); @@ -196,10 +155,7 @@ class RFab extends StatefulWidget { RFab.smallBack({required VoidCallback? onPressed, Key? key}) : this.small( onPressed: onPressed, - icon: Assets.vec.arrowLeftSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.arrowLeftSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); @@ -207,10 +163,7 @@ class RFab extends StatefulWidget { RFab.back({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: Assets.vec.arrowLeftSvg.svg( - width: 20, - height: 20, - ), + icon: Assets.vec.arrowLeftSvg.svg(width: 20, height: 20), backgroundColor: AppColor.blueNormal, key: key, ); diff --git a/packages/core/lib/presentation/widget/buttons/outline_elevated_icon.dart b/packages/core/lib/presentation/widget/buttons/outline_elevated_icon.dart index 7afef0e..d4c57a0 100644 --- a/packages/core/lib/presentation/widget/buttons/outline_elevated_icon.dart +++ b/packages/core/lib/presentation/widget/buttons/outline_elevated_icon.dart @@ -32,10 +32,10 @@ class ROutlinedElevatedIcon extends StatefulWidget { Widget? icon; @override - State createState() => _ROutlinedElevatedStateIcon(); + State createState() => _ROutlinedElevatedIconState(); } -class _ROutlinedElevatedStateIcon extends State { +class _ROutlinedElevatedIconState extends State { @override Widget build(BuildContext context) { return OutlinedButton.icon( diff --git a/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet2.dart b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet2.dart new file mode 100644 index 0000000..91826d5 --- /dev/null +++ b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet2.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'draggable_bottom_sheet_controller.dart'; + + +class DraggableBottomSheet2 extends GetView { + final Color? backgroundColor; + + const DraggableBottomSheet2({super.key, this.backgroundColor = Colors.white}); + + @override + Widget build(BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (controller.isVisible.value && !controller.isVisible.value) { + controller.show(); + } + }); + + return ObxValue((data) { + return Stack( + children: [ + // پس‌زمینه تیره + Positioned.fill( + child: GestureDetector( + onTap: () {}, + child: Container(color: Colors.black54), + ), + ), + // محتوای BottomSheet + AnimatedPositioned( + duration: Duration(milliseconds: 300), + curve: Curves.easeOut, + left: 0, + right: 0, + bottom: 0, + child: GestureDetector( + onVerticalDragUpdate: (details) { + controller.updateHeight(details.primaryDelta); + }, + child: Container( + height: 350, + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.vertical(top: Radius.circular(20)), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.1), + blurRadius: 10, + ), + ], + ), + child: Column( + children: [ + GestureDetector( + onTap: () {}, + child: Container( + padding: EdgeInsets.all(10), + child: Icon(Icons.drag_handle), + ), + ), + Expanded( + child: controller.items[data.value], + ), + ], + ), + ), + ), + ), + ], + ); + }, controller.currentIndex); + } +} diff --git a/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart index 5a1caef..2bf39e1 100644 --- a/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart +++ b/packages/core/lib/presentation/widget/draggable_bottom_sheet/draggable_bottom_sheet_controller.dart @@ -129,7 +129,8 @@ import 'draggable_bottom_sheet.dart'; class DraggableBottomSheetController extends GetxController { final RxBool isVisible = false.obs; final RxDouble currentHeight = 200.0.obs; - + RxList items = [].obs; + RxInt currentIndex = 0.obs; late double initialHeight; late double minHeight; late double maxHeight; @@ -158,9 +159,5 @@ class DraggableBottomSheetController extends GetxController { } } - @override - void onInit() { - super.onInit(); - } } diff --git a/packages/core/lib/presentation/widget/map/custom_marker.dart b/packages/core/lib/presentation/widget/map/custom_marker.dart new file mode 100644 index 0000000..d1e5cae --- /dev/null +++ b/packages/core/lib/presentation/widget/map/custom_marker.dart @@ -0,0 +1,10 @@ +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/logic.dart b/packages/core/lib/presentation/widget/map/logic.dart index 0824b14..78ab225 100644 --- a/packages/core/lib/presentation/widget/map/logic.dart +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:flutter/animation.dart'; +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'; @@ -8,13 +8,16 @@ import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; import 'package:rasadyar_core/utils/logger_utils.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'; - RxList markers = [].obs; + + RxList markers = [].obs; RxList allMarkers = [].obs; Rx mapController = MapController().obs; RxList errorLocationType = RxList(); @@ -61,6 +64,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { @override void onClose() { super.onClose(); + _debounceTimer?.cancel(); animatedMapController.dispose(); mapController.close(); } @@ -113,7 +117,9 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { final latLng = LatLng(position.latitude, position.longitude); currentLocation.value = latLng; - markers.add(latLng); + markers.add( + CustomMarker(id: -1, point: latLng, ), + ); animatedMapController.animateTo( dest: latLng, zoom: 18, @@ -132,7 +138,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { 'radius': 1000.0, }); - markers.addAll(filtered); + // markers.addAll(filtered); }); } @@ -148,4 +154,17 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { .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/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart index 8fe6cc2..4204919 100644 --- a/packages/core/lib/presentation/widget/map/view.dart +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; -import 'package:latlong2/latlong.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'; @@ -13,7 +12,16 @@ import 'package:rasadyar_core/presentation/widget/buttons/outline_elevated.dart' import 'logic.dart'; class MapWidget extends GetView { - const MapWidget({super.key}); + 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) { @@ -48,8 +56,7 @@ class MapWidget extends GetView { onPressed: () async { var res = await Geolocator.openLocationSettings(); if (res) { - var service = - await controller.locationServiceEnabled(); + var service = await controller.locationServiceEnabled(); if (service) { controller.errorLocationType.remove( ErrorLocationType.serviceDisabled, @@ -59,7 +66,6 @@ class MapWidget extends GetView { } }, ), - contentPadding: EdgeInsets.all(8), onWillPop: () async { return controller.errorLocationType.isEmpty; @@ -71,9 +77,7 @@ class MapWidget extends GetView { Future.microtask(() { Get.defaultDialog( title: 'خطا', - content: const Text( - ' دسترسی به سرویس مکان‌یابی غیرفعال است', - ), + content: const Text(' دسترسی به سرویس مکان‌یابی غیرفعال است'), cancel: ROutlinedElevated( text: 'بررسی مجدد', width: 120, @@ -87,9 +91,7 @@ class MapWidget extends GetView { textStyle: AppFonts.yekan16, width: 120, onPressed: () async { - var res = await controller.checkPermission( - request: true, - ); + var res = await controller.checkPermission(request: true); if (res) { controller.errorLocationType.remove( ErrorLocationType.permissionDenied, @@ -110,7 +112,10 @@ class MapWidget extends GetView { } return const SizedBox.shrink(); }, controller.errorLocationType), - _buildMap(), _buildGpsButton(), _buildFilterButton()], + _buildMap(), + _buildGpsButton(), + _buildFilterButton(), + ], ); } @@ -122,16 +127,30 @@ class MapWidget extends GetView { initialCenter: currentLocation.value, initialZoom: 18, onPositionChanged: (camera, hasGesture) { - controller.debouncedUpdateVisibleMarkers(center: camera.center); + if (hasGesture) { + controller.debouncedUpdateVisibleMarkers(center: camera.center); + } + //controller.debouncedUpdateVisibleMarkers(center: camera.center); }, ), children: [ TileLayer(urlTemplate: controller.tileType), - ObxValue((markers) { + ObxValue((markers) { return MarkerLayer( markers: markers - .map((e) => markerWidget(marker: e, onTap: () {})) + .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), @@ -171,21 +190,18 @@ class MapWidget extends GetView { ); } - Marker markerWidget({required LatLng marker, required VoidCallback onTap}) { + /*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, - ) + width: 36, + height: 36, + child: Assets.vec.mapMarkerSvg.svg(width: 30, height: 30), ), ), ); - } + }*/ } diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 546efec..bdcab01 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -6,6 +6,7 @@ export 'buttons/outline_elevated.dart'; export 'buttons/outline_elevated_icon.dart'; export 'buttons/text_button.dart'; export 'draggable_bottom_sheet/draggable_bottom_sheet.dart'; +export 'draggable_bottom_sheet/draggable_bottom_sheet2.dart'; export 'draggable_bottom_sheet/draggable_bottom_sheet_controller.dart'; export 'draggable_bottom_sheet/bottom_sheet_manger.dart'; export 'inputs/r_input.dart'; diff --git a/packages/livestock/lib/presentation/page/map/logic.dart b/packages/livestock/lib/presentation/page/map/logic.dart index c54ed07..04370f3 100644 --- a/packages/livestock/lib/presentation/page/map/logic.dart +++ b/packages/livestock/lib/presentation/page/map/logic.dart @@ -2,7 +2,7 @@ import 'package:rasadyar_core/core.dart'; class MapLogic extends GetxController { - + var ss = Get.find(); } diff --git a/packages/livestock/lib/presentation/page/map/view.dart b/packages/livestock/lib/presentation/page/map/view.dart index d05b39f..6935217 100644 --- a/packages/livestock/lib/presentation/page/map/view.dart +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter/material.dart' as mt; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/presentation/widget/map/view.dart'; - - import 'logic.dart'; class MapPage extends GetView { @@ -14,9 +11,20 @@ class MapPage extends GetView { return Scaffold( body: Stack( children: [ - MapWidget(), + MapWidget( + markerWidget: Icon(Icons.pin_drop_rounded), + initOnTap: () { + + }, + initMarkerWidget: Assets.vec.mapMarkerSvg.svg( + width: 30, + height: 30, + ), + ), + ], ), ); } -} \ No newline at end of file +} + diff --git a/packages/livestock/lib/presentation/page/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart index ee5f9ee..de94cdb 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -1,9 +1,10 @@ +import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; class RequestTaggingLogic extends GetxController { - +final TextEditingController phoneController = TextEditingController(); @override void onReady() { super.onReady(); diff --git a/packages/livestock/lib/presentation/page/request_tagging/view.dart b/packages/livestock/lib/presentation/page/request_tagging/view.dart index 67d773a..0ff57ed 100644 --- a/packages/livestock/lib/presentation/page/request_tagging/view.dart +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -1,5 +1,7 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; import 'logic.dart'; @@ -9,37 +11,98 @@ class RequestTaggingPage extends GetView { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Request Tagging'), - centerTitle: true, - actions: [ - IconButton( - icon: const Icon(Icons.search), - onPressed: () { - // Implement search functionality - }, - ), - ], + backgroundColor: Colors.white, + appBar: RAppBar( + title: 'درخواست پلاک کوبی', + leadingWidth: 40, + leading: Assets.vec.messageAddSvg.svg(width: 12, height: 12), ), - body: Column( - children: [ - const SizedBox(height: 16), - - const SizedBox(height: 16), - Expanded( - child: ListView.builder( - itemCount: 10, // Replace with your data length - itemBuilder: (context, index) { - return ListTile( - title: Text('Request Item $index'), - onTap: () { - // Handle item tap - }, - ); - }, + body: Padding( + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15), + child: 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/requests/view.dart b/packages/livestock/lib/presentation/page/requests/view.dart index 966ea7c..b656387 100644 --- a/packages/livestock/lib/presentation/page/requests/view.dart +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -93,7 +93,7 @@ class RequestsPage extends GetView { itemBuilder: (context, index) { return GestureDetector( onTap: () { - Get.toNamed(LiveStockRoutes.requestTagging,id: 0); + Get.toNamed(LiveStockRoutes.requestTagging); }, child: Container( width: Get.width, diff --git a/packages/livestock/lib/presentation/page/root/view.dart b/packages/livestock/lib/presentation/page/root/view.dart index 879add1..f506375 100644 --- a/packages/livestock/lib/presentation/page/root/view.dart +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -9,6 +9,7 @@ class RootPage extends GetView { @override Widget build(BuildContext context) { return ObxValue((currentIndex) { + return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { @@ -16,7 +17,6 @@ class RootPage extends GetView { eLog('Pop invoked with result: $result, didPop: $didPop'); navigatorKey?.currentState?.pop(); - /*eLog('Pop invoked with result: $result, didPop: $didPop'); iLog(Get.currentRoute); iLog(Get.previousRoute); @@ -39,11 +39,11 @@ class RootPage extends GetView { child: Scaffold( body: IndexedStack( - children: controller.pages, + children: [...controller.pages], index: currentIndex.value, sizing: StackFit.expand, ), - + extendBody: true, bottomNavigationBar: BottomNavigation1( items: [ BottomNavigation1Item( diff --git a/packages/livestock/lib/presentation/page/tagging/logic.dart b/packages/livestock/lib/presentation/page/tagging/logic.dart new file mode 100644 index 0000000..f543973 --- /dev/null +++ b/packages/livestock/lib/presentation/page/tagging/logic.dart @@ -0,0 +1,15 @@ +import 'package:get/get.dart'; + +class TaggingLogic extends GetxController { + @override + void onReady() { + // TODO: implement onReady + super.onReady(); + } + + @override + void onClose() { + // TODO: implement onClose + super.onClose(); + } +} diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart new file mode 100644 index 0000000..6bb7f25 --- /dev/null +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -0,0 +1,239 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; + +import 'logic.dart'; + +class TaggingPage extends GetView { + const TaggingPage({super.key}); + + @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(horizontal: 10, vertical: 15), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Container( + height: 40, + decoration: BoxDecoration( + color: AppColor.greenLightHover, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight), + ), + alignment: Alignment.center, + child: Text('آمار ثبت شده : سبک 5 و سنگین 8 راس'), + ), + ), + SizedBox(width: 4), + IconButton( + onPressed: () {}, + style: IconButton.styleFrom( + backgroundColor: AppColor.blueNormal, + fixedSize: Size(40, 40), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + icon: Assets.vec.editSvg.svg(), + ), + ], + ), + + Expanded( + child: Card( + clipBehavior: Clip.hardEdge, + color: Colors.white, + child: Stack( + fit: StackFit.expand, + children: [ + GridView.builder( + padding: EdgeInsets.symmetric( + horizontal: 20, + vertical: 10, + ), + itemCount: 20, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 12, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + return Container( + decoration: ShapeDecoration( + color: AppColor.lightGreyLightHover, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1, + color: AppColor.blackLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode( + AppColor.blueNormal, + BlendMode.srcIn, + ), + ), + Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode( + AppColor.error, + BlendMode.srcIn, + ), + ), + ], + ), + Text( + 'گوسفند ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + SizedBox(height: 10), + Text( + 'سن : 18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith( + color: AppColor.darkGreyNormal, + ), + ), + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith( + color: AppColor.bgDark, + ), + ), + Text( + '1212115112512', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith( + color: AppColor.blueNormal, + ), + ), + Text( + 'نوع پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith( + color: AppColor.bgDark, + ), + ), + ], + ), + ), + ); + }, + ), + + Positioned( + bottom: 10, + right: 3, + child: RFab.add( + onPressed: () { + Get.bottomSheet( + Container( + padding: EdgeInsets.all(20), + color: Colors.white, + height: 300, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: 40, + width: Get.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 1, + color: AppColor.darkGreyLight, + ), + ), + child: GestureDetector( + onTap: () { + + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'گونه دام', + style: AppFonts.yekan14, + ), + Icon(CupertinoIcons.chevron_up), + ], + ), + ), + ), + /* DropdownMenu( + width: Get.width, + + dropdownMenuEntries: [ + DropdownMenuEntry( + value: 'گوسفند', + label: 'گوسفند', + ), + DropdownMenuEntry( + value: 'بز', + label: 'بز', + ), + DropdownMenuEntry( + value: 'گوساله', + label: 'گوساله', + ), + ], + ),*/ + ], + ), + ), + isScrollControlled: true, + ); + }, + ), + ), + ], + ), + ), + ), + + SizedBox(height: 10), + + RElevated( + text: 'ثبت نهایی و ارسال به اتحادیه', + textStyle: AppFonts.yekan18, + height: 40, + backgroundColor: AppColor.greenNormal, + onPressed: () {}, + isFullWidth: true, + ), + ], + ), + ), + ); + } +} diff --git a/packages/livestock/lib/presentation/routes/app_pages.dart b/packages/livestock/lib/presentation/routes/app_pages.dart index b74d313..1ca33e7 100644 --- a/packages/livestock/lib/presentation/routes/app_pages.dart +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -8,6 +8,8 @@ import 'package:rasadyar_livestock/presentation/page/request_tagging/view.dart'; import 'package:rasadyar_livestock/presentation/page/requests/logic.dart'; 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'; part 'app_routes.dart'; @@ -26,18 +28,35 @@ sealed class LiveStockPages { Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => ProfileLogic()); Get.lazyPut(() => MapWidgetLogic()); + Get.lazyPut(() => DraggableBottomSheetController()); }), children: [ - GetPage( + /*GetPage( name: LiveStockRoutes.requestTagging, page: () => RequestTaggingPage(), middlewares: [AuthMiddleware()], binding: BindingsBuilder(() { Get.lazyPut(() => RequestTaggingLogic()); }), - ), - ] + ),*/ + ], ), + GetPage( + name: LiveStockRoutes.requestTagging, + page: () => RequestTaggingPage(), + middlewares: [AuthMiddleware()], + binding: BindingsBuilder(() { + Get.lazyPut(() => RequestTaggingLogic()); + }), + ), + GetPage( + name: LiveStockRoutes.tagging, + page: () => TaggingPage(), + middlewares: [AuthMiddleware()], + binding: BindingsBuilder(() { + Get.lazyPut(() => TaggingLogic()); + }), + ), ]; } diff --git a/packages/livestock/lib/presentation/routes/app_routes.dart b/packages/livestock/lib/presentation/routes/app_routes.dart index 616d5ee..95a777a 100644 --- a/packages/livestock/lib/presentation/routes/app_routes.dart +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -6,5 +6,8 @@ sealed class LiveStockRoutes { static const init = '/liveStock'; static const requests = '/requests'; static const profile = '/profile'; - static const requestTagging = '$init/tagging'; + + //static const requestTagging = '$init/tagging'; + static const requestTagging = '$requests/tagging'; + static const tagging = '/tagging'; } From 5ca69760e64d467aaf33b47de8f0a88fc3871bf8 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:11:12 +0330 Subject: [PATCH 12/25] feat : new text input with fixed hint --- .../widget/inputs/input_fixed_hint.dart | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 packages/core/lib/presentation/widget/inputs/input_fixed_hint.dart diff --git a/packages/core/lib/presentation/widget/inputs/input_fixed_hint.dart b/packages/core/lib/presentation/widget/inputs/input_fixed_hint.dart new file mode 100644 index 0000000..ad4004b --- /dev/null +++ b/packages/core/lib/presentation/widget/inputs/input_fixed_hint.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; + +import '../../common/app_color.dart'; +import '../../common/app_fonts.dart' show AppFonts; + +enum InputType { text, number, email, password } + +class TextFiledFixedHint extends StatefulWidget { + const TextFiledFixedHint({ + super.key, + required this.hintText, + required this.onChanged, + this.inputType = InputType.text, + this.initialValue, + this.controller, + this.keyboardType, + this.textInputAction, + this.enabled, + this.readOnly, + this.maxLines, + this.minLines, + }); + + final String hintText; + final InputType inputType; + + final ValueChanged? onChanged; + final String? initialValue; + final TextEditingController? controller; + final TextInputType? keyboardType; + final TextInputAction? textInputAction; + final bool? enabled; + final bool? readOnly; + final int? maxLines; + final int? minLines; + + @override + State createState() => _TextFiledFixedHintState(); +} + +class _TextFiledFixedHintState extends State { + TextEditingController? tmpController; + + @override + void initState() { + super.initState(); + if (widget.controller == null) { + tmpController = TextEditingController(text: widget.initialValue); + if (widget.initialValue != null) { + tmpController?.text = widget.initialValue!; + } + } else { + tmpController = widget.controller; + } + } + + @override + Widget build(BuildContext context) { + return Container( + height: 40, + width: MediaQuery.of(context).size.width, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + border: Border.all(color: AppColor.darkGreyLight), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only(top: 3), + child: Text(widget.hintText, style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive)), + ), + Expanded( + child: TextField( + controller: tmpController, + keyboardType: widget.inputType == InputType.number ? TextInputType.number : widget.keyboardType, + textInputAction: widget.textInputAction, + onChanged: widget.onChanged, + enabled: widget.enabled, + readOnly: widget.readOnly ?? false, + maxLines: widget.maxLines ?? 1, + minLines: widget.minLines ?? 1, + cursorHeight: 25, + textAlignVertical: TextAlignVertical.top, + obscureText: widget.inputType == InputType.password, + textAlign: widget.inputType == InputType.number ? TextAlign.start : TextAlign.start, + textDirection: widget.inputType == InputType.number ? TextDirection.ltr : TextDirection.rtl, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive), + decoration: InputDecoration(border: InputBorder.none), + ), + ), + ], + ), + ); + } +} From 363e810070813d113b34e314cc67eb97a40ca2b6 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:11:33 +0330 Subject: [PATCH 13/25] feat : overlay dropdown list --- .../widget/overlay_dropdown_widget/view.dart | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 packages/core/lib/presentation/widget/overlay_dropdown_widget/view.dart diff --git a/packages/core/lib/presentation/widget/overlay_dropdown_widget/view.dart b/packages/core/lib/presentation/widget/overlay_dropdown_widget/view.dart new file mode 100644 index 0000000..8d8496d --- /dev/null +++ b/packages/core/lib/presentation/widget/overlay_dropdown_widget/view.dart @@ -0,0 +1,143 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:rasadyar_core/presentation/common/app_color.dart'; +import 'package:rasadyar_core/presentation/common/app_fonts.dart'; + + + +class OverlayDropdownWidget extends StatefulWidget { + final List items; + final T? selectedItem; + final T? initialValue; + final Widget Function(T item) itemBuilder; + final Widget Function(T? selected) labelBuilder; + final void Function(T selected)? onChanged; + final EdgeInsets? contentPadding; + + const OverlayDropdownWidget({ + super.key, + required this.items, + required this.itemBuilder, + required this.labelBuilder, + this.initialValue, + this.onChanged, + this.selectedItem, + this.contentPadding + }); + + @override + State> createState() => _OverlayDropdownState(); +} + +class _OverlayDropdownState extends State> { + final GlobalKey _key = GlobalKey(); + OverlayEntry? _overlayEntry; + final RxBool _isOpen = false.obs; + T? selectedItem ; + + @override + void initState() { + super.initState(); + selectedItem = widget.selectedItem ?? widget.initialValue; + } + + void _showOverlay() { + final renderBox = _key.currentContext!.findRenderObject() as RenderBox; + final size = renderBox.size; + final offset = renderBox.localToGlobal(Offset.zero); + + _overlayEntry = OverlayEntry( + builder: + (_) => GestureDetector( + onTap: _removeOverlay, + behavior: HitTestBehavior.translucent, + child: Stack( + children: [ + Positioned( + left: offset.dx, + top: offset.dy + size.height + 4, + width: size.width, + child: Material( + elevation: 4, + borderRadius: BorderRadius.circular(8), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: AppColor.darkGreyLight), + borderRadius: BorderRadius.circular(8), + ), + child: ListView( + padding: EdgeInsets.zero, + shrinkWrap: true, + children: + widget.items.map((item) { + return InkWell( + onTap: () { + widget.onChanged?.call(item); + setState(() { + selectedItem = item; + }); + _removeOverlay(); + }, + child: Padding( + padding:widget.contentPadding?? const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: widget.itemBuilder(item), + ), + ); + }).toList(), + ), + ), + ), + ), + ], + ), + ), + ); + + Overlay.of(context).insert(_overlayEntry!); + _isOpen.value = true; + } + + void _removeOverlay() { + _overlayEntry?.remove(); + _overlayEntry = null; + _isOpen.value = false; + } + + @override + void dispose() { + _removeOverlay(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + key: _key, + onTap: () { + _isOpen.value ? _removeOverlay() : _showOverlay(); + }, + 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: [ + widget.labelBuilder(selectedItem), + Icon( + _isOpen.value + ? CupertinoIcons.chevron_up + : CupertinoIcons.chevron_down, + ), + ], + ), + ), + ); + } +} From 3e868e415848c08cede612786fb69a0346be1197 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:11:51 +0330 Subject: [PATCH 14/25] fix : font size --- packages/core/lib/presentation/widget/buttons/elevated.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/lib/presentation/widget/buttons/elevated.dart b/packages/core/lib/presentation/widget/buttons/elevated.dart index bcbe124..01f9743 100644 --- a/packages/core/lib/presentation/widget/buttons/elevated.dart +++ b/packages/core/lib/presentation/widget/buttons/elevated.dart @@ -49,7 +49,7 @@ class RElevated extends StatelessWidget { ), minimumSize: Size(isFullWidth ? double.infinity : width, height), padding: EdgeInsets.zero, - textStyle: textStyle ?? AppFonts.yekan24, + textStyle: textStyle ?? AppFonts.yekan18, ), child: isLoading From b1f08ce0dc1ffafc0e814d46472911cdd160a7ea Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:12:30 +0330 Subject: [PATCH 15/25] chore: barrel new widget --- packages/core/lib/presentation/widget/widget.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index bdcab01..8888a00 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -17,3 +17,5 @@ export 'tabs/tab.dart'; export 'vec_widget.dart'; export 'card/card_with_icon_with_border.dart'; export 'chips/r_chips.dart'; +export 'overlay_dropdown_widget/view.dart'; +export 'inputs/input_fixed_hint.dart'; From 2dbe8a2489a036559c72a568ee974ab4ea4a585c Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:13:07 +0330 Subject: [PATCH 16/25] feat : tagging page and add livestock tagging --- .../lib/presentation/page/tagging/logic.dart | 4 +- .../lib/presentation/page/tagging/view.dart | 447 +++++++++++------- 2 files changed, 290 insertions(+), 161 deletions(-) diff --git a/packages/livestock/lib/presentation/page/tagging/logic.dart b/packages/livestock/lib/presentation/page/tagging/logic.dart index f543973..c60d7ff 100644 --- a/packages/livestock/lib/presentation/page/tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/tagging/logic.dart @@ -1,6 +1,8 @@ -import 'package:get/get.dart'; +import 'package:rasadyar_core/core.dart'; class TaggingLogic extends GetxController { + RxInt selectedSegment = 0.obs; + @override void onReady() { // TODO: implement onReady diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart index 6bb7f25..19babe1 100644 --- a/packages/livestock/lib/presentation/page/tagging/view.dart +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -37,15 +37,18 @@ class TaggingPage extends GetView { ), SizedBox(width: 4), IconButton( - onPressed: () {}, + onPressed:() { + Get.bottomSheet( + _buildBottomSheet(), + isScrollControlled: true, + ); + }, style: IconButton.styleFrom( backgroundColor: AppColor.blueNormal, fixedSize: Size(40, 40), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), - icon: Assets.vec.editSvg.svg(), + icon: Assets.vec.addSvg.svg(), ), ], ), @@ -54,169 +57,74 @@ class TaggingPage extends GetView { child: Card( clipBehavior: Clip.hardEdge, color: Colors.white, - child: Stack( - fit: StackFit.expand, - children: [ - GridView.builder( - padding: EdgeInsets.symmetric( - horizontal: 20, - vertical: 10, + child: GridView.builder( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + itemCount: 20, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 12, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + return Container( + decoration: ShapeDecoration( + color: AppColor.lightGreyLightHover, + shape: RoundedRectangleBorder( + side: BorderSide(width: 1, color: AppColor.blackLightHover), + borderRadius: BorderRadius.circular(8), + ), ), - itemCount: 20, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 12, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - return Container( - decoration: ShapeDecoration( - color: AppColor.lightGreyLightHover, - shape: RoundedRectangleBorder( - side: BorderSide( - width: 1, - color: AppColor.blackLightHover, - ), - borderRadius: BorderRadius.circular(8), - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Assets.vec.editSvg.svg( - width: 16, - height: 16, - colorFilter: ColorFilter.mode( - AppColor.blueNormal, - BlendMode.srcIn, - ), - ), - Assets.vec.trashSvg.svg( - width: 16, - height: 16, - colorFilter: ColorFilter.mode( - AppColor.error, - BlendMode.srcIn, - ), - ), - ], + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), ), - Text( - 'گوسفند ماده', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith( - color: AppColor.blueNormal, - ), - ), - SizedBox(height: 10), - Text( - 'سن : 18 ماه', - textAlign: TextAlign.center, - style: AppFonts.yekan12.copyWith( - color: AppColor.darkGreyNormal, - ), - ), - Text( - 'نوع نژاد', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith( - color: AppColor.bgDark, - ), - ), - Text( - '1212115112512', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith( - color: AppColor.blueNormal, - ), - ), - Text( - 'نوع پلاک', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith( - color: AppColor.bgDark, - ), + Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), ), ], ), - ), - ); - }, - ), - - Positioned( - bottom: 10, - right: 3, - child: RFab.add( - onPressed: () { - Get.bottomSheet( - Container( - padding: EdgeInsets.all(20), - color: Colors.white, - height: 300, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: 40, - width: Get.width, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), - border: Border.all( - width: 1, - color: AppColor.darkGreyLight, - ), - ), - child: GestureDetector( - onTap: () { - - }, - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - 'گونه دام', - style: AppFonts.yekan14, - ), - Icon(CupertinoIcons.chevron_up), - ], - ), - ), - ), - /* DropdownMenu( - width: Get.width, - - dropdownMenuEntries: [ - DropdownMenuEntry( - value: 'گوسفند', - label: 'گوسفند', - ), - DropdownMenuEntry( - value: 'بز', - label: 'بز', - ), - DropdownMenuEntry( - value: 'گوساله', - label: 'گوساله', - ), - ], - ),*/ - ], - ), + Text( + 'گوسفند ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), ), - isScrollControlled: true, - ); - }, + SizedBox(height: 10), + Text( + 'سن : 18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyNormal), + ), + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), + ), + Text( + '1212115112512', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), + ), + Text( + 'نوع پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), + ), + ], + ), ), - ), - ], + ); + }, ), ), ), @@ -236,4 +144,223 @@ class TaggingPage extends GetView { ), ); } + + Container _buildBottomSheet() { + return Container( + padding: EdgeInsets.all(20), + + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(25), + topRight: Radius.circular(25), + ), + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 8, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 3, + width: 50, + decoration: BoxDecoration( + color: AppColor.darkGreyDark, + borderRadius: BorderRadius.circular(8), + ), + ), + ], + ), + + SizedBox(height: 3), + + OverlayDropdownWidget( + items: [ + 'گوسفند ماده', + 'گوسفند نر', + 'بز ماده', + 'بز نر', + 'گوساله ماده', + 'گوساله نر', + ], + onChanged: (value) { + print('Selected: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'گونه دام'), + ), + 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), + ), + ], + ), + ), + ObxValue((data) { + return 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), + + OverlayDropdownWidget( + items: ['نوع نژاد 1', 'نوع نژاد 2', 'نوع نژاد 3'], + onChanged: (value) { + print('Selected Breed: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'نژاد'), + ), + + TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک مادر ', + onChanged: (String value) { + eLog('Mother Tag: $value'); + }, + ), + TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک پدر ', + onChanged: (String value) { + eLog('father Tag: $value'); + }, + ), + TextFiledFixedHint( + inputType: InputType.number, + hintText: 'پلاک دام', + onChanged: (String value) { + eLog('father Tag: $value'); + }, + ), + OverlayDropdownWidget( + items: ['نوع پلاک 1', 'نوع پلاک 2', 'نوع پلاک 3'], + onChanged: (value) { + print('Selected Breed: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'نوع پلاک'), + ), + + 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), + ], + ), + ), + ), + ], + ), + ), + ), + ), + + 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(); + }, + ), + ), + ], + ), + ), + ); + } } From 2898cc8fbf6a2116eb11417d58f0a8933d0c6124 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:43:59 +0330 Subject: [PATCH 17/25] feat : base widget for bottom sheet --- .../bottom_sheet/base_bottom_sheet.dart | 57 +++++++++++++++++++ .../core/lib/presentation/widget/widget.dart | 1 + 2 files changed, 58 insertions(+) create mode 100644 packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart diff --git a/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart new file mode 100644 index 0000000..e628b35 --- /dev/null +++ b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart @@ -0,0 +1,57 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/presentation/common/app_color.dart'; + +class BaseBottomSheet extends StatelessWidget { + const BaseBottomSheet({super.key, required this.child}); + + final Widget child; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.symmetric(vertical: 15, horizontal: 20), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), + ), + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 8, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width, + height: 20, + child: Stack( + alignment: AlignmentDirectional.center, + children: [ + Container( + height: 3, + width: 50, + decoration: BoxDecoration(color: AppColor.darkGreyDark, borderRadius: BorderRadius.circular(8)), + ), + + Positioned( + left: 0, + child: IconButton( + onPressed: () { + Navigator.of(context).pop(); + }, + icon: Icon(CupertinoIcons.clear_circled), + ), + ), + ], + ), + ), + + SizedBox(height: 2), + + child, + ], + ), + ), + ); + } +} diff --git a/packages/core/lib/presentation/widget/widget.dart b/packages/core/lib/presentation/widget/widget.dart index 8888a00..52c3f21 100644 --- a/packages/core/lib/presentation/widget/widget.dart +++ b/packages/core/lib/presentation/widget/widget.dart @@ -19,3 +19,4 @@ export 'card/card_with_icon_with_border.dart'; export 'chips/r_chips.dart'; export 'overlay_dropdown_widget/view.dart'; export 'inputs/input_fixed_hint.dart'; +export 'bottom_sheet/base_bottom_sheet.dart'; From 1c2e4822979616896fa613ce6ddbc38d5c1ceee7 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 12:46:15 +0330 Subject: [PATCH 18/25] refactor : extract to widget's --- .../lib/presentation/page/tagging/view.dart | 421 +++++++++--------- 1 file changed, 200 insertions(+), 221 deletions(-) diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart index 19babe1..9dcd936 100644 --- a/packages/livestock/lib/presentation/page/tagging/view.dart +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:rasadyar_core/core.dart'; -import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; import 'logic.dart'; @@ -37,11 +36,8 @@ class TaggingPage extends GetView { ), SizedBox(width: 4), IconButton( - onPressed:() { - Get.bottomSheet( - _buildBottomSheet(), - isScrollControlled: true, - ); + onPressed: () { + Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); }, style: IconButton.styleFrom( backgroundColor: AppColor.blueNormal, @@ -145,222 +141,205 @@ class TaggingPage extends GetView { ); } - Container _buildBottomSheet() { + 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(); + }, + ), + ), + ], + ), + ); + } + + 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), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } + + 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( - padding: EdgeInsets.all(20), + 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)), + ], + ), + ); + } - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(25), - topRight: Radius.circular(25), - ), - ), - child: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - spacing: 8, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 3, - width: 50, - decoration: BoxDecoration( - color: AppColor.darkGreyDark, - borderRadius: BorderRadius.circular(8), - ), - ), - ], - ), - - SizedBox(height: 3), - - OverlayDropdownWidget( - items: [ - 'گوسفند ماده', - 'گوسفند نر', - 'بز ماده', - 'بز نر', - 'گوساله ماده', - 'گوساله نر', - ], - onChanged: (value) { - print('Selected: $value'); - }, - itemBuilder: (item) => Text(item), - labelBuilder: (item) => Text(item ?? 'گونه دام'), - ), - 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), - ), - ], - ), - ), - ObxValue((data) { - return 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), - - OverlayDropdownWidget( - items: ['نوع نژاد 1', 'نوع نژاد 2', 'نوع نژاد 3'], - onChanged: (value) { - print('Selected Breed: $value'); - }, - itemBuilder: (item) => Text(item), - labelBuilder: (item) => Text(item ?? 'نژاد'), - ), - - TextFiledFixedHint( - inputType: InputType.number, - hintText: 'پلاک مادر ', - onChanged: (String value) { - eLog('Mother Tag: $value'); - }, - ), - TextFiledFixedHint( - inputType: InputType.number, - hintText: 'پلاک پدر ', - onChanged: (String value) { - eLog('father Tag: $value'); - }, - ), - TextFiledFixedHint( - inputType: InputType.number, - hintText: 'پلاک دام', - onChanged: (String value) { - eLog('father Tag: $value'); - }, - ), - OverlayDropdownWidget( - items: ['نوع پلاک 1', 'نوع پلاک 2', 'نوع پلاک 3'], - onChanged: (value) { - print('Selected Breed: $value'); - }, - itemBuilder: (item) => Text(item), - labelBuilder: (item) => Text(item ?? 'نوع پلاک'), - ), - - 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), - ], - ), - ), - ), - ], - ), - ), - ), - ), - - 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(); - }, - ), - ), - ], - ), - ), - ); + OverlayDropdownWidget _buildLiveStockSpecies() { + return OverlayDropdownWidget( + items: ['گوسفند ماده', 'گوسفند نر', 'بز ماده', 'بز نر', 'گوساله ماده', 'گوساله نر'], + onChanged: (value) { + print('Selected: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'گونه دام'), + ); } } From aa724c72a48769563b75b4b183573f54a07d239c Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 26 May 2025 14:00:52 +0330 Subject: [PATCH 19/25] refactor : request page and fix padding's --- .../lib/presentation/page/requests/logic.dart | 2 + .../lib/presentation/page/requests/view.dart | 442 ++++++++++-------- 2 files changed, 238 insertions(+), 206 deletions(-) diff --git a/packages/livestock/lib/presentation/page/requests/logic.dart b/packages/livestock/lib/presentation/page/requests/logic.dart index 9cb9154..bf98dd3 100644 --- a/packages/livestock/lib/presentation/page/requests/logic.dart +++ b/packages/livestock/lib/presentation/page/requests/logic.dart @@ -4,4 +4,6 @@ import 'package:rasadyar_livestock/presentation/page/root/logic.dart'; class RequestsLogic extends GetxController { RxList filterSelected = [].obs; + RxBool isFilterShowed = false.obs; + } diff --git a/packages/livestock/lib/presentation/page/requests/view.dart b/packages/livestock/lib/presentation/page/requests/view.dart index b656387..54b9dc8 100644 --- a/packages/livestock/lib/presentation/page/requests/view.dart +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -10,213 +10,13 @@ class RequestsPage extends GetView { @override Widget build(BuildContext context) { return Scaffold( - appBar: RAppBar( - title: 'لیست درخواست‌ها', - hasBack: false, - centerTitle: true, - ), + appBar: RAppBar(title: 'لیست درخواست‌ها', hasBack: false, centerTitle: true), body: Column( children: [ - SizedBox(height: 16), - _searchWidget(), - SizedBox(height: 16), - SizedBox( - height: 50, - 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), - ), - ), - SizedBox(height: 10), - Expanded( - child: ListView.separated( - itemCount: 10, - physics: BouncingScrollPhysics(), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), - separatorBuilder: (context, index) => SizedBox(height: 16), - itemBuilder: (context, index) { - return GestureDetector( - onTap: () { - Get.toNamed(LiveStockRoutes.requestTagging); - }, - child: Container( - width: Get.width, - height: 75, - decoration: BoxDecoration( - color: - index < 3 - ? AppColor.yellowNormal - : index < 7 - ? AppColor.greenLightActive - : AppColor.blueLight, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - SizedBox(width: 5), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(8), - bottomRight: Radius.circular(8), - ), - ), - child: Row( - children: [ - SizedBox(width: 10), - Text( - 'محمد احمدی', - textAlign: TextAlign.center, - style: AppFonts.yekan12.copyWith( - color: AppColor.blueNormal, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(width: 20), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - - children: [ - Text( - 'پنج شنبه 14 اردیبهشت', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.darkGreyNormal, - ), - ), - Text( - ' همدان - نهاوند - روستای - همدان - نهاوند - روستای ', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.darkGreyNormal, - ), - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ], - ), - ), - SizedBox(width: 20), - GestureDetector( - onTap: () { - // controller.onTapMap(); - }, - child: SizedBox( - width: 50, - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - Assets.vec.mapSvg.svg( - width: 20, - height: 20, - colorFilter: ColorFilter.mode( - AppColor.blueNormal, - BlendMode.srcIn, - ), - ), - SizedBox(height: 8), - Text( - 'مسیریابی', - textAlign: TextAlign.center, - style: AppFonts.yekan10.copyWith( - color: AppColor.blueNormal, - ), - ), - ], - ), - ), - ), - - SizedBox(width: 20), - ], - ), - ), - ), - - Container( - width: 20, - child: Center( - child: RotatedBox( - quarterTurns: 3, - child: Text( - index < 3 - ? ' بازرسی' - : index < 7 - ? 'اطلاعات' - : 'ارجاع به تعاونی', - style: AppFonts.yekan8, - textAlign: TextAlign.center, - ), - ), - ), - ), - ], - ), - ), - ); - }, - ), - ), + SizedBox(height: 8), + _buildSearchAndFilter(), + _buildFilterWidget(), + _buildListOfContent(), RElevated( text: '+ ایجاد درخواست', width: Get.width - 36, @@ -232,9 +32,239 @@ class RequestsPage extends GetView { ); } + Expanded _buildListOfContent() { + return Expanded( + child: ListView.separated( + shrinkWrap: true, + itemCount: 10, + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: controller.isFilterShowed.value ? 5 : 10), + separatorBuilder: (context, index) => SizedBox(height: 6), + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + Get.toNamed(LiveStockRoutes.requestTagging); + }, + child: Container( + width: Get.width, + height: 75, + decoration: BoxDecoration( + color: + index < 3 + ? AppColor.yellowNormal + : index < 7 + ? AppColor.greenLightActive + : AppColor.blueLight, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + SizedBox(width: 5), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8), + bottomRight: Radius.circular(8), + ), + border: Border.all( + color: + index < 3 + ? AppColor.yellowNormal + : index < 7 + ? AppColor.greenLightActive + : AppColor.blueLight, + width: 2, + ), + ), + child: Row( + children: [ + SizedBox(width: 10), + Text( + 'محمد احمدی', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith( + color: AppColor.blueNormal, + fontWeight: FontWeight.w600, + ), + ), + SizedBox(width: 20), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + + children: [ + Text( + 'پنج شنبه 14 اردیبهشت', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith(color: AppColor.darkGreyNormal), + ), + Text( + ' همدان - نهاوند - روستای - همدان - نهاوند - روستای ', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith(color: AppColor.darkGreyNormal), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ], + ), + ), + SizedBox(width: 20), + GestureDetector( + onTap: () { + // controller.onTapMap(); + }, + child: SizedBox( + width: 50, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Assets.vec.mapSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + SizedBox(height: 8), + Text( + 'مسیریابی', + textAlign: TextAlign.center, + style: AppFonts.yekan10.copyWith(color: AppColor.blueNormal), + ), + ], + ), + ), + ), + + SizedBox(width: 20), + ], + ), + ), + ), + + Container( + width: 20, + child: Center( + child: RotatedBox( + quarterTurns: 3, + child: Text( + index < 3 + ? ' بازرسی' + : index < 7 + ? 'اطلاعات' + : 'ارجاع به تعاونی', + style: AppFonts.yekan8, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ), + ); + }, + ), + ); + } + + Row _buildSearchAndFilter() { + return Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 10.0), + child: IconButton( + onPressed: () { + controller.isFilterShowed.value = !controller.isFilterShowed.value; + }, + + style: IconButton.styleFrom( + backgroundColor: AppColor.blueNormal, + fixedSize: Size(40, 40), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + icon: Assets.vec.filterSvg.svg(), + ), + ), + Expanded(child: _searchWidget()), + ], + ); + } + + ObxValue _buildFilterWidget() { + return ObxValue((data) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: EdgeInsets.only(top: 5), + curve: Curves.easeInOut, + height: data.value ? 45 : 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.isFilterShowed); + } + Widget _searchWidget() { return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), + padding: const EdgeInsets.only(right: 8.0, left: 20.0), child: RTextField( suffixIcon: Padding( padding: const EdgeInsets.all(12.0), From 04b8fe593f3ec05d671c779cd8a8562a20eed37d Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 27 May 2025 08:48:35 +0330 Subject: [PATCH 20/25] fix : bottom sheet height --- .../presentation/widget/bottom_sheet/base_bottom_sheet.dart | 4 +++- packages/livestock/lib/presentation/page/tagging/view.dart | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart index e628b35..c685305 100644 --- a/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart +++ b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart @@ -3,13 +3,15 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; class BaseBottomSheet extends StatelessWidget { - const BaseBottomSheet({super.key, required this.child}); + const BaseBottomSheet({super.key, required this.child, this.height}); final Widget child; + final double? height; @override Widget build(BuildContext context) { return Container( + height: height ?? MediaQuery.of(context).size.height * 0.85, padding: EdgeInsets.symmetric(vertical: 15, horizontal: 20), decoration: BoxDecoration( color: Colors.white, diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart index 9dcd936..235d4c0 100644 --- a/packages/livestock/lib/presentation/page/tagging/view.dart +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -37,7 +37,10 @@ class TaggingPage extends GetView { SizedBox(width: 4), IconButton( onPressed: () { - Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); + Get.bottomSheet( + _buildBottomSheet(), + isScrollControlled: true, + ); }, style: IconButton.styleFrom( backgroundColor: AppColor.blueNormal, From a3327dd708e5155df9f97bef131b18a720549a91 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 27 May 2025 12:21:18 +0330 Subject: [PATCH 21/25] feat : add counter list --- .../lib/presentation/page/requests/view.dart | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/packages/livestock/lib/presentation/page/requests/view.dart b/packages/livestock/lib/presentation/page/requests/view.dart index 54b9dc8..2b73f22 100644 --- a/packages/livestock/lib/presentation/page/requests/view.dart +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -34,30 +34,32 @@ class RequestsPage extends GetView { Expanded _buildListOfContent() { return Expanded( - child: ListView.separated( - shrinkWrap: true, - itemCount: 10, - physics: BouncingScrollPhysics(), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: controller.isFilterShowed.value ? 5 : 10), - separatorBuilder: (context, index) => SizedBox(height: 6), - itemBuilder: (context, index) { - return GestureDetector( - onTap: () { - Get.toNamed(LiveStockRoutes.requestTagging); - }, - child: Container( - width: Get.width, - height: 75, - decoration: BoxDecoration( - color: - index < 3 - ? AppColor.yellowNormal - : index < 7 - ? AppColor.greenLightActive - : AppColor.blueLight, - borderRadius: BorderRadius.circular(8), - ), - child: Row( + child: ListView.separated( + shrinkWrap: true, + itemCount: 10, + physics: BouncingScrollPhysics(), + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 50), + separatorBuilder: (context, index) => SizedBox(height: 6), + itemBuilder: (context, index) { + return GestureDetector( + onTap: () { + Get.toNamed(LiveStockRoutes.requestTagging); + }, + child: Container( + width: Get.width, + height: 75, + decoration: BoxDecoration( + color: + index < 3 + ? AppColor.yellowNormal + : index < 7 + ? AppColor.greenLightActive + : AppColor.blueLight, + borderRadius: BorderRadius.circular(8), + ), + child: Stack( + children: [ + Row( children: [ SizedBox(width: 5), Expanded( @@ -161,11 +163,26 @@ class RequestsPage extends GetView { ), ], ), - ), - ); - }, - ), - ); + Positioned( + top: 5, + right: 10, + + child:Container( + padding: EdgeInsets.all(4), + alignment: AlignmentDirectional.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.black54,), + child: Text((index*20).toString(),style: AppFonts.yekan12.copyWith(color: Colors.white),), + ), + ), + ], + ), + ), + ); + }, + ), + ); } Row _buildSearchAndFilter() { From b935f3f12ae205536d9643ab126cdc30571d8b06 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 27 May 2025 14:31:50 +0330 Subject: [PATCH 22/25] feat : content list --- assets/icons/virtual_tag.svg | 1 + assets/vec/place_holder.svg.vec | Bin 0 -> 5160 bytes assets/vec/virtual_tag.svg.vec | Bin 0 -> 1725 bytes lib/presentation/common/assets.dart | 36 +-- .../lib/presentation/common/assets.gen.dart | 12 + .../lib/presentation/page/tagging/view.dart | 281 +++++++++++++----- 6 files changed, 223 insertions(+), 107 deletions(-) create mode 100644 assets/icons/virtual_tag.svg create mode 100644 assets/vec/place_holder.svg.vec create mode 100644 assets/vec/virtual_tag.svg.vec diff --git a/assets/icons/virtual_tag.svg b/assets/icons/virtual_tag.svg new file mode 100644 index 0000000..1f8b8aa --- /dev/null +++ b/assets/icons/virtual_tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/vec/place_holder.svg.vec b/assets/vec/place_holder.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..caeb6bf3555827d9e81281726165faf16f3603fd GIT binary patch literal 5160 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 KQ6Uiy4gCukGL5eQ literal 0 HcmV?d00001 diff --git a/assets/vec/virtual_tag.svg.vec b/assets/vec/virtual_tag.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..3d6d199286f982295e9d2982b8ee96f77fe7fc5e GIT binary patch literal 1725 zcmZuydr(wW96tA6Koka%M*+Jm4v$d`2{HpqLhh%ypo2)_Ac!`gf;A{Gm5ov=C|WZO zWQYPQAgnBcYapOF7Q2*2H5y^WqflOEqoQGplv3Qzy}Q@?qjTrX_dCDyxWDiFokz;T z!-VlCge(`UQW!WXaD)hg(mQImz%il~P(LPctZ41+Y!Nt4wA@3I1kOsdhJLv%aMsjP zFod|!MF`6>EW^-h`B;{V5&g7GfRKH(PT;jW0$*=!q_#1_>@!B($PM(*-3wCr6S6)(fJM$fVpeYf)@|s* zVDvGhUHS$b(I9PGJ6%_U);5iVC6@}#ZTjEg&rX^DZ)}t>>{}Cp_8f$M*o2-(dB}cf zLhX)R6g)PeD<&7APfYkDFc;kvJ!a=3b;<Q`fAw>hV`0q>40lj>k*LUj?_7gC~leu zwRJNF3tplenz8aU;3_mBFd-JsO^ujLPlSE09%U69k$L){vafjz!8_}TYabR5^>j)xPjmujJ#c7TI_4YrQhA^L(2x|?>u(mKfTD;O&>Q)DF5 z3y|oMnP+SX?bPV{#DLeIc%rbP zjruug-fBc)K0)EFPho#=l0QT-xPF{JME&dEyvyfXHQ_u(yN_BR$EhIJ|I5Ri4=wft z2Z3j`uyb7ibz2oyAM-;YhRw>-L4BW2**7^sk`7sSHY|aOBjMV29^&+!!grqlb}jJz9pGuc8pM z@&xXzjl$!r75Mo63akz}3FQfT#<*%EEnJHCglY^)`$kLe0UPsP74yM)NXbwL;$0Vt zjO{uJ6+#`7o(qSF;&~JCRClbUKY_Nz@d^04s9ZvYP%8C{XdYiG%{TXlTE const SvgGenImage('assets/icons/user_square.svg'); + /// File path: assets/icons/virtual_tag.svg + SvgGenImage get virtualTag => const SvgGenImage('assets/icons/virtual_tag.svg'); + /// List of all assets List get values => [ add, @@ -161,6 +164,7 @@ class $AssetsIconsGen { trash, user, userSquare, + virtualTag, ]; } @@ -252,6 +256,9 @@ class $AssetsVecGen { /// File path: assets/vec/picture_frame.svg.vec SvgGenImage get pictureFrameSvg => const SvgGenImage.vec('assets/vec/picture_frame.svg.vec'); + /// File path: assets/vec/place_holder.svg.vec + SvgGenImage get placeHolderSvg => const SvgGenImage.vec('assets/vec/place_holder.svg.vec'); + /// File path: assets/vec/profile_circle.svg.vec SvgGenImage get profileCircleSvg => const SvgGenImage.vec('assets/vec/profile_circle.svg.vec'); @@ -288,6 +295,9 @@ class $AssetsVecGen { /// File path: assets/vec/user_square.svg.vec SvgGenImage get userSquareSvg => const SvgGenImage.vec('assets/vec/user_square.svg.vec'); + /// File path: assets/vec/virtual_tag.svg.vec + SvgGenImage get virtualTagSvg => const SvgGenImage.vec('assets/vec/virtual_tag.svg.vec'); + /// List of all assets List get values => [ addSvg, @@ -313,6 +323,7 @@ class $AssetsVecGen { messageAddSvg, pdfDownloadSvg, pictureFrameSvg, + placeHolderSvg, profileCircleSvg, profileUserSvg, receiptDiscountSvg, @@ -325,6 +336,7 @@ class $AssetsVecGen { trashSvg, userSvg, userSquareSvg, + virtualTagSvg, ]; } diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart index 235d4c0..8623a91 100644 --- a/packages/livestock/lib/presentation/page/tagging/view.dart +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -37,10 +37,7 @@ class TaggingPage extends GetView { SizedBox(width: 4), IconButton( onPressed: () { - Get.bottomSheet( - _buildBottomSheet(), - isScrollControlled: true, - ); + Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); }, style: IconButton.styleFrom( backgroundColor: AppColor.blueNormal, @@ -53,78 +50,139 @@ class TaggingPage extends GetView { ), Expanded( - child: Card( - clipBehavior: Clip.hardEdge, - color: Colors.white, - child: GridView.builder( - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), - itemCount: 20, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 12, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - return Container( - decoration: ShapeDecoration( - color: AppColor.lightGreyLightHover, - shape: RoundedRectangleBorder( - side: BorderSide(width: 1, color: AppColor.blackLightHover), - borderRadius: BorderRadius.circular(8), - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: ListView.separated( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10), + itemCount: 20, + itemBuilder: (context, index) { + return Container( + width: Get.width, + height: 85, + decoration: BoxDecoration( + color: + index < 5 + ? AppColor.yellowNormal + : index < 12 + ? AppColor.greenLightActive + : AppColor.blueLight, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + children: [ + SizedBox(width: 5), + Expanded( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(8), + bottomRight: Radius.circular(8), + ), + border: Border.all( + color: + index < 5 + ? AppColor.yellowNormal + : index < 12 + ? AppColor.greenLightActive + : AppColor.blueLight, + width: 2, + ), + ), + child: Column( children: [ - Assets.vec.editSvg.svg( - width: 16, - height: 16, - colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), - ), - Assets.vec.trashSvg.svg( - width: 16, - height: 16, - colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), - ), + SizedBox(height: 10), + Expanded(child: Row( + children: [ + SizedBox(width: 10,), + Container( + padding: EdgeInsets.all(8), + alignment: AlignmentDirectional.center, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.black54,), + child: Text((index+1).toString(),style: AppFonts.yekan18.copyWith(color: Colors.white),), + ), + + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + padding: EdgeInsets.all(8), + alignment: AlignmentDirectional.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.black26,), + child: Text('ماده',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), + ), + Container( + padding: EdgeInsets.all(8), + alignment: AlignmentDirectional.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.black26,), + child: Text('18 ماه',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), + ), + Container( + padding: EdgeInsets.all(8), + alignment: AlignmentDirectional.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + color: Colors.black26,), + child: Text('سرابی',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), + ), + ], + ), + ), + ], + )), + SizedBox(height: 10), + Expanded(child: + Row( + children: [ + SizedBox(width: 10,), + Text('پلاک : 1212115112512', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)), + Spacer(), + Assets.vec.editSvg.svg( + width: 24, + height: 24, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + SizedBox(width: 10), + Assets.vec.trashSvg.svg( + width: 24, + height: 24, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn)), + SizedBox(width: 10,), + ], + + )), + ], ), - Text( - 'گوسفند ماده', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), - ), - SizedBox(height: 10), - Text( - 'سن : 18 ماه', - textAlign: TextAlign.center, - style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyNormal), - ), - Text( - 'نوع نژاد', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), - ), - Text( - '1212115112512', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), - ), - Text( - 'نوع پلاک', - textAlign: TextAlign.center, - style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), - ), - ], + ), ), - ), - ); - }, - ), + + Container( + width: 20, + child: Center( + child: RotatedBox( + quarterTurns: 3, + child: Text( + index < 5 + ? 'گاو' + : index < 12 + ? 'گوسفند' + : 'مرغ', + style: AppFonts.yekan8, + textAlign: TextAlign.center, + ), + ), + ), + ), + ], + ), + ); + }, separatorBuilder: (BuildContext context, int index) =>SizedBox(height: 4,) ), ), @@ -144,6 +202,85 @@ class TaggingPage extends GetView { ); } + Widget _buildOldPage() { + return Expanded( + child: Card( + clipBehavior: Clip.hardEdge, + color: Colors.white, + child: GridView.builder( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10), + itemCount: 20, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 12, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + return Container( + decoration: ShapeDecoration( + color: AppColor.lightGreyLightHover, + shape: RoundedRectangleBorder( + side: BorderSide(width: 1, color: AppColor.blackLightHover), + borderRadius: BorderRadius.circular(8), + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), + ), + ], + ), + Text( + 'گوسفند ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), + ), + SizedBox(height: 10), + Text( + 'سن : 18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan12.copyWith(color: AppColor.darkGreyNormal), + ), + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), + ), + Text( + '1212115112512', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), + ), + Text( + 'نوع پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), + ), + ], + ), + ), + ); + }, + ), + ), + ); + + } + Widget _buildBottomSheet() { return BaseBottomSheet( child: Column( From b86a2d986ebfe334b0fa6f81aedaed457570295f Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 28 May 2025 14:15:19 +0330 Subject: [PATCH 23/25] feat : new tagging page --- assets/icons/tag_label.svg | 4 + assets/icons/virtual.svg | 24 + assets/icons/virtual_tag.svg | 1 - assets/vec/tag_label.svg.vec | Bin 0 -> 487 bytes assets/vec/virtual.svg.vec | Bin 0 -> 11224 bytes assets/vec/virtual_tag.svg.vec | Bin 1725 -> 0 bytes lib/presentation/common/assets.dart | 46 -- .../lib/presentation/common/assets.gen.dart | 20 +- .../bottom_sheet/base_bottom_sheet.dart | 5 +- .../lib/presentation/page/tagging/logic.dart | 3 + .../lib/presentation/page/tagging/view.dart | 635 +++++++++++++----- tools/runner.sh | 5 +- 12 files changed, 509 insertions(+), 234 deletions(-) create mode 100644 assets/icons/tag_label.svg create mode 100644 assets/icons/virtual.svg delete mode 100644 assets/icons/virtual_tag.svg create mode 100644 assets/vec/tag_label.svg.vec create mode 100644 assets/vec/virtual.svg.vec delete mode 100644 assets/vec/virtual_tag.svg.vec delete mode 100644 lib/presentation/common/assets.dart diff --git a/assets/icons/tag_label.svg b/assets/icons/tag_label.svg new file mode 100644 index 0000000..7db9b38 --- /dev/null +++ b/assets/icons/tag_label.svg @@ -0,0 +1,4 @@ + + + diff --git a/assets/icons/virtual.svg b/assets/icons/virtual.svg new file mode 100644 index 0000000..b3563c1 --- /dev/null +++ b/assets/icons/virtual.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/virtual_tag.svg b/assets/icons/virtual_tag.svg deleted file mode 100644 index 1f8b8aa..0000000 --- a/assets/icons/virtual_tag.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/vec/tag_label.svg.vec b/assets/vec/tag_label.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..7afb4cd8e5999ee56f01bc2e1cc232da9f6e1b5a GIT binary patch literal 487 zcmYe&?O&Hu~{4FCVjy2dd4XJ7!b6@W4g_KZL=X$A%caUf=3 zWC8<5CJ1C^0CAaxSdh0v>*_B+m+nd!Lpa_Z_||b35KT`O2ZqlgH7H^_#=dem2M4=SGe)s%IUvtP&lg+zlPPem6N<2q=N+ zyN);PL41(k?iF@`X+`;dF#YxRZ!o>hh0zJ5j)8&238W81^XJ~UWVBzxRZ@S|=6)wjm_d~&SsDZm9pV4;*5DoGVh+dhs x-T@?E6+FoSq#i^&%T$5slc_CWc@Pa!528W(LGmDTVdfjifnwwTe;@^lIsjfytH1yN literal 0 HcmV?d00001 diff --git a/assets/vec/virtual.svg.vec b/assets/vec/virtual.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..13b9ec3a2de7d3874214a0df0bbfc7d6bf510ac1 GIT binary patch literal 11224 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 literal 0 HcmV?d00001 diff --git a/assets/vec/virtual_tag.svg.vec b/assets/vec/virtual_tag.svg.vec deleted file mode 100644 index 3d6d199286f982295e9d2982b8ee96f77fe7fc5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1725 zcmZuydr(wW96tA6Koka%M*+Jm4v$d`2{HpqLhh%ypo2)_Ac!`gf;A{Gm5ov=C|WZO zWQYPQAgnBcYapOF7Q2*2H5y^WqflOEqoQGplv3Qzy}Q@?qjTrX_dCDyxWDiFokz;T z!-VlCge(`UQW!WXaD)hg(mQImz%il~P(LPctZ41+Y!Nt4wA@3I1kOsdhJLv%aMsjP zFod|!MF`6>EW^-h`B;{V5&g7GfRKH(PT;jW0$*=!q_#1_>@!B($PM(*-3wCr6S6)(fJM$fVpeYf)@|s* zVDvGhUHS$b(I9PGJ6%_U);5iVC6@}#ZTjEg&rX^DZ)}t>>{}Cp_8f$M*o2-(dB}cf zLhX)R6g)PeD<&7APfYkDFc;kvJ!a=3b;<Q`fAw>hV`0q>40lj>k*LUj?_7gC~leu zwRJNF3tplenz8aU;3_mBFd-JsO^ujLPlSE09%U69k$L){vafjz!8_}TYabR5^>j)xPjmujJ#c7TI_4YrQhA^L(2x|?>u(mKfTD;O&>Q)DF5 z3y|oMnP+SX?bPV{#DLeIc%rbP zjruug-fBc)K0)EFPho#=l0QT-xPF{JME&dEyvyfXHQ_u(yN_BR$EhIJ|I5Ri4=wft z2Z3j`uyb7ibz2oyAM-;YhRw>-L4BW2**7^sk`7sSHY|aOBjMV29^&+!!grqlb}jJz9pGuc8pM z@&xXzjl$!r75Mo63akz}3FQfT#<*%EEnJHCglY^)`$kLe0UPsP74yM)NXbwL;$0Vt zjO{uJ6+#`7o(qSF;&~JCRClbUKY_Nz@d^04s9ZvYP%8C{XdYiG%{TXlTE const SvgGenImage('assets/icons/setting.svg'); + /// File path: assets/icons/tag_label.svg + SvgGenImage get tagLabel => const SvgGenImage('assets/icons/tag_label.svg'); + /// File path: assets/icons/tag_user.svg SvgGenImage get tagUser => const SvgGenImage('assets/icons/tag_user.svg'); @@ -123,8 +126,8 @@ class $AssetsIconsGen { /// File path: assets/icons/user_square.svg SvgGenImage get userSquare => const SvgGenImage('assets/icons/user_square.svg'); - /// File path: assets/icons/virtual_tag.svg - SvgGenImage get virtualTag => const SvgGenImage('assets/icons/virtual_tag.svg'); + /// File path: assets/icons/virtual.svg + SvgGenImage get virtual => const SvgGenImage('assets/icons/virtual.svg'); /// List of all assets List get values => [ @@ -160,11 +163,12 @@ class $AssetsIconsGen { search, securityTime, setting, + tagLabel, tagUser, trash, user, userSquare, - virtualTag, + virtual, ]; } @@ -283,6 +287,9 @@ class $AssetsVecGen { /// File path: assets/vec/setting.svg.vec SvgGenImage get settingSvg => const SvgGenImage.vec('assets/vec/setting.svg.vec'); + /// File path: assets/vec/tag_label.svg.vec + SvgGenImage get tagLabelSvg => const SvgGenImage.vec('assets/vec/tag_label.svg.vec'); + /// File path: assets/vec/tag_user.svg.vec SvgGenImage get tagUserSvg => const SvgGenImage.vec('assets/vec/tag_user.svg.vec'); @@ -295,8 +302,8 @@ class $AssetsVecGen { /// File path: assets/vec/user_square.svg.vec SvgGenImage get userSquareSvg => const SvgGenImage.vec('assets/vec/user_square.svg.vec'); - /// File path: assets/vec/virtual_tag.svg.vec - SvgGenImage get virtualTagSvg => const SvgGenImage.vec('assets/vec/virtual_tag.svg.vec'); + /// File path: assets/vec/virtual.svg.vec + SvgGenImage get virtualSvg => const SvgGenImage.vec('assets/vec/virtual.svg.vec'); /// List of all assets List get values => [ @@ -332,11 +339,12 @@ class $AssetsVecGen { searchSvg, securityTimeSvg, settingSvg, + tagLabelSvg, tagUserSvg, trashSvg, userSvg, userSquareSvg, - virtualTagSvg, + virtualSvg, ]; } diff --git a/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart index c685305..cb646f0 100644 --- a/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart +++ b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart @@ -3,10 +3,11 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; class BaseBottomSheet extends StatelessWidget { - const BaseBottomSheet({super.key, required this.child, this.height}); + const BaseBottomSheet({super.key, required this.child, this.height, this.bgColor}); final Widget child; final double? height; + final Color? bgColor; @override Widget build(BuildContext context) { @@ -14,7 +15,7 @@ class BaseBottomSheet extends StatelessWidget { height: height ?? MediaQuery.of(context).size.height * 0.85, padding: EdgeInsets.symmetric(vertical: 15, horizontal: 20), decoration: BoxDecoration( - color: Colors.white, + color:bgColor?? Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), ), child: SingleChildScrollView( diff --git a/packages/livestock/lib/presentation/page/tagging/logic.dart b/packages/livestock/lib/presentation/page/tagging/logic.dart index c60d7ff..30e8316 100644 --- a/packages/livestock/lib/presentation/page/tagging/logic.dart +++ b/packages/livestock/lib/presentation/page/tagging/logic.dart @@ -2,6 +2,9 @@ import 'package:rasadyar_core/core.dart'; class TaggingLogic extends GetxController { RxInt selectedSegment = 0.obs; + RxBool searchIsSelected = false.obs; + RxBool filterIsSelected = false.obs; + RxList filterSelected = [].obs; @override void onReady() { diff --git a/packages/livestock/lib/presentation/page/tagging/view.dart b/packages/livestock/lib/presentation/page/tagging/view.dart index 8623a91..6e21741 100644 --- a/packages/livestock/lib/presentation/page/tagging/view.dart +++ b/packages/livestock/lib/presentation/page/tagging/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/presentation/widget/buttons/fab.dart'; import 'logic.dart'; @@ -15,190 +16,194 @@ class TaggingPage extends GetView { title: 'پلاک کوبی', leadingWidth: 40, leading: Assets.vec.messageAddSvg.svg(width: 12, height: 12), + additionalActions: [ + GestureDetector( + onTap: () { + if (controller.searchIsSelected.value) { + controller.searchIsSelected.value = !controller.searchIsSelected.value; + } + controller.filterIsSelected.value = !controller.filterIsSelected.value; + }, + child: Assets.icons.filter.svg(width: 20, height: 20), + ), + SizedBox(width: 16), + GestureDetector( + onTap: () { + if (controller.filterIsSelected.value) { + controller.filterIsSelected.value = !controller.filterIsSelected.value; + } + controller.searchIsSelected.value = !controller.searchIsSelected.value; + }, + child: Assets.icons.search.svg(width: 20, height: 20), + ), + ], ), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 15), - child: Column( - children: [ - Row( - children: [ - Expanded( - child: Container( - height: 40, - decoration: BoxDecoration( - color: AppColor.greenLightHover, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: AppColor.darkGreyLight), - ), - alignment: Alignment.center, - child: Text('آمار ثبت شده : سبک 5 و سنگین 8 راس'), - ), + body: 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, ), - SizedBox(width: 4), - IconButton( - onPressed: () { - Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); - }, - style: IconButton.styleFrom( - backgroundColor: AppColor.blueNormal, - fixedSize: Size(40, 40), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + ], + ), + Positioned( + right: 10, + bottom: 75, + child: RFab.add( + onPressed: () { + Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); + }, + ), + ), + ], + ), + ); + } + + Container _buildInfoDetails() { + return Container( + height: 40, + margin: EdgeInsets.fromLTRB(15, 10, 15, 2), + decoration: BoxDecoration( + color: AppColor.greenLightHover, + borderRadius: BorderRadius.circular(8), + border: Border.all(color: AppColor.darkGreyLight), + ), + alignment: Alignment.center, + child: Text('پلاک شده : سبک 5 و سنگین 8 راس'), + ); + } + + Expanded _buildListContent() { + return Expanded( + child: ListView.separated( + padding: EdgeInsets.symmetric(horizontal: 15, vertical: 10), + itemCount: 20, + physics: BouncingScrollPhysics(), + cacheExtent: 280, + addRepaintBoundaries: true, + itemBuilder: (context, index) { + return _buildItemList(index); + }, + separatorBuilder: (BuildContext context, int index) => SizedBox(height: 6), + ), + ); + } + + Stack _buildItemList(int index) { + return Stack( + clipBehavior: Clip.none, + children: [ + Container( + width: Get.width, + height: 75, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 2, + color: + index < 5 + ? AppColor.yellowNormal + : index < 12 + ? AppColor.greenLightActive + : AppColor.blueLight, + ), + ), + child: Row( + children: [ + SizedBox(width: 30), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Get.bottomSheet(_buildInfoBottomSheet(), isScrollControlled: true); + }, + child: Stack( + clipBehavior: Clip.none, + children: [ + Text('123456789012346', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal)), + Positioned(top: -20, right: -10, child: Assets.icons.virtual.svg(width: 20, height: 20)), + ], + ), + ), + Spacer(), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('گوسفند ماده', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal)), + SizedBox(height: 4), + Text('نوع نژاد', style: AppFonts.yekan14.copyWith(color: AppColor.bgDark)), + ], + ), + Spacer(), + Text('18 ماه', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)), + Spacer(), + Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + Assets.vec.trashSvg.svg( + width: 20, + height: 20, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), + ), + ], + ), + ), + SizedBox(width: 8), + ], + ), + ), + 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), ), - icon: Assets.vec.addSvg.svg(), ), ], ), - - Expanded( - child: ListView.separated( - padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10), - itemCount: 20, - itemBuilder: (context, index) { - return Container( - width: Get.width, - height: 85, - decoration: BoxDecoration( - color: - index < 5 - ? AppColor.yellowNormal - : index < 12 - ? AppColor.greenLightActive - : AppColor.blueLight, - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - SizedBox(width: 5), - Expanded( - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topRight: Radius.circular(8), - bottomRight: Radius.circular(8), - ), - border: Border.all( - color: - index < 5 - ? AppColor.yellowNormal - : index < 12 - ? AppColor.greenLightActive - : AppColor.blueLight, - width: 2, - ), - ), - child: Column( - children: [ - SizedBox(height: 10), - Expanded(child: Row( - children: [ - SizedBox(width: 10,), - Container( - padding: EdgeInsets.all(8), - alignment: AlignmentDirectional.center, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.black54,), - child: Text((index+1).toString(),style: AppFonts.yekan18.copyWith(color: Colors.white),), - ), - - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Container( - padding: EdgeInsets.all(8), - alignment: AlignmentDirectional.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.black26,), - child: Text('ماده',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), - ), - Container( - padding: EdgeInsets.all(8), - alignment: AlignmentDirectional.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.black26,), - child: Text('18 ماه',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), - ), - Container( - padding: EdgeInsets.all(8), - alignment: AlignmentDirectional.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - color: Colors.black26,), - child: Text('سرابی',style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),), - ), - ], - ), - ), - ], - )), - SizedBox(height: 10), - Expanded(child: - Row( - children: [ - SizedBox(width: 10,), - Text('پلاک : 1212115112512', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)), - Spacer(), - Assets.vec.editSvg.svg( - width: 24, - height: 24, - colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), - ), - SizedBox(width: 10), - Assets.vec.trashSvg.svg( - width: 24, - height: 24, - colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn)), - SizedBox(width: 10,), - ], - - )), - - ], - ), - ), - ), - - Container( - width: 20, - child: Center( - child: RotatedBox( - quarterTurns: 3, - child: Text( - index < 5 - ? 'گاو' - : index < 12 - ? 'گوسفند' - : 'مرغ', - style: AppFonts.yekan8, - textAlign: TextAlign.center, - ), - ), - ), - ), - ], - ), - ); - }, separatorBuilder: (BuildContext context, int index) =>SizedBox(height: 4,) - ), - ), - - SizedBox(height: 10), - - RElevated( - text: 'ثبت نهایی و ارسال به اتحادیه', - textStyle: AppFonts.yekan18, - height: 40, - backgroundColor: AppColor.greenNormal, - onPressed: () {}, - isFullWidth: true, - ), - ], + ), ), - ), + ], ); } @@ -278,7 +283,6 @@ class TaggingPage extends GetView { ), ), ); - } Widget _buildBottomSheet() { @@ -319,6 +323,178 @@ class TaggingPage extends GetView { ); } + Widget _buildInfoBottomSheet() { + return BaseBottomSheet( + height: Get.height * 0.5, + bgColor: const Color(0xFFF5F5F5), + child: Card( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 15, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + Text('محمد احمدی', style: AppFonts.yekan14), + + GestureDetector( + onTap: () { + _buildDeleteDialog(onConfirm: () { + + }); + }, + child: Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), + ), + ), + ], + ), + Container( + height: 32, + padding: EdgeInsets.all(8), + decoration: BoxDecoration(color: AppColor.blueLightHover), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'تاریخ ثبت', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '1404/2/2', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شماره پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '123456789012346', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'جنسیت ', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'افشاری', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع گله', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'روستایی', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شهر', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'کرج', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'سن', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ], + ), + ), + ), + ); + } + + void _buildDeleteDialog({required VoidCallback onConfirm}) { + Get.defaultDialog( + title: 'حذف دام', + middleText: 'آیا از حذف این دام مطمئن هستید؟', + confirm: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: AppColor.error, foregroundColor: Colors.white), + onPressed: onConfirm, + child: Text('بله'), + ), + cancel: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('خیر'), + ), + ); + } + SizedBox _buildLiveStockImage() { return SizedBox( width: Get.width, @@ -482,4 +658,107 @@ class TaggingPage extends GetView { 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); + } } diff --git a/tools/runner.sh b/tools/runner.sh index e0b9992..1931741 100644 --- a/tools/runner.sh +++ b/tools/runner.sh @@ -1 +1,4 @@ -dart run build_runner build --delete-conflicting-outputs \ No newline at end of file +cd ../ +dart run build_runner build --delete-conflicting-outputs + + From 7dbb66465c453ab18789970dcb60647a3adeaa58 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 2 Jun 2025 09:38:02 +0330 Subject: [PATCH 24/25] feat : refresh login test: core --- lib/main.dart | 2 - .../data/services/token_storage_service.dart | 44 ++----- packages/auth/lib/data/utils/safe_call.dart | 61 ++++++++++ packages/auth/lib/hive_registrar.g.dart | 3 +- .../lib/presentation/pages/auth/logic.dart | 4 +- .../presentation/widget/captcha/logic.dart | 4 +- .../build/unit_test_assets/AssetManifest.json | 1 + .../lib/assets/flutter_map_logo.png | Bin 0 -> 2424 bytes .../lib/presentation/utils/color_utils.dart | 2 +- packages/core/lib/utils/safe_call_utils.dart | 59 ++++++--- .../local/hive_local_storage.dart | 112 ++++++++++++++++++ .../infrastructure/local/i_local_storage.dart | 44 +++++++ .../infrastructure/remote/dio_form_data.dart | 23 ++++ .../remote/dio_remote_test.dart | 0 .../infrastructure/remote/dio_response.dart | 20 ++++ .../remote/interfaces/i_form_data.dart | 6 + .../remote/interfaces/i_http_client.dart | 54 +++++++++ .../remote/interfaces/i_http_response.dart | 6 + .../remote/interfaces/i_remote.dart | 4 + packages/core/test/injection/di_test.dart | 18 +++ .../presentation/common/app_color_test.dart | 43 +++++++ .../presentation/utils/color_utils_test.dart | 35 ++++++ .../utils/list_extensions_test.dart | 53 +++++++++ pubspec.yaml | 2 +- 24 files changed, 538 insertions(+), 62 deletions(-) create mode 100644 packages/auth/lib/data/utils/safe_call.dart create mode 100644 packages/core/build/unit_test_assets/AssetManifest.json create mode 100644 packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png create mode 100644 packages/core/test/infrastructure/local/hive_local_storage.dart create mode 100644 packages/core/test/infrastructure/local/i_local_storage.dart create mode 100644 packages/core/test/infrastructure/remote/dio_form_data.dart create mode 100644 packages/core/test/infrastructure/remote/dio_remote_test.dart create mode 100644 packages/core/test/infrastructure/remote/dio_response.dart create mode 100644 packages/core/test/infrastructure/remote/interfaces/i_form_data.dart create mode 100644 packages/core/test/infrastructure/remote/interfaces/i_http_client.dart create mode 100644 packages/core/test/infrastructure/remote/interfaces/i_http_response.dart create mode 100644 packages/core/test/infrastructure/remote/interfaces/i_remote.dart create mode 100644 packages/core/test/injection/di_test.dart create mode 100644 packages/core/test/presentation/common/app_color_test.dart create mode 100644 packages/core/test/presentation/utils/color_utils_test.dart create mode 100644 packages/core/test/presentation/utils/list_extensions_test.dart diff --git a/lib/main.dart b/lib/main.dart index 42195b2..395decd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,9 +2,7 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_app/presentation/routes/app_pages.dart'; import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_auth/data/services/token_storage_service.dart'; - import 'package:rasadyar_core/core.dart'; - import 'infrastructure/di/di.dart'; import 'infrastructure/service/auth_service.dart'; diff --git a/packages/auth/lib/data/services/token_storage_service.dart b/packages/auth/lib/data/services/token_storage_service.dart index 39d33dd..0c56166 100644 --- a/packages/auth/lib/data/services/token_storage_service.dart +++ b/packages/auth/lib/data/services/token_storage_service.dart @@ -18,58 +18,32 @@ class TokenStorageService extends GetxService { Rxn appModule = Rxn(null); Future init() async { + await Hive.initFlutter(); Hive.registerAdapters(); - IsolatedHive.registerAdapters(); final String? encryptedKey = await _secureStorage.read(key: 'hive_enc_key'); - final encryptionKey = - encryptedKey != null - ? base64Url.decode(encryptedKey) - : Hive.generateSecureKey(); + final encryptionKey = encryptedKey != null ? base64Url.decode(encryptedKey) : Hive.generateSecureKey(); if (encryptedKey == null) { - await _secureStorage.write( - key: 'hive_enc_key', - value: base64UrlEncode(encryptionKey), - ); + await _secureStorage.write(key: 'hive_enc_key', value: base64UrlEncode(encryptionKey)); } await _localStorage.init(); - await _localStorage.openBox( - _boxName, - encryptionCipher: HiveAesCipher(encryptionKey), - ); + await _localStorage.openBox(_boxName, encryptionCipher: HiveAesCipher(encryptionKey)); - accessToken.value = _localStorage.read( - boxName: _boxName, - key: _accessTokenKey, - ); - refreshToken.value = _localStorage.read( - boxName: _boxName, - key: _refreshTokenKey, - ); - appModule.value = _localStorage.read( - boxName: _boxName, - key: _moduleKey, - ); + accessToken.value = _localStorage.read(boxName: _boxName, key: _accessTokenKey); + refreshToken.value = _localStorage.read(boxName: _boxName, key: _refreshTokenKey); + appModule.value = _localStorage.read(boxName: _boxName, key: _moduleKey); } Future saveAccessToken(String token) async { - await _localStorage.save( - boxName: _boxName, - key: _accessTokenKey, - value: token, - ); + await _localStorage.save(boxName: _boxName, key: _accessTokenKey, value: token); accessToken.value = token; accessToken.refresh(); } Future saveRefreshToken(String token) async { - await _localStorage.save( - boxName: _boxName, - key: _refreshTokenKey, - value: token, - ); + await _localStorage.save(boxName: _boxName, key: _refreshTokenKey, value: token); refreshToken.value = token; refreshToken.refresh(); } diff --git a/packages/auth/lib/data/utils/safe_call.dart b/packages/auth/lib/data/utils/safe_call.dart new file mode 100644 index 0000000..6d08637 --- /dev/null +++ b/packages/auth/lib/data/utils/safe_call.dart @@ -0,0 +1,61 @@ +import 'package:flutter/foundation.dart'; +import 'package:rasadyar_auth/auth.dart'; +import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; +import 'package:rasadyar_core/core.dart'; + +import '../models/response/auth/auth_response_model.dart'; +import '../services/token_storage_service.dart'; + +Future safeCall({ + required AppAsyncCallback call, + Function(T result)? onSuccess, + ErrorCallback? onError, + VoidCallback? onComplete, + bool showLoading = false, + bool showError = false, + bool showSuccess = false, + bool showToast = false, + bool showSnackBar = false, + Function()? onShowLoading, + Function()? onHideLoading, + Function()? onShowSuccessMessage, + Function()? onShowErrorMessage, +}) { + final authRepository = diAuth.get(); + TokenStorageService tokenStorageService = Get.find(); + + return gSafeCall( + call: call, + onSuccess: onSuccess, + onError: onError, + onComplete: onComplete, + showLoading: showLoading, + showError: showError, + showSuccess: showSuccess, + showToast: showToast, + showSnackBar: showSnackBar, + onShowLoading: onShowLoading, + onHideLoading: onHideLoading, + onShowSuccessMessage: onShowSuccessMessage, + onShowErrorMessage: onShowErrorMessage, + retryOnAuthError: true, + onTokenRefresh: () { + var token = tokenStorageService.refreshToken.value; + authRepository + .loginWithRefreshToken(authRequest: {"refresh_token": token}) + .then((value) async { + if (value is AuthResponseModel) { + await tokenStorageService.saveAccessToken(value.access!); + } else { + throw Exception("Failed to refresh token"); + } + }) + .catchError((error) { + if (kDebugMode) { + print('Error during token refresh: $error'); + } + throw error; + }); + }, + ); +} diff --git a/packages/auth/lib/hive_registrar.g.dart b/packages/auth/lib/hive_registrar.g.dart index 166b5cb..b46fdff 100644 --- a/packages/auth/lib/hive_registrar.g.dart +++ b/packages/auth/lib/hive_registrar.g.dart @@ -7,8 +7,9 @@ import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart extension HiveRegistrar on HiveInterface { void registerAdapters() { - registerAdapter(ModuleAdapter()); registerAdapter(UserLocalModelAdapter()); + registerAdapter(ModuleAdapter()); + } } diff --git a/packages/auth/lib/presentation/pages/auth/logic.dart b/packages/auth/lib/presentation/pages/auth/logic.dart index 59b8167..624328a 100644 --- a/packages/auth/lib/presentation/pages/auth/logic.dart +++ b/packages/auth/lib/presentation/pages/auth/logic.dart @@ -8,6 +8,7 @@ import 'package:rasadyar_auth/data/models/request/login_request/login_request_mo import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; import 'package:rasadyar_auth/data/services/token_storage_service.dart'; +import 'package:rasadyar_auth/data/utils/safe_call.dart'; import 'package:rasadyar_auth/presentation/widget/captcha/logic.dart'; import 'package:rasadyar_core/core.dart'; @@ -73,7 +74,6 @@ class AuthLogic extends GetxController { @override void onInit() { super.onInit(); - tokenStorageService.init(); } @override @@ -120,8 +120,6 @@ class AuthLogic extends GetxController { await tokenStorageService.saveModule(_module); await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); await tokenStorageService.saveAccessToken(result?.access ?? ''); - - //Get.offAndToNamed(Routes.home); }, onError: (error, stackTrace) { if (error is DioException) { diff --git a/packages/auth/lib/presentation/widget/captcha/logic.dart b/packages/auth/lib/presentation/widget/captcha/logic.dart index 4adb51c..6a89f38 100644 --- a/packages/auth/lib/presentation/widget/captcha/logic.dart +++ b/packages/auth/lib/presentation/widget/captcha/logic.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_auth/data/di/auth_di.dart'; import 'package:rasadyar_auth/data/models/response/captcha/captcha_response_model.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; +import 'package:rasadyar_auth/data/utils/safe_call.dart'; import 'package:rasadyar_core/core.dart'; -class CaptchaWidgetLogic extends GetxController - with StateMixin { +class CaptchaWidgetLogic extends GetxController with StateMixin { Rx textController = TextEditingController().obs; RxnString captchaKey = RxnString(); GlobalKey formKey = GlobalKey(); diff --git a/packages/core/build/unit_test_assets/AssetManifest.json b/packages/core/build/unit_test_assets/AssetManifest.json new file mode 100644 index 0000000..52a2006 --- /dev/null +++ b/packages/core/build/unit_test_assets/AssetManifest.json @@ -0,0 +1 @@ +{"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 new file mode 100644 index 0000000000000000000000000000000000000000..8603d0a3d2a91580f77171968c7d13e73fd1482a GIT binary patch literal 2424 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 0 && amount <= 1, 'مقدار تیرگی باید بین 0 و 1 باشد'); + assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1'); final hslColor = HSLColor.fromColor(this); final newLightness = (hslColor.lightness - amount).clamp(0.0, 1.0); final hslDarkerColor = hslColor.withLightness(newLightness); diff --git a/packages/core/lib/utils/safe_call_utils.dart b/packages/core/lib/utils/safe_call_utils.dart index e210b40..c4baa0b 100644 --- a/packages/core/lib/utils/safe_call_utils.dart +++ b/packages/core/lib/utils/safe_call_utils.dart @@ -1,14 +1,17 @@ -import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:rasadyar_core/core.dart'; -typedef AsyncCallback = Future Function(); +import '../core.dart'; + +typedef AppAsyncCallback = Future Function(); typedef ErrorCallback = void Function(dynamic error, StackTrace? stackTrace); typedef VoidCallback = void Function(); -// تعریف دقیق تابع safeCall -Future safeCall({ - required AsyncCallback call, +/// this is global safe call function +/// A utility function to safely cal l an asynchronous function with error +/// handling and optional loading, success, and error messages. +/// +Future gSafeCall({ + required AppAsyncCallback call, Function(T result)? onSuccess, ErrorCallback? onError, VoidCallback? onComplete, @@ -17,6 +20,8 @@ Future safeCall({ bool showSuccess = false, bool showToast = false, bool showSnackBar = false, + bool retryOnAuthError = false, + Function()? onTokenRefresh, Function()? onShowLoading, Function()? onHideLoading, Function()? onShowSuccessMessage, @@ -34,18 +39,34 @@ Future safeCall({ } onSuccess?.call(result); - - } catch (error, stackTrace) { - if (showError) { - (onShowErrorMessage ?? _defaultShowErrorMessage)(); + if (retryOnAuthError && isTokenExpiredError(error)) { + try { + await onTokenRefresh?.call(); + final retryResult = await call(); + if (showSuccess) { + (onShowSuccessMessage ?? _defaultShowSuccessMessage)(); + } + onSuccess?.call(retryResult); + return; + } catch (retryError, retryStackTrace) { + if (showError) { + (onShowErrorMessage ?? _defaultShowErrorMessage)(); + } + onError?.call(retryError, retryStackTrace); + if (kDebugMode) { + print('safeCall retry error: $retryError\n$retryStackTrace'); + } + } + } else { + if (showError) { + (onShowErrorMessage ?? _defaultShowErrorMessage)(); + } + onError?.call(error, stackTrace); + if (kDebugMode) { + print('safeCall error: $error\n$stackTrace'); + } } - - onError?.call(error, stackTrace); - if (kDebugMode) { - print('safeCall error: $error\n$stackTrace'); - } - } finally { if (showLoading) { (onHideLoading ?? _defaultHideLoading)(); @@ -69,4 +90,8 @@ void _defaultShowSuccessMessage() { void _defaultShowErrorMessage() { // پیاده‌سازی پیش‌فرض -} \ No newline at end of file +} + +bool isTokenExpiredError(dynamic error) { + return error is DioException && error.response?.statusCode == 401; +} diff --git a/packages/core/test/infrastructure/local/hive_local_storage.dart b/packages/core/test/infrastructure/local/hive_local_storage.dart new file mode 100644 index 0000000..53b7b55 --- /dev/null +++ b/packages/core/test/infrastructure/local/hive_local_storage.dart @@ -0,0 +1,112 @@ +import 'package:flutter/foundation.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'i_local_storage.dart'; + +class HiveLocalStorage implements ILocalStorage { + HiveLocalStorage() { + Hive.initFlutter(); + } + + final Map _boxes = {}; + + @override + Future init() async => await Hive.initFlutter(); + + @override + Future openBox( + String boxName, { + HiveCipher? encryptionCipher, + bool crashRecovery = true, + String? path, + Uint8List? bytes, + String? collection, + }) async { + if (!_boxes.containsKey(boxName)) { + final box = await Hive.openBox( + boxName, + encryptionCipher: encryptionCipher, + crashRecovery: crashRecovery, + ); + _boxes[boxName] = box; + } + } + + @override + T? read({required String boxName, required String key}) { + try { + Box? box = getBox(boxName); + return box?.get(key) as T?; + } on Exception catch (e) { + eLog(e); + return null; + } + } + + @override + Future add({required String boxName, required dynamic value}) async { + Box? box = getBox(boxName); + await box?.add(value); + } + + @override + Future addAll({ + required String boxName, + required Iterable values, + }) async { + Box? box = getBox(boxName); + await box?.addAll(values); + } + + Box? getBox(String boxName) { + final box = _boxes[boxName]; + if (box is Box) { + return box; + } else { + throw Exception('Box $boxName is not of exist'); + } + } + + @override + Future clear(String boxName) async { + await _boxes[boxName]?.clear(); + } + + @override + Future close(String boxName) async => await _boxes[boxName]?.close(); + + @override + Future deleteValue({ + required String boxName, + required String key, + }) async { + Box? box = getBox(boxName); + await box?.delete(key); + } + + @override + Future save({ + required String boxName, + required String key, + required value, + }) async { + Box? box = getBox(boxName); + await box?.put(key, value); + } + + @override + Future saveAll({required String boxName, required Map entries}) async { + Box? box = getBox(boxName); + await box?.putAll(entries); + } + + @override + Future saveAt({ + required String boxName, + required int index, + required value, + }) async { + Box? box = getBox(boxName); + await box?.putAt(index, value); + } +} diff --git a/packages/core/test/infrastructure/local/i_local_storage.dart b/packages/core/test/infrastructure/local/i_local_storage.dart new file mode 100644 index 0000000..7cb4f49 --- /dev/null +++ b/packages/core/test/infrastructure/local/i_local_storage.dart @@ -0,0 +1,44 @@ +import 'package:flutter/foundation.dart'; +import 'package:hive_ce/hive.dart'; + +abstract class ILocalStorage { + Future init(); + + Future openBox( + String boxName, { + HiveCipher? encryptionCipher, + bool crashRecovery = true, + String? path, + Uint8List? bytes, + String? collection, + }); + + T? read({required String boxName, required String key}); + + Future deleteValue({required String boxName, required String key}); + + Future add({required String boxName, required E value}); + + Future addAll({required String boxName, required Iterable values}); + + Future clear(String boxName); + + Future close(String boxName); + + Future save({ + required String boxName, + required String key, + required dynamic value, + }); + + Future saveAt({ + required String boxName, + required int index, + required dynamic value, + }); + + Future saveAll({ + required String boxName, + required Map entries, + }); +} diff --git a/packages/core/test/infrastructure/remote/dio_form_data.dart b/packages/core/test/infrastructure/remote/dio_form_data.dart new file mode 100644 index 0000000..8e74832 --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_form_data.dart @@ -0,0 +1,23 @@ +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_remote_test.dart b/packages/core/test/infrastructure/remote/dio_remote_test.dart new file mode 100644 index 0000000..e69de29 diff --git a/packages/core/test/infrastructure/remote/dio_response.dart b/packages/core/test/infrastructure/remote/dio_response.dart new file mode 100644 index 0000000..30f54eb --- /dev/null +++ b/packages/core/test/infrastructure/remote/dio_response.dart @@ -0,0 +1,20 @@ +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/interfaces/i_form_data.dart b/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart new file mode 100644 index 0000000..ddbda85 --- /dev/null +++ b/packages/core/test/infrastructure/remote/interfaces/i_form_data.dart @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..9550c18 --- /dev/null +++ b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart @@ -0,0 +1,54 @@ + +import 'dart:typed_data'; +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 new file mode 100644 index 0000000..461146a --- /dev/null +++ b/packages/core/test/infrastructure/remote/interfaces/i_http_response.dart @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000..648883b --- /dev/null +++ b/packages/core/test/infrastructure/remote/interfaces/i_remote.dart @@ -0,0 +1,4 @@ +abstract class IRemote{ + Future init(); +} + diff --git a/packages/core/test/injection/di_test.dart b/packages/core/test/injection/di_test.dart new file mode 100644 index 0000000..369847c --- /dev/null +++ b/packages/core/test/injection/di_test.dart @@ -0,0 +1,18 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:logger/logger.dart'; +import 'package:rasadyar_core/core.dart'; + +void main() { + setUp(() async { + await setupAllCoreProvider(); + }); + + group('di', () { + test('is ready', () { + expect(diCore.isRegistered(), isTrue); + expect(diCore.isRegistered(), isTrue); + expect(diCore.get(), isA()); + expect(diCore.get(), isA()); + }); + }); +} diff --git a/packages/core/test/presentation/common/app_color_test.dart b/packages/core/test/presentation/common/app_color_test.dart new file mode 100644 index 0000000..34a174f --- /dev/null +++ b/packages/core/test/presentation/common/app_color_test.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/presentation/common/app_color.dart'; + + +void main() { + group('AppColor', () { + test('blue colors', () { + expect(AppColor.blueLight, const Color(0xFFeaefff)); + expect(AppColor.blueLightHover, const Color(0xFFe0e7ff)); + expect(AppColor.blueLightActive, const Color(0xFFbecdff)); + expect(AppColor.blueNormal, const Color(0xFF2d5fff)); + expect(AppColor.blueNormalHover, const Color(0xFF2956e6)); + expect(AppColor.blueNormalActive, const Color(0xFF244ccc)); + expect(AppColor.blueDark, const Color(0xFF2247bf)); + expect(AppColor.blueDarkHover, const Color(0xFF1b3999)); + expect(AppColor.blueDarkActive, const Color(0xFF142b73)); + expect(AppColor.blueDarker, const Color(0xFF102159)); + }); + + test('green colors', () { + expect(AppColor.greenLight, const Color(0xFFe6faf5)); + expect(AppColor.greenLightHover, const Color(0xFFd9f7f0)); + expect(AppColor.greenLightActive, const Color(0xFFb0efdf)); + expect(AppColor.greenNormal, const Color(0xFF00cc99)); + expect(AppColor.greenNormalHover, const Color(0xFF00b88a)); + expect(AppColor.greenNormalActive, const Color(0xFF00a37a)); + expect(AppColor.greenDark, const Color(0xFF009973)); + expect(AppColor.greenDarkHover, const Color(0xFF007a5c)); + expect(AppColor.greenDarkActive, const Color(0xFF005c45)); + expect(AppColor.greenDarker, const Color(0xFF004736)); + }); + + test('category colors', () { + expect(AppColor.confirm, AppColor.greenNormalActive); + expect(AppColor.warning, AppColor.yellowNormal); + expect(AppColor.error, AppColor.redNormal); + expect(AppColor.info, AppColor.tealNormal); + }); + + + }); +} \ No newline at end of file diff --git a/packages/core/test/presentation/utils/color_utils_test.dart b/packages/core/test/presentation/utils/color_utils_test.dart new file mode 100644 index 0000000..c628757 --- /dev/null +++ b/packages/core/test/presentation/utils/color_utils_test.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/presentation/utils/color_utils.dart'; + +void main() { + group('ColorUtils extension', () { + const baseColor = Color(0xFF42A5F5); + + test('disabledColor returns color with alpha 38', () { + Color disabled = baseColor.disabledColor; + expect(disabled.a, 0.14901960784313725); + expect(disabled.r, baseColor.r); + expect(disabled.g, baseColor.g); + expect(disabled.b, baseColor.b); + }); + + test('hoverColor returns color darkened by 0.5', () { + Color hover = baseColor.hoverColor; + final expected = + HSLColor.fromColor( + baseColor, + ).withLightness((HSLColor.fromColor(baseColor).lightness - 0.5).clamp(0.0, 1.0)).toColor(); + expect(hover.g, expected.g); + }); + + test('pressedColor returns color darkened by 0.1', () { + Color pressed = baseColor.pressedColor; + final expected = + HSLColor.fromColor( + baseColor, + ).withLightness((HSLColor.fromColor(baseColor).lightness - 0.1).clamp(0.0, 1.0)).toColor(); + expect(pressed.r, expected.r); + }); + }); +} diff --git a/packages/core/test/presentation/utils/list_extensions_test.dart b/packages/core/test/presentation/utils/list_extensions_test.dart new file mode 100644 index 0000000..d3a3e76 --- /dev/null +++ b/packages/core/test/presentation/utils/list_extensions_test.dart @@ -0,0 +1,53 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:rasadyar_core/presentation/utils/list_extensions.dart'; + +void main(){ + group('toggle test', (){ + + List list = [1, 2, 3]; + + test('should remove item if it exists', () { + list.toggle(2); + expect(list, [1, 3]); + }); + + + test('should add item if it not exists', () { + list.toggle(10); + expect(list, [1, 3 , 10]); + }); + + + + + }); + group('insert to first item' ,(){ + + List list = [1, 2, 3]; + + test('should insert item at start if it does not exist', () { + list.ensureContainsAtStart(0); + expect(list, [0, 1, 2, 3]); + }); + + test('should not insert item at start if it already exists', () { + list.ensureContainsAtStart(2); + expect(list, [0, 1, 2, 3]); + }); + + + + }); + group('clear and add item' ,(){ + + List list = [1, 2, 3]; + + test('must be clear and add item ', () { + list.resetWith(20); + expect(list, [20]); + }); + + + + }); +} diff --git a/pubspec.yaml b/pubspec.yaml index b8726e5..2ec5d9e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: rasadyar_app description: "A new Flutter project." publish_to: 'none' -version: 1.0.0+1 +version: 1.2.0+2 environment: sdk: ^3.7.2 From f646eac8b0bd2c0c28488127326b7fb7376b77df Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Mon, 2 Jun 2025 09:40:52 +0330 Subject: [PATCH 25/25] chore : optimize --- packages/auth/lib/presentation/pages/auth/logic.dart | 1 - .../test/infrastructure/remote/interfaces/i_http_client.dart | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/auth/lib/presentation/pages/auth/logic.dart b/packages/auth/lib/presentation/pages/auth/logic.dart index 624328a..37b2e2e 100644 --- a/packages/auth/lib/presentation/pages/auth/logic.dart +++ b/packages/auth/lib/presentation/pages/auth/logic.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:rasadyar_auth/auth.dart'; import 'package:rasadyar_auth/data/common/dio_error_handler.dart'; -import 'package:rasadyar_auth/data/models/local/module/module_model.dart'; import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart'; import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; diff --git a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart index 9550c18..3e6327c 100644 --- a/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart +++ b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart @@ -1,5 +1,4 @@ -import 'dart:typed_data'; import 'package:dio/dio.dart'; import 'i_form_data.dart'; import 'i_http_response.dart';