From 884b4f155687a9be8a6e43742ae2c625244f3b9c Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Tue, 23 Sep 2025 11:18:33 +0330 Subject: [PATCH] fix : some ui and --- assets/icons/active_fram.svg | 6 + assets/icons/chicken_inspection.svg | 10 ++ assets/icons/farms.svg | 9 ++ assets/icons/registerKill.svg | 14 +++ assets/vec/active_fram.svg.vec | Bin 0 -> 3321 bytes assets/vec/farms.svg.vec | Bin 0 -> 5206 bytes assets/vec/registerKill.svg.vec | Bin 0 -> 2853 bytes integration_test/app_test.dart | 76 ++++++++++++ .../pages/poultry_science/farm/logic.dart | 9 +- .../pages/poultry_science/home/view.dart | 8 +- .../killing_registration/logic.dart | 14 +-- .../killing_registration/view.dart | 22 +--- .../poultry_science/poultry_action/logic.dart | 8 +- .../lib/presentation/routes/pages.dart | 2 +- packages/chicken/pubspec.yaml | 2 +- .../lib/presentation/common/assets.gen.dart | 32 +++++ .../utils/first_digit_decimal_formatter.dart | 24 ++++ packages/core/lib/utils/utils.dart | 1 + packages/core/pubspec.lock | 4 +- pubspec.lock | 117 ++++++++++-------- pubspec.yaml | 14 ++- 21 files changed, 271 insertions(+), 101 deletions(-) create mode 100644 assets/icons/active_fram.svg create mode 100644 assets/icons/chicken_inspection.svg create mode 100644 assets/icons/farms.svg create mode 100644 assets/icons/registerKill.svg create mode 100644 assets/vec/active_fram.svg.vec create mode 100644 assets/vec/farms.svg.vec create mode 100644 assets/vec/registerKill.svg.vec create mode 100644 integration_test/app_test.dart create mode 100644 packages/core/lib/utils/first_digit_decimal_formatter.dart diff --git a/assets/icons/active_fram.svg b/assets/icons/active_fram.svg new file mode 100644 index 0000000..6ce9f47 --- /dev/null +++ b/assets/icons/active_fram.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/icons/chicken_inspection.svg b/assets/icons/chicken_inspection.svg new file mode 100644 index 0000000..4807d12 --- /dev/null +++ b/assets/icons/chicken_inspection.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/farms.svg b/assets/icons/farms.svg new file mode 100644 index 0000000..0c98468 --- /dev/null +++ b/assets/icons/farms.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/registerKill.svg b/assets/icons/registerKill.svg new file mode 100644 index 0000000..deb6c49 --- /dev/null +++ b/assets/icons/registerKill.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/assets/vec/active_fram.svg.vec b/assets/vec/active_fram.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..d420f34ea3feb948b7b508a626088c241247151e GIT binary patch literal 3321 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 literal 0 HcmV?d00001 diff --git a/assets/vec/registerKill.svg.vec b/assets/vec/registerKill.svg.vec new file mode 100644 index 0000000000000000000000000000000000000000..db8807f1827dee7d59d98d0a2a466bb4cab59e83 GIT binary patch literal 2853 zcmY+G3s6)?7KZPg8IcsDD8&Nq42YD^5&?C=XtL6OtI<*v5{*fzAeE?Fx*=*bC_WYh ziK6kX;DeXSfXEw$SSAaCt}z-!T}2dG!;mP^t@wa|sL|OzeTUTMQp0!8>2v<>zJ0py z{b~`%=6?fj`QxxG%VB$AX*W*)F;q!&?h3bXRq$tWP@l#Zt z_NUV>Rn-ZHxYVBOciRy`Ei!;&=ti#ykM?hZswhb;gr9kJ5=qR9kD4?KGah>Kx2wXC zwZW5n9hiYzswX$JO-HHzJT4R~7<~F161Uq~S;Se%Ax^c@KiwFF{aw?MIw$}vX9nVz z`D0OC7&7{gMAdtlj#yQWIy-ek#SKmdR|~;WC`IOl1Y(<=DJw20Qt*9GBmUU`y6i zz@uvpd-Picyw}WQTR*m9@~6?v&0@uY#Y@ z!tI%?-gywWxg2M$2M6&#eVNCahx_qMxkaot&QHWyCH-|CAp7T_0g^K(nn7`Y`-cxG zZ%wr?NXMx21L+c}AEJA)k8H1a=q=;Fp6AUeKlhT^p=airzFG8FC;HPE&a!dk*#u-H zM8iovhrefe!EKT|pPLnpq=XTi+KCjOl;Hh46Fa^Yes4Zv!Fgl`ias08At%esS680J z9#=D;d7u_SVJ4o~Q6u91ENRqj0NL}euayk__H$6&ljK#Pykk>Vf^>|!6(C(A^+UX~ z?K|0?(f^W+|JUg6LHVcNt#jzri8#`)!(^8V2lJ4)suBPFC>QtI8*%fd1)uM`h2Z5D zM9sL3?|NG>Ro{du7jj^!Z^HAk9PG}%gSF{7*zj31QpW12>jwqh$it?$> zG(A6uzMoicf3eQHKRH0i*-}S z@N_>bj`bSLBb%*Iu8rlizt*Pzg`eqLiCv3=`Rrt|uU-Xn+NVCLAv|trIqdBrJo1-P zq}f9_?e`$#IKJ^r5!PJ@;o*UW;#_i^PYIqp?w|+%aQrp7?n%O?Iv|qYNxg{vUp1ih zmbu(~`}NC6eb|^MytUy3%q$dAohHrH-?ICbkJ(;y!c|+2+?zW8Ux2_qK_eR_g zP?jGT&#^`9yG%*yhivWn(jJV(L=i{hqC6TW=}dkR4U^CfXHoLG(tLX6XHs;E@ek{+ z>H~!RysRDr44V+q=PKsB7Z2;Se@nXLT$lcj?KiMuVIqiY(>H_s`tD@(t*(K3_aFv) z*5IqnhcI^R89e>*5MEEJmK^hb6{>_?`q@9RNwmNG{u>$JIlo-Ya~IxH%W&Lnr`YFZ z2yNUB^0%$uhJ;fUVy#oK_18*C_lQ%{PrAKV>=EadHeQqXSa8wiBVX&{UG7gNbO$i0 z=&2afe)!ft!OFkx$9U^w$=RuoBojLxqCF^0d{z96bJq_`?vKrs^jLOO?5l^OUXOy} z+l&^;4CMqGQl5fn@$Zx@xY8}#N1b~qQurEuo_-;DyJ`oV3%k+7n)zwi_d?-4WP|sh zn;SSWYI|?Vb~hs*@G+-X8S&)xaCwj>5RlC>j6Ijjt?Bg{7|-?{_OjGB$jTq}R~dk}>B)ByXC% zu}#F;!<|8SMAG?x9^b3kP7d-G13%i&glV>y;ypMHXI^!pWXK%xUV4I!#jCN4cVNng z$tb9Pg<;uAh>UrS>e@|sv+XtdUx=5Cj*XG*N{d3Qubva%% mockGService.init()).thenAnswer((_) async {}); + when(() => mockGService.isFirstTime()).thenReturn(false); + when(() => mockGService.setIsNotFirstTime()).thenAnswer((_) async {}); + when(() => mockTokenService.init()).thenAnswer((_) async {}); + + // Put mocks in GetX + Get.put(mockGService); + Get.put(mockTokenService); + }); + + tearDown(() { + Get.reset(); + }); + + testWidgets('should navigate through splash to modules page', (WidgetTester tester) async { + // Start the app + app.main(); + await tester.pumpAndSettle(); + + // Verify splash screen is displayed + expect(find.byType(Scaffold), findsOneWidget); + + // Wait for splash screen animations and navigation + await tester.pumpAndSettle(const Duration(seconds: 3)); + + // Should navigate to modules page or auth page based on authentication state + expect(find.byType(Scaffold), findsOneWidget); + }); + + testWidgets('should display correct app title and theme', (WidgetTester tester) async { + // Start the app + app.main(); + await tester.pumpAndSettle(); + + // Verify app structure + final materialApp = tester.widget(find.byType(GetMaterialApp)); + expect(materialApp.title, 'رصدیار'); + expect(materialApp.locale, const Locale("fa", "IR")); + }); + + testWidgets('should handle navigation between pages', (WidgetTester tester) async { + // Start the app + app.main(); + await tester.pumpAndSettle(); + + // Wait for initial navigation + await tester.pumpAndSettle(const Duration(seconds: 2)); + + // Verify that navigation works + expect(find.byType(Scaffold), findsOneWidget); + }); + }); +} diff --git a/packages/chicken/lib/presentation/pages/poultry_science/farm/logic.dart b/packages/chicken/lib/presentation/pages/poultry_science/farm/logic.dart index 3f7c0d4..3c62afa 100644 --- a/packages/chicken/lib/presentation/pages/poultry_science/farm/logic.dart +++ b/packages/chicken/lib/presentation/pages/poultry_science/farm/logic.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/data/models/response/poultry_farm/poultry_farm.dart'; - import 'package:rasadyar_chicken/presentation/pages/poultry_science/home/logic.dart'; import 'package:rasadyar_chicken/presentation/pages/poultry_science/root/logic.dart'; import 'package:rasadyar_core/core.dart'; @@ -14,7 +13,7 @@ class FarmLogic extends GetxController { labelTitle: 'کل فارم ها', isLoading: true, labelVecIcon: Assets.vec.cubeScanSvg.path, - blendMode: BlendMode.dst, + iconColor: AppColor.blueNormalOld, valueBgColor: Colors.white, labelGradient: LinearGradient( begin: Alignment.topCenter, @@ -90,10 +89,7 @@ class FarmLogic extends GetxController { count: res?.count ?? 0, next: res?.next, previous: res?.previous, - results: [ - ...(farmList.value.data?.results ?? []), - ...?res?.results, - ], + results: [...(farmList.value.data?.results ?? []), ...?res?.results], ), ); } @@ -101,6 +97,7 @@ class FarmLogic extends GetxController { onError: (error, stackTrace) {}, ); } + void toggleExpanded(int index) { expandedIndex.value = expandedIndex.value == index ? -1 : index; } diff --git a/packages/chicken/lib/presentation/pages/poultry_science/home/view.dart b/packages/chicken/lib/presentation/pages/poultry_science/home/view.dart index 83509c4..d77aed0 100644 --- a/packages/chicken/lib/presentation/pages/poultry_science/home/view.dart +++ b/packages/chicken/lib/presentation/pages/poultry_science/home/view.dart @@ -68,7 +68,7 @@ class PoultryScienceHomePage extends GetView { colorFilter: ColorFilter.mode(AppColor.iconColor, BlendMode.srcIn), ), Text( - 'فارم های مرغ گوشتی', + 'اطلاعات فارم‌ها', textAlign: TextAlign.right, style: AppFonts.yekan16.copyWith(color: AppColor.iconColor), ), @@ -173,7 +173,7 @@ class PoultryScienceHomePage extends GetView { firstTagInformation(), Row( children: [ - Text('اطلاعات جوجه ریزی', textAlign: TextAlign.right, style: AppFonts.yekan16), + Text('اطلاعات جوجه‌ریزی', textAlign: TextAlign.right, style: AppFonts.yekan16), ], ), secondTagInformation(), @@ -303,7 +303,7 @@ class PoultryScienceHomePage extends GetView { ), widelyUsed( - title: 'جوجه ریزی فعال', + title: 'جوجه‌ریزی فعال', iconPath: Assets.vec.boxTickSvg.path, isOnEdit: false, cardColor: Color(0xFFD9BEFF), @@ -322,7 +322,7 @@ class PoultryScienceHomePage extends GetView { right: 11, child: Container( color: Colors.white, - child: Text('پر کاربرد ها', textAlign: TextAlign.right, style: AppFonts.yekan16), + child: Text('پر کاربردها', textAlign: TextAlign.right, style: AppFonts.yekan16), ), ), ], diff --git a/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/logic.dart b/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/logic.dart index 161a0af..82290c5 100644 --- a/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/logic.dart +++ b/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/logic.dart @@ -8,7 +8,6 @@ import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_ import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.dart'; import 'package:rasadyar_chicken/data/models/response/sell_for_freezing/sell_for_freezing.dart'; import 'package:rasadyar_chicken/presentation/pages/poultry_science/root/logic.dart'; -import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart'; import 'package:rasadyar_core/core.dart'; class KillingRegistrationLogic extends GetxController { @@ -89,7 +88,6 @@ class KillingRegistrationLogic extends GetxController { ); } - @override void onClose() { super.onClose(); @@ -107,7 +105,8 @@ class KillingRegistrationLogic extends GetxController { quantityKillsController.addListener(() { quantityKillsIsCompleted.value = quantityKillsController.text.trim().isNotEmpty; - if (averageWeightKillsController.text.isNotEmpty && quantityKillsController.text.trim().isNotEmpty) { + if (averageWeightKillsController.text.isNotEmpty && + quantityKillsController.text.trim().isNotEmpty) { generatedApprovedPrice.value = calculateApprovedPrice().toInt(); priceFreeSaleController.text = generatedApprovedPrice.value.separatedByComma; @@ -120,10 +119,10 @@ class KillingRegistrationLogic extends GetxController { }); averageWeightKillsController.addListener(() { - averageWeightKillsIsCompleted.value = averageWeightKillsController.text.trim().isNotEmpty; - if (averageWeightKillsController.text.trim().isNotEmpty && quantityKillsController.text.trim().isNotEmpty) { + if (averageWeightKillsController.text.trim().isNotEmpty && + quantityKillsController.text.trim().isNotEmpty) { generatedApprovedPrice.value = calculateApprovedPrice().toInt(); priceFreeSaleController.text = generatedApprovedPrice.value.separatedByComma; checkSubmitButton(); @@ -359,9 +358,8 @@ class KillingRegistrationLogic extends GetxController { 'ثبت با موفقیت انجام شد', durationInSeconds: 2, onDismissed: () async { - fLog('Kill Registration onDismissed'); Future.delayed(Duration(milliseconds: 300), () { - Get.back(id: poultryFirstKey); + Get.back(); }); }, ); @@ -408,6 +406,4 @@ class KillingRegistrationLogic extends GetxController { poultryHatchingList.value = Resource>.success([]); killHouseList.value = Resource>.success([]); } - - } diff --git a/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/view.dart b/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/view.dart index 6a158e0..1a6067d 100644 --- a/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/view.dart +++ b/packages/chicken/lib/presentation/pages/poultry_science/killing_registration/view.dart @@ -40,13 +40,7 @@ class KillingRegistrationPage extends GetView { ObxValue((data) { return Visibility( visible: data.value, - child: Column( - children: [ - - averageWeightKillsWidget(), - - ], - ), + child: Column(children: [averageWeightKillsWidget()]), ); }, controller.quantityKillsIsCompleted), @@ -55,19 +49,15 @@ class KillingRegistrationPage extends GetView { visible: data.value, child: Column( children: [ - saleTypeWidget(), priceWidget(), buyerListWidget(), slaughterhouseSelectedWidget(), submitButtonWidget(), - ], ), ); }, controller.averageWeightKillsIsCompleted), - - ], ), ); @@ -107,10 +97,7 @@ class KillingRegistrationPage extends GetView { ], ); } else { - return Text( - '${item.unitName} (${item.address?.city?.name})', - maxLines: 2, - ); + return Text('${item.unitName} (${item.address?.city?.name})', maxLines: 2); } } @@ -236,7 +223,7 @@ class KillingRegistrationPage extends GetView { ), buildUnitRow( - title: 'جمع تلفات ثبت شده دامپزشک و مرغدار', + title: 'تلفات', value: data.value?.losses.separatedByCommaFa, unit: 'قطعه', padding: EdgeInsetsGeometry.symmetric(horizontal: 4), @@ -248,7 +235,7 @@ class KillingRegistrationPage extends GetView { padding: EdgeInsetsGeometry.symmetric(horizontal: 4), ), buildUnitRow( - title: 'سن مرغ', + title: 'سن جوجه', value: data.value?.chickenAge.separatedByCommaFa, unit: 'روز', padding: EdgeInsetsGeometry.symmetric(horizontal: 4), @@ -386,6 +373,7 @@ class KillingRegistrationPage extends GetView { }, filledColor: Colors.white, keyboardType: TextInputType.number, + inputFormatters: [FirstDigitDecimalFormatter()], controller: controller.averageWeightKillsController, ), ); diff --git a/packages/chicken/lib/presentation/pages/poultry_science/poultry_action/logic.dart b/packages/chicken/lib/presentation/pages/poultry_science/poultry_action/logic.dart index 6b8e332..cb84a89 100644 --- a/packages/chicken/lib/presentation/pages/poultry_science/poultry_action/logic.dart +++ b/packages/chicken/lib/presentation/pages/poultry_science/poultry_action/logic.dart @@ -14,22 +14,22 @@ class PoultryActionLogic extends GetxController { PoultryActionItem( title: "بازرسی", route: ChickenRoutes.inspectionPoultryScience, - icon: Assets.vec.cubeSearchSvg.path, + icon: Assets.vec.chickenInspectionSvg.path, ), PoultryActionItem( title: "ثبت کشتار", route: ChickenRoutes.genocidePoultryScience, - icon: Assets.vec.noteRemoveSvg.path, + icon: Assets.vec.registerKillSvg.path, ), PoultryActionItem( title: "فارم ها", route: ChickenRoutes.farmPoultryScience, - icon: Assets.vec.cubeScanSvg.path, + icon: Assets.vec.farmsSvg.path, ), PoultryActionItem( title: "جوجه ریزی فعال", route: ChickenRoutes.activeHatchingPoultryScience, - icon: Assets.vec.boxTickSvg.path, + icon: Assets.vec.activeFramSvg.path, ), ].obs; } diff --git a/packages/chicken/lib/presentation/routes/pages.dart b/packages/chicken/lib/presentation/routes/pages.dart index a66efa2..88af388 100644 --- a/packages/chicken/lib/presentation/routes/pages.dart +++ b/packages/chicken/lib/presentation/routes/pages.dart @@ -216,7 +216,7 @@ sealed class ChickenPages { binding: BindingsBuilder(() { Get.lazyPut(() => GenocideLogic()); Get.lazyPut(() => PoultryScienceRootLogic()); - Get.put( KillingRegistrationLogic()); + Get.lazyPut(() => KillingRegistrationLogic(),fenix: true); }), ), GetPage( diff --git a/packages/chicken/pubspec.yaml b/packages/chicken/pubspec.yaml index 683ba53..afbc30c 100644 --- a/packages/chicken/pubspec.yaml +++ b/packages/chicken/pubspec.yaml @@ -1,6 +1,6 @@ name: rasadyar_chicken description: A starting point for Dart libraries or applications. -version: 1.2.1+2 +version: 1.3.2+3 environment: sdk: ^3.9.0 diff --git a/packages/core/lib/presentation/common/assets.gen.dart b/packages/core/lib/presentation/common/assets.gen.dart index dc116dc..512eff0 100644 --- a/packages/core/lib/presentation/common/assets.gen.dart +++ b/packages/core/lib/presentation/common/assets.gen.dart @@ -32,6 +32,9 @@ class $AssetsAnimGen { class $AssetsIconsGen { const $AssetsIconsGen(); + /// File path: assets/icons/active_fram.svg + SvgGenImage get activeFram => const SvgGenImage('assets/icons/active_fram.svg'); + /// File path: assets/icons/add.svg SvgGenImage get add => const SvgGenImage('assets/icons/add.svg'); @@ -89,6 +92,9 @@ class $AssetsIconsGen { /// File path: assets/icons/chicken_house.svg SvgGenImage get chickenHouse => const SvgGenImage('assets/icons/chicken_house.svg'); + /// File path: assets/icons/chicken_inspection.svg + SvgGenImage get chickenInspection => const SvgGenImage('assets/icons/chicken_inspection.svg'); + /// File path: assets/icons/chicken_map_marker.svg SvgGenImage get chickenMapMarker => const SvgGenImage('assets/icons/chicken_map_marker.svg'); @@ -164,6 +170,9 @@ class $AssetsIconsGen { /// File path: assets/icons/farm.svg SvgGenImage get farm => const SvgGenImage('assets/icons/farm.svg'); + /// File path: assets/icons/farms.svg + SvgGenImage get farms => const SvgGenImage('assets/icons/farms.svg'); + /// File path: assets/icons/filter.svg SvgGenImage get filter => const SvgGenImage('assets/icons/filter.svg'); @@ -272,6 +281,9 @@ class $AssetsIconsGen { /// File path: assets/icons/receipt_discount.svg SvgGenImage get receiptDiscount => const SvgGenImage('assets/icons/receipt_discount.svg'); + /// File path: assets/icons/registerKill.svg + SvgGenImage get registerKill => const SvgGenImage('assets/icons/registerKill.svg'); + /// File path: assets/icons/sale.svg SvgGenImage get sale => const SvgGenImage('assets/icons/sale.svg'); @@ -337,6 +349,7 @@ class $AssetsIconsGen { /// List of all assets List get values => [ + activeFram, add, appBarInspection, arrowLeft, @@ -356,6 +369,7 @@ class $AssetsIconsGen { chicken, chicken2, chickenHouse, + chickenInspection, chickenMapMarker, chickenPattern, clipboardEye, @@ -381,6 +395,7 @@ class $AssetsIconsGen { empty, excelDownload, farm, + farms, filter, filterOutline, gps, @@ -417,6 +432,7 @@ class $AssetsIconsGen { rasadNan, rasadToyor, receiptDiscount, + registerKill, sale, scan, scanBarcode, @@ -500,6 +516,9 @@ class $AssetsRiveGen { class $AssetsVecGen { const $AssetsVecGen(); + /// File path: assets/vec/active_fram.svg.vec + SvgGenImage get activeFramSvg => const SvgGenImage.vec('assets/vec/active_fram.svg.vec'); + /// File path: assets/vec/add.svg.vec SvgGenImage get addSvg => const SvgGenImage.vec('assets/vec/add.svg.vec'); @@ -557,6 +576,9 @@ class $AssetsVecGen { /// File path: assets/vec/chicken_house.svg.vec SvgGenImage get chickenHouseSvg => const SvgGenImage.vec('assets/vec/chicken_house.svg.vec'); + /// File path: assets/vec/chicken_inspection.svg.vec + SvgGenImage get chickenInspectionSvg => const SvgGenImage.vec('assets/vec/chicken_inspection.svg.vec'); + /// File path: assets/vec/chicken_map_marker.svg.vec SvgGenImage get chickenMapMarkerSvg => const SvgGenImage.vec('assets/vec/chicken_map_marker.svg.vec'); @@ -632,6 +654,9 @@ class $AssetsVecGen { /// File path: assets/vec/farm.svg.vec SvgGenImage get farmSvg => const SvgGenImage.vec('assets/vec/farm.svg.vec'); + /// File path: assets/vec/farms.svg.vec + SvgGenImage get farmsSvg => const SvgGenImage.vec('assets/vec/farms.svg.vec'); + /// File path: assets/vec/filter.svg.vec SvgGenImage get filterSvg => const SvgGenImage.vec('assets/vec/filter.svg.vec'); @@ -740,6 +765,9 @@ class $AssetsVecGen { /// File path: assets/vec/receipt_discount.svg.vec SvgGenImage get receiptDiscountSvg => const SvgGenImage.vec('assets/vec/receipt_discount.svg.vec'); + /// File path: assets/vec/registerKill.svg.vec + SvgGenImage get registerKillSvg => const SvgGenImage.vec('assets/vec/registerKill.svg.vec'); + /// File path: assets/vec/sale.svg.vec SvgGenImage get saleSvg => const SvgGenImage.vec('assets/vec/sale.svg.vec'); @@ -805,6 +833,7 @@ class $AssetsVecGen { /// List of all assets List get values => [ + activeFramSvg, addSvg, appBarInspectionSvg, arrowLeftSvg, @@ -824,6 +853,7 @@ class $AssetsVecGen { chickenSvg, chicken2Svg, chickenHouseSvg, + chickenInspectionSvg, chickenMapMarkerSvg, chickenPatternSvg, clipboardEyeSvg, @@ -849,6 +879,7 @@ class $AssetsVecGen { emptySvg, excelDownloadSvg, farmSvg, + farmsSvg, filterSvg, filterOutlineSvg, gpsSvg, @@ -885,6 +916,7 @@ class $AssetsVecGen { rasadNanSvg, rasadToyorSvg, receiptDiscountSvg, + registerKillSvg, saleSvg, scanSvg, scanBarcodeSvg, diff --git a/packages/core/lib/utils/first_digit_decimal_formatter.dart b/packages/core/lib/utils/first_digit_decimal_formatter.dart new file mode 100644 index 0000000..0816a8f --- /dev/null +++ b/packages/core/lib/utils/first_digit_decimal_formatter.dart @@ -0,0 +1,24 @@ +import 'package:flutter/services.dart'; + +class FirstDigitDecimalFormatter extends TextInputFormatter { + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + String digit = newValue.text.replaceAll(RegExp(r'[^0-9]'), ""); + late String res; + + if (digit.isEmpty) { + return newValue.copyWith(text: ''); + } + + if (digit.length == 1) { + res = digit; + } else { + res = '${digit[0]}.${digit.substring(1)}'; + } + + return TextEditingValue( + text: res, + selection: TextSelection.collapsed(offset: res.length), + ); + } +} diff --git a/packages/core/lib/utils/utils.dart b/packages/core/lib/utils/utils.dart index cda3077..4ceb568 100644 --- a/packages/core/lib/utils/utils.dart +++ b/packages/core/lib/utils/utils.dart @@ -14,3 +14,4 @@ export 'number_utils.dart'; export 'parser.dart'; export 'route_utils.dart'; export 'separator_input_formatter.dart'; +export 'first_digit_decimal_formatter.dart'; diff --git a/packages/core/pubspec.lock b/packages/core/pubspec.lock index a7ff537..1c0ff80 100644 --- a/packages/core/pubspec.lock +++ b/packages/core/pubspec.lock @@ -953,10 +953,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd" + sha256: "33a040668b31b320aafa4822b7b1e177e163fc3c1e835c6750319d4ab23aa6fe" url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.11.1" latlong2: dependency: "direct main" description: diff --git a/pubspec.lock b/pubspec.lock index e6e5b31..c433104 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + sha256: dd3d2ad434b9510001d089e8de7556d50c834481b9abc2891a0184a8493a19dc url: "https://pub.dev" source: hosted - version: "85.0.0" + version: "89.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "974859dc0ff5f37bc4313244b3218c791810d03ab3470a579580279ba971a48d" + sha256: c22b6e7726d1f9e5db58c7251606076a71ca0dbcf76116675edfadbec0c9e875 url: "https://pub.dev" source: hosted - version: "7.7.1" + version: "8.2.0" android_intent_plus: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build - sha256: "6439a9c71a4e6eca8d9490c1b380a25b02675aa688137dfbe66d2062884a23ac" + sha256: "5b887c55a0f734b433b3b2d89f9cd1f99eb636b17e268a5b4259258bc916504b" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "4.0.0" build_config: dependency: transitive description: @@ -97,30 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.4" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "2b21a125d66a86b9511cc3fb6c668c42e9a1185083922bf60e46d483a81a9712" - url: "https://pub.dev" - source: hosted - version: "3.0.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: fd3c09f4bbff7fa6e8d8ef688a0b2e8a6384e6483a25af0dac75fef362bcfe6f + sha256: "804c47c936df75e1911c19a4fb8c46fa8ff2b3099b9f2b2aa4726af3774f734b" url: "https://pub.dev" source: hosted - version: "2.7.0" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: ab27e46c8aa233e610cf6084ee6d8a22c6f873a0a9929241d8855b7a72978ae7 - url: "https://pub.dev" - source: hosted - version: "9.3.0" + version: "2.8.0" built_collection: dependency: transitive description: @@ -285,10 +269,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + sha256: c87dfe3d56f183ffe9106a18aebc6db431fc7c98c31a54b952a77f3d54a85697 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" dartx: dependency: transitive description: @@ -446,22 +430,27 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_gen_core: dependency: transitive description: name: flutter_gen_core - sha256: eda54fdc5de08e7eeea663eb8442aafc8660b5a13fda4e0c9e572c64e50195fb + sha256: b6bafbbd981da2f964eb45bcb8b8a7676a281084f8922c0c75de4cfbaa849311 url: "https://pub.dev" source: hosted - version: "5.11.0" + version: "5.12.0" flutter_gen_runner: dependency: "direct dev" description: name: flutter_gen_runner - sha256: "669bf8b7a9b4acbdcb7fcc5e12bf638aca19acedf43341714cbca3bf3a219521" + sha256: c99b10af9d404e3f46fd1927e7d90099779e935e86022674c4c2a9e6c2a93b29 url: "https://pub.dev" source: hosted - version: "5.11.0" + version: "5.12.0" flutter_launcher_icons: dependency: "direct main" description: @@ -625,10 +614,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: da32f8ba8cfcd4ec71d9decc8cbf28bd2c31b5283d9887eb51eb4a0659d8110c + sha256: "13065f10e135263a4f5a4391b79a8efc5fb8106f8dd555a9e49b750b45393d77" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.3" freezed_annotation: dependency: "direct main" description: @@ -645,6 +634,11 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" geoclue: dependency: transitive description: @@ -785,10 +779,10 @@ packages: dependency: "direct dev" description: name: hive_ce_generator - sha256: a169feeff2da9cc2c417ce5ae9bcebf7c8a95d7a700492b276909016ad70a786 + sha256: "8c677690c8ead43778ddf7ed8ff17e852dd5d22d082c75182b072842c0dc5055" url: "https://pub.dev" source: hosted - version: "1.9.3" + version: "1.9.5" http: dependency: transitive description: @@ -917,6 +911,11 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" intl: dependency: transitive description: @@ -961,10 +960,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: "3f2913b7c2430afe8ac5afe6fb15c1de4a60af4f630625e6e238f80ba4b80cbd" + sha256: "33a040668b31b320aafa4822b7b1e177e163fc3c1e835c6750319d4ab23aa6fe" url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "6.11.1" latlong2: dependency: transitive description: @@ -1081,10 +1080,10 @@ packages: dependency: transitive description: name: mockito - sha256: "2314cbe9165bcd16106513df9cf3c3224713087f09723b128928dc11a4379f99" + sha256: "4feb43bc4eb6c03e832f5fcd637d1abb44b98f9cfa245c58e27382f58859f8f6" url: "https://pub.dev" source: hosted - version: "5.5.0" + version: "5.5.1" mocktail: dependency: "direct dev" description: @@ -1341,6 +1340,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + process: + dependency: transitive + description: + name: process + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + url: "https://pub.dev" + source: hosted + version: "5.0.5" proj4dart: dependency: transitive description: @@ -1379,7 +1386,7 @@ packages: path: "packages/chicken" relative: true source: path - version: "1.2.1+2" + version: "1.3.2+3" rasadyar_core: dependency: "direct main" description: @@ -1530,18 +1537,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" + sha256: ccf30b0c9fbcd79d8b6f5bfac23199fb354938436f62475e14aea0f29ee0f800 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.1" source_helper: dependency: transitive description: name: source_helper - sha256: "4f81479fe5194a622cdd1713fe1ecb683a6e6c85cd8cec8e2e35ee5ab3fdf2a1" + sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723" url: "https://pub.dev" source: hosted - version: "1.3.6" + version: "1.3.8" source_span: dependency: transitive description: @@ -1630,6 +1637,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" synchronized: dependency: transitive description: @@ -1662,14 +1677,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.5" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" typed_data: dependency: transitive description: @@ -1766,6 +1773,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + url: "https://pub.dev" + source: hosted + version: "3.1.0" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a616485..400931f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: rasadyar_app description: "A new Flutter project." publish_to: 'none' -version: 1.3.7+5 +version: 1.3.8+6 environment: sdk: ^3.9.0 @@ -34,13 +34,15 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + integration_test: + sdk: flutter flutter_lints: ^6.0.0 ##code generation - build_runner: ^2.7.0 - hive_ce_generator: ^1.9.3 - freezed: ^3.2.0 - json_serializable: ^6.11.0 - flutter_gen_runner: ^5.11.0 + build_runner: ^2.8.0 + hive_ce_generator: ^1.9.5 + freezed: ^3.2.3 + json_serializable: ^6.11.1 + flutter_gen_runner: ^5.12.0 change_app_package_name: ^1.5.0 ##test