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/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/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/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/images/place_holder.png b/assets/images/place_holder.png new file mode 100644 index 0000000..fe12c5a Binary files /dev/null and b/assets/images/place_holder.png differ diff --git a/assets/vec/inspection.svg.vec b/assets/vec/inspection.svg.vec new file mode 100644 index 0000000..ed9d937 Binary files /dev/null and b/assets/vec/inspection.svg.vec differ diff --git a/assets/vec/liveStock.svg.vec b/assets/vec/liveStock.svg.vec new file mode 100644 index 0000000..469f5a1 Binary files /dev/null and b/assets/vec/liveStock.svg.vec differ diff --git a/assets/vec/place_holder.svg.vec b/assets/vec/place_holder.svg.vec new file mode 100644 index 0000000..caeb6bf Binary files /dev/null and b/assets/vec/place_holder.svg.vec differ diff --git a/assets/vec/search.svg.vec b/assets/vec/search.svg.vec new file mode 100644 index 0000000..da0271d Binary files /dev/null and b/assets/vec/search.svg.vec differ diff --git a/assets/vec/tag_label.svg.vec b/assets/vec/tag_label.svg.vec new file mode 100644 index 0000000..7afb4cd Binary files /dev/null and b/assets/vec/tag_label.svg.vec differ diff --git a/assets/vec/virtual.svg.vec b/assets/vec/virtual.svg.vec new file mode 100644 index 0000000..13b9ec3 Binary files /dev/null and b/assets/vec/virtual.svg.vec differ diff --git a/lib/infrastructure/service/auth_service.dart b/lib/infrastructure/service/auth_service.dart index 3f38f67..9a4a12f 100644 --- a/lib/infrastructure/service/auth_service.dart +++ b/lib/infrastructure/service/auth_service.dart @@ -1,7 +1,9 @@ -import 'package:rasadyar_auth/auth.dart'; +import 'package:rasadyar_app/presentation/routes/app_pages.dart'; +import 'package:rasadyar_auth/data/models/local/module/module_model.dart'; import 'package:rasadyar_auth/data/services/token_storage_service.dart'; import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_inspection/inspection.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; class AuthService extends GetxService { var tokenService = Get.find(); @@ -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/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/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/core/lib/presentation/common/assets.dart b/lib/presentations/common/assets.dart similarity index 51% rename from packages/core/lib/presentation/common/assets.dart rename to lib/presentations/common/assets.dart index 0e70b14..2ee3b2b 100644 --- a/packages/core/lib/presentation/common/assets.dart +++ b/lib/presentations/common/assets.dart @@ -16,7 +16,9 @@ class Assets { 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'; @@ -28,6 +30,7 @@ class Assets { 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'; @@ -36,37 +39,5 @@ class Assets { 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/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..0c56166 100644 --- a/packages/auth/lib/data/services/token_storage_service.dart +++ b/packages/auth/lib/data/services/token_storage_service.dart @@ -1,69 +1,59 @@ 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 { + await Hive.initFlutter(); + Hive.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, - ); + 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(); } + 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/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 b4abe2c..b46fdff 100644 --- a/packages/auth/lib/hive_registrar.g.dart +++ b/packages/auth/lib/hive_registrar.g.dart @@ -8,11 +8,14 @@ import 'package:rasadyar_auth/data/models/local/user_local/user_local_model.dart extension HiveRegistrar on HiveInterface { void registerAdapters() { registerAdapter(UserLocalModelAdapter()); + registerAdapter(ModuleAdapter()); + } } 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..37b2e2e 100644 --- a/packages/auth/lib/presentation/pages/auth/logic.dart +++ b/packages/auth/lib/presentation/pages/auth/logic.dart @@ -7,9 +7,12 @@ 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'; +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; @@ -68,13 +73,12 @@ class AuthLogic extends GetxController { @override void onInit() { super.onInit(); - tokenStorageService.init(); } @override void onReady() { - // TODO: implement onReady super.onReady(); + iLog('module111 : ${_module.toString()}'); } @override @@ -106,15 +110,15 @@ 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!); - //Get.offAndToNamed(Routes.home); + await tokenStorageService.saveModule(_module); + await tokenStorageService.saveRefreshToken(result?.refresh ?? ''); + await tokenStorageService.saveAccessToken(result?.access ?? ''); }, onError: (error, stackTrace) { if (error is DioException) { 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/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/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/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 0000000..8603d0a Binary files /dev/null and b/packages/core/build/unit_test_assets/packages/flutter_map/lib/assets/flutter_map_logo.png differ diff --git a/packages/core/lib/core.dart b/packages/core/lib/core.dart index 6108fd6..0197984 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'; @@ -24,7 +26,7 @@ export 'infrastructure/local/hive_local_storage.dart'; //export 'package:encrypt/encrypt.dart' show Encrypted; //Map and location -export 'package:latlong2/latlong.dart'; +export 'package:latlong2/latlong.dart' ; export 'package:persian_datetime_picker/persian_datetime_picker.dart'; export 'package:rasadyar_core/presentation/common/common.dart'; export 'package:rasadyar_core/presentation/utils/utils.dart'; diff --git a/packages/core/lib/presentation/common/app_fonts.dart b/packages/core/lib/presentation/common/app_fonts.dart index dd5d433..c850c32 100644 --- a/packages/core/lib/presentation/common/app_fonts.dart +++ b/packages/core/lib/presentation/common/app_fonts.dart @@ -107,6 +107,15 @@ class AppFonts { height: _height, ); + + static const TextStyle yekan8= TextStyle( + // Rounded from 10.24 + fontFamily: yekan, + fontWeight: regular, + fontSize: 8, + height: _height, + ); + static const TextStyle yekan61Bold = TextStyle( fontFamily: yekan, fontWeight: bold, // Use bold weight 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..c289778 --- /dev/null +++ b/packages/core/lib/presentation/common/assets.gen.dart @@ -0,0 +1,486 @@ +/// 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/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'); + + /// 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/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'); + + /// File path: assets/icons/setting.svg + SvgGenImage get setting => 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'); + + /// 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'); + + /// File path: assets/icons/virtual.svg + SvgGenImage get virtual => const SvgGenImage('assets/icons/virtual.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, + placeHolder, + profileCircle, + profileUser, + receiptDiscount, + scan, + scanBarcode, + search, + securityTime, + setting, + tagLabel, + tagUser, + trash, + user, + userSquare, + virtual, + ]; +} + +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'); + + /// 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, placeHolder]; +} + +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/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'); + + /// 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/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'); + + /// 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'); + + /// 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'); + + /// 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 => [ + addSvg, + arrowLeftSvg, + arrowRightSvg, + bgHeaderUserProfileSvg, + calendarSvg, + calendarSearchSvg, + callSvg, + diagramSvg, + downloadSvg, + editSvg, + excelDownloadSvg, + filterSvg, + gpsSvg, + informationSvg, + inspectionSvg, + keySvg, + liveStockSvg, + logoutSvg, + mapSvg, + mapMarkerSvg, + messageAddSvg, + pdfDownloadSvg, + pictureFrameSvg, + placeHolderSvg, + profileCircleSvg, + profileUserSvg, + receiptDiscountSvg, + scanSvg, + scanBarcodeSvg, + searchSvg, + securityTimeSvg, + settingSvg, + tagLabelSvg, + tagUserSvg, + trashSvg, + userSvg, + userSquareSvg, + virtualSvg, + ]; +} + +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/utils/color_utils.dart b/packages/core/lib/presentation/utils/color_utils.dart index 46f9bb8..19bea54 100644 --- a/packages/core/lib/presentation/utils/color_utils.dart +++ b/packages/core/lib/presentation/utils/color_utils.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; extension ColorUtils on Color { Color _darken([double amount = 0.1]) { - assert(amount >= 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/presentation/widget/app_bar/r_app_bar.dart b/packages/core/lib/presentation/widget/app_bar/r_app_bar.dart index 47f7da9..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 @@ -8,9 +8,12 @@ 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; + final int? leadingWidth; final Widget? leading; const RAppBar({ @@ -22,6 +25,9 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { this.onBackPressed, this.additionalActions, this.leading, + this.hasBack = true, + this.centerTitle = false, + this.leadingWidth }); @override @@ -32,25 +38,32 @@ class RAppBar extends StatelessWidget implements PreferredSizeWidget { elevation: 0, excludeHeaderSemantics: true, scrolledUnderElevation: 0, + centerTitle: centerTitle, titleTextStyle: 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!, - 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/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/bottom_sheet/base_bottom_sheet.dart b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart new file mode 100644 index 0000000..cb646f0 --- /dev/null +++ b/packages/core/lib/presentation/widget/bottom_sheet/base_bottom_sheet.dart @@ -0,0 +1,60 @@ +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, this.height, this.bgColor}); + + final Widget child; + final double? height; + final Color? bgColor; + + @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:bgColor?? 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/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 diff --git a/packages/core/lib/presentation/widget/buttons/fab.dart b/packages/core/lib/presentation/widget/buttons/fab.dart index 3dfe651..3a33df7 100644 --- a/packages/core/lib/presentation/widget/buttons/fab.dart +++ b/packages/core/lib/presentation/widget/buttons/fab.dart @@ -1,8 +1,8 @@ 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 +22,7 @@ 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 +30,7 @@ class RFab extends StatefulWidget { RFab.add({required VoidCallback? onPressed, Key? key}) : this( onPressed: onPressed, - icon: vecWidget(Assets.vecAddSvg), + icon: Assets.vec.addSvg.svg(width: 40, height: 40), backgroundColor: AppColor.greenNormal, key: key, ); @@ -41,7 +41,7 @@ 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 +49,7 @@ 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 +60,7 @@ 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 +68,7 @@ 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 +79,7 @@ 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 +87,7 @@ 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 +98,7 @@ 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 +106,7 @@ 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 +117,7 @@ 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 +125,7 @@ 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 +136,7 @@ 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 +144,7 @@ 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 +155,7 @@ 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 +163,7 @@ 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/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/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..ca7d2b6 --- /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(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Colors.white, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgGenImage(icon).svg(width: 50, height: 50), + const SizedBox(height: 8), + Text( + title, + style: AppFonts.yekan16.copyWith(color: AppColor.blueNormal), + ), + ], + ), + ), + ), + ); + } +} 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..7788061 --- /dev/null +++ b/packages/core/lib/presentation/widget/chips/r_chips.dart @@ -0,0 +1,112 @@ +import 'package:flutter/cupertino.dart'; +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.whiteGreyDark, + }); + + 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), + 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/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/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), + ), + ), + ], + ), + ); + } +} 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 new file mode 100644 index 0000000..78ab225 --- /dev/null +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -0,0 +1,170 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:flutter_map_animations/flutter_map_animations.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:get/get.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:rasadyar_core/utils/logger_utils.dart'; + +import '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 allMarkers = [].obs; + Rx mapController = MapController().obs; + RxList errorLocationType = RxList(); + 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, + ); + 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(); + } + + @override + void onClose() { + super.onClose(); + _debounceTimer?.cancel(); + animatedMapController.dispose(); + 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), + ); + final latLng = LatLng(position.latitude, position.longitude); + + currentLocation.value = latLng; + markers.add( + CustomMarker(id: -1, point: 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(); + } + + 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 new file mode 100644 index 0000000..4204919 --- /dev/null +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:get/get.dart'; +import 'package:rasadyar_core/presentation/common/app_color.dart'; +import 'package:rasadyar_core/presentation/common/app_fonts.dart'; +import 'package:rasadyar_core/presentation/common/assets.gen.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/elevated.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/outline_elevated.dart'; + +import 'logic.dart'; + +class MapWidget extends GetView { + final VoidCallback? initOnTap; + final Widget? initMarkerWidget; + final Widget markerWidget; + + const MapWidget({ + this.initOnTap, + this.initMarkerWidget, + required this.markerWidget, + super.key, + }); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + ObxValue((errorType) { + if (errorType.isNotEmpty) { + if (errorType.contains(ErrorLocationType.serviceDisabled)) { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text('سرویس مکان‌یابی غیرفعال است'), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + var service = await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove( + ErrorLocationType.serviceDisabled, + ); + Get.back(); + } + // Don't call Get.back() if service is still disabled + }, + ), + confirm: RElevated( + text: 'روشن کردن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await Geolocator.openLocationSettings(); + if (res) { + var service = await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove( + ErrorLocationType.serviceDisabled, + ); + Get.back(); + } + } + }, + ), + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } else { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text(' دسترسی به سرویس مکان‌یابی غیرفعال است'), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + await controller.checkPermission(); + }, + ), + confirm: RElevated( + text: 'اجازه دادن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await controller.checkPermission(request: true); + if (res) { + controller.errorLocationType.remove( + ErrorLocationType.permissionDenied, + ); + Get.back(); + } + }, + ), + + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } + } + return const SizedBox.shrink(); + }, controller.errorLocationType), + _buildMap(), + _buildGpsButton(), + _buildFilterButton(), + ], + ); + } + + Widget _buildMap() { + return ObxValue((currentLocation) { + return FlutterMap( + mapController: controller.animatedMapController.mapController, + options: MapOptions( + initialCenter: currentLocation.value, + initialZoom: 18, + onPositionChanged: (camera, hasGesture) { + if (hasGesture) { + controller.debouncedUpdateVisibleMarkers(center: camera.center); + } + //controller.debouncedUpdateVisibleMarkers(center: camera.center); + }, + ), + children: [ + TileLayer(urlTemplate: controller.tileType), + ObxValue((markers) { + return MarkerLayer( + markers: + markers + .map( + (e) => Marker( + point: e.point, + child: GestureDetector( + onTap: e.id != -1 ? e.onTap : initOnTap, + child: + e.id != -1 + ? markerWidget + : initMarkerWidget ?? SizedBox.shrink(), + ), + ), + ) + .toList(), + ); + }, controller.markers), + ], + ); + }, controller.currentLocation); + } + + Widget _buildGpsButton() { + return Positioned( + right: 10, + bottom: 83, + child: ObxValue((data) { + return RFab.small( + backgroundColor: AppColor.greenNormal, + isLoading: data.value, + icon: Assets.vec.gpsSvg.svg(), + onPressed: () async { + controller.isLoading.value = true; + await controller.determineCurrentPosition(); + controller.isLoading.value = false; + }, + ); + }, controller.isLoading), + ); + } + + Widget _buildFilterButton() { + return Positioned( + right: 10, + bottom: 30, + child: RFab.small( + backgroundColor: AppColor.blueNormal, + icon: Assets.vec.filterSvg.svg(width: 24, height: 24), + onPressed: () {}, + ), + ); + } + + /*Marker markerWidget({required LatLng marker, required VoidCallback onTap}) { + return Marker( + point: marker, + child: GestureDetector( + onTap: onTap, + behavior: HitTestBehavior.opaque, + child: SizedBox( + width: 36, + height: 36, + child: Assets.vec.mapMarkerSvg.svg(width: 30, height: 30), + ), + ), + ); + }*/ +} diff --git a/packages/core/lib/presentation/widget/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, + ), + ], + ), + ), + ); + } +} 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..52c3f21 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'; @@ -14,3 +15,8 @@ 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'; +export 'chips/r_chips.dart'; +export 'overlay_dropdown_widget/view.dart'; +export 'inputs/input_fixed_hint.dart'; +export 'bottom_sheet/base_bottom_sheet.dart'; 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/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/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..3e6327c --- /dev/null +++ b/packages/core/test/infrastructure/remote/interfaces/i_http_client.dart @@ -0,0 +1,53 @@ + +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/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/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/.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/lib/livestock.dart b/packages/livestock/lib/livestock.dart new file mode 100644 index 0000000..6289ca5 --- /dev/null +++ b/packages/livestock/lib/livestock.dart @@ -0,0 +1,6 @@ +/// Support for doing something awesome. +/// +/// More dartdocs go here. +library; + + 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..04370f3 --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/logic.dart @@ -0,0 +1,8 @@ +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 new file mode 100644 index 0000000..6935217 --- /dev/null +++ b/packages/livestock/lib/presentation/page/map/view.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +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 Scaffold( + body: Stack( + children: [ + MapWidget( + markerWidget: Icon(Icons.pin_drop_rounded), + initOnTap: () { + + }, + initMarkerWidget: Assets.vec.mapMarkerSvg.svg( + width: 30, + height: 30, + ), + ), + + ], + ), + ); + } +} + 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/request_tagging/logic.dart b/packages/livestock/lib/presentation/page/request_tagging/logic.dart new file mode 100644 index 0000000..de94cdb --- /dev/null +++ b/packages/livestock/lib/presentation/page/request_tagging/logic.dart @@ -0,0 +1,17 @@ +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(); + } + + @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..0ff57ed --- /dev/null +++ b/packages/livestock/lib/presentation/page/request_tagging/view.dart @@ -0,0 +1,109 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.dart'; +import 'package:rasadyar_livestock/presentation/routes/app_pages.dart'; + +import 'logic.dart'; + +class RequestTaggingPage extends GetView { + const RequestTaggingPage({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(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/logic.dart b/packages/livestock/lib/presentation/page/requests/logic.dart new file mode 100644 index 0000000..bf98dd3 --- /dev/null +++ b/packages/livestock/lib/presentation/page/requests/logic.dart @@ -0,0 +1,9 @@ +import 'package:rasadyar_core/core.dart'; +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 new file mode 100644 index 0000000..2b73f22 --- /dev/null +++ b/packages/livestock/lib/presentation/page/requests/view.dart @@ -0,0 +1,302 @@ +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: 8), + _buildSearchAndFilter(), + _buildFilterWidget(), + _buildListOfContent(), + RElevated( + text: '+ ایجاد درخواست', + width: Get.width - 36, + height: 40, + textStyle: AppFonts.yekan18.copyWith(color: Colors.white), + onPressed: () { + //TODO + }, + ), + SizedBox(height: 10), + ], + ), + ); + } + + Expanded _buildListOfContent() { + return Expanded( + 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( + 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, + ), + ), + ), + ), + ], + ), + 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() { + 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.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(), + ), + ); + } +} 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..0aed723 --- /dev/null +++ b/packages/livestock/lib/presentation/page/root/logic.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_core/core.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 = [ + 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 + void onReady() { + // TODO: implement onReady + super.onReady(); + } + + @override + void onClose() { + // 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 new file mode 100644 index 0000000..f506375 --- /dev/null +++ b/packages/livestock/lib/presentation/page/root/view.dart @@ -0,0 +1,75 @@ +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 ObxValue((currentIndex) { + + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, result) { + final navigatorKey = Get.nestedKey(currentIndex); + eLog('Pop invoked with result: $result, didPop: $didPop'); + navigatorKey?.currentState?.pop(); + + /*eLog('Pop invoked with result: $result, didPop: $didPop'); + iLog(Get.currentRoute); + iLog(Get.previousRoute); + + final navigatorKey = Get.nestedKey(currentIndex); + + if (currentIndex.value == 0 && + navigatorKey != null && + navigatorKey.currentState != null) { + if (navigatorKey.currentState!.canPop()) { + navigatorKey.currentState!.pop(); + return; + } + + if (!didPop) { + return; + } + }*/ + }, + + child: Scaffold( + body: IndexedStack( + children: [...controller.pages], + index: currentIndex.value, + sizing: StackFit.expand, + ), + extendBody: true, + 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/page/tagging/logic.dart b/packages/livestock/lib/presentation/page/tagging/logic.dart new file mode 100644 index 0000000..30e8316 --- /dev/null +++ b/packages/livestock/lib/presentation/page/tagging/logic.dart @@ -0,0 +1,20 @@ +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() { + // 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..6e21741 --- /dev/null +++ b/packages/livestock/lib/presentation/page/tagging/view.dart @@ -0,0 +1,764 @@ +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), + 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: Stack( + children: [ + Column( + children: [ + _buildFilterWidget(), + _buildSearchWidget(), + _buildInfoDetails(), + _buildListContent(), + SizedBox(height: 10), + + Padding( + padding: const EdgeInsets.fromLTRB(35, 0, 35, 20), + child: RElevated( + text: 'ثبت نهایی و ارسال به اتحادیه', + textStyle: AppFonts.yekan18, + height: 40, + backgroundColor: AppColor.greenNormal, + onPressed: () {}, + isFullWidth: true, + ), + ), + ], + ), + Positioned( + right: 10, + bottom: 75, + child: RFab.add( + onPressed: () { + Get.bottomSheet(_buildBottomSheet(), isScrollControlled: true); + }, + ), + ), + ], + ), + ); + } + + Container _buildInfoDetails() { + return Container( + height: 40, + 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), + ), + ), + ], + ), + ), + ), + ], + ); + } + + 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( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 8, + children: [ + _buildLiveStockSpecies(), + _buildLivestockBirthday(), + _buildLivestockGender(), + + _buildLivestockBreed(), + + _buildMotherTagNumber(), + _buildFatherTagNumber(), + _buildTagNumber(), + _buildTagType(), + + _buildLiveStockImage(), + + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: RElevated( + text: 'افزودن دام به گله', + textStyle: AppFonts.yekan18.copyWith(color: Colors.white), + width: Get.width, + backgroundColor: AppColor.greenNormal, + height: 40, + onPressed: () { + Get.back(); + }, + ), + ), + ], + ), + ); + } + + Widget _buildInfoBottomSheet() { + return BaseBottomSheet( + height: Get.height * 0.5, + bgColor: const Color(0xFFF5F5F5), + child: Card( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + spacing: 15, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Assets.vec.editSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + Text('محمد احمدی', style: AppFonts.yekan14), + + GestureDetector( + onTap: () { + _buildDeleteDialog(onConfirm: () { + + }); + }, + child: Assets.vec.trashSvg.svg( + width: 16, + height: 16, + colorFilter: ColorFilter.mode(AppColor.error, BlendMode.srcIn), + ), + ), + ], + ), + Container( + height: 32, + padding: EdgeInsets.all(8), + decoration: BoxDecoration(color: AppColor.blueLightHover), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'تاریخ ثبت', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '1404/2/2', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شماره پلاک', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '123456789012346', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'جنسیت ', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'ماده', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع نژاد', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'افشاری', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'نوع گله', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'روستایی', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'شهر', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + 'کرج', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'سن', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + Text( + '18 ماه', + textAlign: TextAlign.center, + style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark), + ), + ], + ), + ], + ), + ), + ), + ); + } + + void _buildDeleteDialog({required VoidCallback onConfirm}) { + Get.defaultDialog( + title: 'حذف دام', + middleText: 'آیا از حذف این دام مطمئن هستید؟', + confirm: ElevatedButton( + style: ElevatedButton.styleFrom(backgroundColor: AppColor.error, foregroundColor: Colors.white), + onPressed: onConfirm, + child: Text('بله'), + ), + cancel: ElevatedButton( + onPressed: () { + Get.back(); + }, + child: Text('خیر'), + ), + ); + } + + SizedBox _buildLiveStockImage() { + return SizedBox( + width: Get.width, + height: 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( + height: 40, + width: Get.width, + padding: const EdgeInsets.symmetric(horizontal: 12), + decoration: BoxDecoration( + border: Border.all(color: AppColor.darkGreyLight), + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('تاریخ تولد', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive)), + Text('1404/5/5', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyNormalActive)), + ], + ), + ); + } + + OverlayDropdownWidget _buildLiveStockSpecies() { + return OverlayDropdownWidget( + items: ['گوسفند ماده', 'گوسفند نر', 'بز ماده', 'بز نر', 'گوساله ماده', 'گوساله نر'], + onChanged: (value) { + print('Selected: $value'); + }, + itemBuilder: (item) => Text(item), + labelBuilder: (item) => Text(item ?? 'گونه دام'), + ); + } + + ObxValue _buildFilterWidget() { + return ObxValue((data) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: EdgeInsets.only(top: 5), + curve: Curves.easeInOut, + height: data.value ? 50 : 0, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: EdgeInsets.symmetric(horizontal: 12), + child: ObxValue((data) { + return Row( + spacing: 12, + children: [ + CustomChip( + title: 'انتخاب فیلتر', + index: 0, + isSelected: true, + selectedColor: AppColor.blueNormal, + onTap: (index) {}, + ), + + RFilterChips( + title: 'درخواست‌های من', + index: 1, + isSelected: data.contains(1), + selectedColor: AppColor.yellowNormal, + onTap: (index) { + if (data.contains(1)) { + data.remove(1); + } else { + data.add(1); + } + }, + ), + + RFilterChips( + title: 'در انتظار ثبت ', + index: 2, + selectedColor: AppColor.greenLightActive, + isSelected: data.contains(2), + onTap: (index) { + if (data.contains(2)) { + data.remove(2); + } else { + data.add(2); + } + }, + ), + + RFilterChips( + title: 'ارجاع به تعاونی', + index: 3, + selectedColor: AppColor.blueLightHover, + isSelected: data.contains(3), + onTap: (index) { + if (data.contains(3)) { + data.remove(3); + } else { + data.add(3); + } + }, + ), + ], + ); + }, controller.filterSelected), + ), + ); + }, controller.filterIsSelected); + } + + ObxValue _buildSearchWidget() { + return ObxValue((data) { + return AnimatedContainer( + duration: Duration(milliseconds: 300), + padding: EdgeInsets.only(top: 5), + curve: Curves.easeInOut, + height: data.value ? 50 : 0, + child: Visibility( + visible: data.value, + child: Padding( + padding: const EdgeInsets.only(right: 8.0, left: 20.0), + child: RTextField( + suffixIcon: Padding( + padding: const EdgeInsets.all(12.0), + child: Assets.vec.searchSvg.svg( + width: 10, + height: 10, + colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), + ), + ), + hintText: 'جستجو', + onChanged: (value) { + //controller.search(value); + }, + controller: TextEditingController(), + ), + ), + ), + ); + }, controller.searchIsSelected); + } +} 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..1ca33e7 --- /dev/null +++ b/packages/livestock/lib/presentation/routes/app_pages.dart @@ -0,0 +1,62 @@ +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/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'; +import 'package:rasadyar_livestock/presentation/page/tagging/logic.dart'; +import 'package:rasadyar_livestock/presentation/page/tagging/view.dart'; + +part 'app_routes.dart'; + +sealed class LiveStockPages { + LiveStockPages._(); + + static final pages = [ + GetPage( + name: LiveStockRoutes.init, + page: () => RootPage(), + middlewares: [AuthMiddleware()], + binding: BindingsBuilder(() { + Get.put(RootLogic()); + Get.lazyPut(() => RequestsLogic()); + Get.lazyPut(() => MapLogic()); + Get.lazyPut(() => ProfileLogic()); + Get.lazyPut(() => ProfileLogic()); + Get.lazyPut(() => MapWidgetLogic()); + Get.lazyPut(() => DraggableBottomSheetController()); + }), + children: [ + /*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 new file mode 100644 index 0000000..95a777a --- /dev/null +++ b/packages/livestock/lib/presentation/routes/app_routes.dart @@ -0,0 +1,13 @@ +part of 'app_pages.dart'; + +sealed class LiveStockRoutes { + LiveStockRoutes._(); + + static const init = '/liveStock'; + static const requests = '/requests'; + static const profile = '/profile'; + + //static const requestTagging = '$init/tagging'; + static const requestTagging = '$requests/tagging'; + static const tagging = '/tagging'; +} diff --git a/packages/livestock/pubspec.yaml b/packages/livestock/pubspec.yaml new file mode 100644 index 0000000..9f8ba58 --- /dev/null +++ b/packages/livestock/pubspec.yaml @@ -0,0 +1,37 @@ +name: rasadyar_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: + sdk: ^3.7.2 + + +dependencies: + flutter: + sdk: flutter + rasadyar_core: + path: ../core + rasadyar_auth: + path: ../auth + ##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 + + diff --git a/packages/livestock/test/livestock_test.dart b/packages/livestock/test/livestock_test.dart new file mode 100644 index 0000000..534cb37 --- /dev/null +++ b/packages/livestock/test/livestock_test.dart @@ -0,0 +1,5 @@ + + +void main() { + +} 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: diff --git a/pubspec.yaml b/pubspec.yaml index 95fc0f1..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 @@ -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 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 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 + + diff --git a/tools/vecGeneratoe.sh b/tools/vecGeneratoe.sh index 4f92558..4c6cf89 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="../assets/icons" +targetPath="../assets/vec" +echo "🗃️ sourcePath path: $sourcePath" +echo "🗃️ targetPath path: $targetPath" if [ ! -e "$targetPath" ]; then