From 3d73d9a17a59b2894e325b32abff3b59b9134339 Mon Sep 17 00:00:00 2001 From: "mr.mojtaba" Date: Wed, 10 Dec 2025 16:42:53 +0330 Subject: [PATCH] feat: add image upload functionality to poultry science feature, including repository and data source updates for handling image uploads --- .../local/poultry_farm_local_data_source.dart | 2 + .../poultry_farm_remote_data_source.dart | 2 + .../data/models/.gitkeep | 2 + .../repositories/poultry_farm_repository.dart | 2 + .../poultry_farm_inspection/domain/.gitkeep | 2 + .../presentation/.gitkeep | 2 + .../poultry_science_remote_data_source.dart | 5 + ...ultry_science_remote_data_source_impl.dart | 16 + .../poultry_science_repository.dart | 5 + .../poultry_science_repository_impl.dart | 8 + .../pages/active_hatching/logic.dart | 3 +- .../pages/active_hatching/view.dart | 54 +- .../presentation/pages/home/view.dart | 1 - .../presentation/routes/pages.dart | 71 +- .../card_info.dart | 60 ++ .../create_inspection_bottom_sheet.dart | 233 +++++++ .../create_inspection_bottom_sheet_logic.dart | 545 +++++++++++++++ .../step1_page.dart | 232 +++++++ .../step2_page.dart | 654 ++++++++++++++++++ .../step3_page.dart | 517 ++++++++++++++ .../step4_page.dart | 495 +++++++++++++ .../step5_page.dart | 599 ++++++++++++++++ .../presentation/routes/global_binding.dart | 7 +- 23 files changed, 3481 insertions(+), 36 deletions(-) create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step1_page.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step3_page.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step4_page.dart create mode 100644 packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step5_page.dart diff --git a/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/local/poultry_farm_local_data_source.dart b/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/local/poultry_farm_local_data_source.dart index 8a77734..8fca579 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/local/poultry_farm_local_data_source.dart +++ b/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/local/poultry_farm_local_data_source.dart @@ -3,3 +3,5 @@ abstract class PoultryFarmLocalDataSource { } + + diff --git a/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/remote/poultry_farm_remote_data_source.dart b/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/remote/poultry_farm_remote_data_source.dart index 7614630..4b80b06 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/remote/poultry_farm_remote_data_source.dart +++ b/packages/chicken/lib/features/poultry_farm_inspection/data/datasources/remote/poultry_farm_remote_data_source.dart @@ -3,3 +3,5 @@ abstract class PoultryFarmRemoteDataSource { } + + diff --git a/packages/chicken/lib/features/poultry_farm_inspection/data/models/.gitkeep b/packages/chicken/lib/features/poultry_farm_inspection/data/models/.gitkeep index b28b04f..3f2ff2d 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/data/models/.gitkeep +++ b/packages/chicken/lib/features/poultry_farm_inspection/data/models/.gitkeep @@ -1,3 +1,5 @@ + + diff --git a/packages/chicken/lib/features/poultry_farm_inspection/data/repositories/poultry_farm_repository.dart b/packages/chicken/lib/features/poultry_farm_inspection/data/repositories/poultry_farm_repository.dart index 3a1aa5e..c27fe0e 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/data/repositories/poultry_farm_repository.dart +++ b/packages/chicken/lib/features/poultry_farm_inspection/data/repositories/poultry_farm_repository.dart @@ -3,3 +3,5 @@ abstract class PoultryFarmRepository { } + + diff --git a/packages/chicken/lib/features/poultry_farm_inspection/domain/.gitkeep b/packages/chicken/lib/features/poultry_farm_inspection/domain/.gitkeep index b28b04f..3f2ff2d 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/domain/.gitkeep +++ b/packages/chicken/lib/features/poultry_farm_inspection/domain/.gitkeep @@ -1,3 +1,5 @@ + + diff --git a/packages/chicken/lib/features/poultry_farm_inspection/presentation/.gitkeep b/packages/chicken/lib/features/poultry_farm_inspection/presentation/.gitkeep index b28b04f..3f2ff2d 100644 --- a/packages/chicken/lib/features/poultry_farm_inspection/presentation/.gitkeep +++ b/packages/chicken/lib/features/poultry_farm_inspection/presentation/.gitkeep @@ -1,3 +1,5 @@ + + diff --git a/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source.dart b/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source.dart index 0b1c805..33ca503 100644 --- a/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source.dart +++ b/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source.dart @@ -89,4 +89,9 @@ abstract class PoultryScienceRemoteDataSource { required String token, required String orderId, }); + + Future?> uploadImages({ + required String token, + required List images, + }); } diff --git a/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source_impl.dart b/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source_impl.dart index 6d43e36..6b8f532 100644 --- a/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source_impl.dart +++ b/packages/chicken/lib/features/poultry_science/data/datasources/remote/poultry_science_remote_data_source_impl.dart @@ -245,5 +245,21 @@ class PoultryScienceRemoteDataSourceImpl ); } + @override + Future?> uploadImages({ + required String token, + required List images, + }) async { + var res = await _httpClient.post?>( + '/upload_image_to_server_for_poultry_science/', + headers: {'Authorization': 'Bearer $token'}, + data: FormData.fromMap({ + 'file': images.map((e) => MultipartFile.fromFileSync(e.path)).toList(), + }), + fromJson: (json) => List.from(json['urls'] as List), + ); + return res.data; + } + //endregion } diff --git a/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository.dart b/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository.dart index 2d2669b..743134e 100644 --- a/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository.dart +++ b/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository.dart @@ -89,4 +89,9 @@ abstract class PoultryScienceRepository { required String token, required String orderId, }); + + Future?> uploadImages({ + required String token, + required List images, + }); } diff --git a/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository_impl.dart b/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository_impl.dart index 5348969..cba2334 100644 --- a/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository_impl.dart +++ b/packages/chicken/lib/features/poultry_science/data/repositories/poultry_science_repository_impl.dart @@ -180,4 +180,12 @@ class PoultryScienceRepositoryImpl implements PoultryScienceRepository { }) async { return await _dataSource.deletePoultryOder(token: token, orderId: orderId); } + + @override + Future?> uploadImages({ + required String token, + required List images, + }) async { + return await _dataSource.uploadImages(token: token, images: images); + } } diff --git a/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/logic.dart b/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/logic.dart index 69fbe0c..9719360 100644 --- a/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/logic.dart +++ b/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/logic.dart @@ -1,3 +1,4 @@ +import 'package:rasadyar_chicken/data/di/chicken_di.dart'; import 'package:rasadyar_chicken/features/poultry_science/data/model/response/hatching/hatching_models.dart'; import 'package:rasadyar_chicken/features/poultry_science/data/repositories/poultry_science_repository.dart'; import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/root/logic.dart'; @@ -22,7 +23,7 @@ class ActiveHatchingLogic extends GetxController { @override void onInit() { super.onInit(); - poultryScienceRepository = Get.find(); + poultryScienceRepository = diChicken.get(); } @override diff --git a/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/view.dart b/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/view.dart index 18af948..b4bb6c7 100644 --- a/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/view.dart +++ b/packages/chicken/lib/features/poultry_science/presentation/pages/active_hatching/view.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/features/poultry_science/data/model/response/hatching/hatching_models.dart'; import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/active_hatching/logic.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart'; import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart'; import 'package:rasadyar_core/core.dart'; @@ -50,7 +52,6 @@ class ActiveHatchingPage extends GetView { itemCount: data.value.data?.results?.length ?? 0, separatorBuilder: (context, index) => SizedBox(height: 8.h), onLoadMore: () async => controller.getHatchingList(true), - ); }, controller.activeHatchingList); } @@ -58,7 +59,10 @@ class ActiveHatchingPage extends GetView { Container itemListExpandedWidget(HatchingModel item) { return Container( padding: EdgeInsets.symmetric(horizontal: 8), - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), child: Column( spacing: 8, children: [ @@ -111,7 +115,10 @@ class ActiveHatchingPage extends GetView { ), ), - buildRow(title: 'شماره مجوز جوجه ریزی', value: item.licenceNumber ?? 'N/A'), + buildRow( + title: 'شماره مجوز جوجه ریزی', + value: item.licenceNumber ?? 'N/A', + ), buildUnitRow( title: 'حجم جوجه ریزی', value: item.quantity.separatedByCommaFa, @@ -122,21 +129,52 @@ class ActiveHatchingPage extends GetView { value: item.leftOver.separatedByCommaFa, unit: '(قطعه)', ), - buildUnitRow(title: 'تلفات', value: item.losses.separatedByCommaFa, unit: '(قطعه)'), + buildUnitRow( + title: 'تلفات', + value: item.losses.separatedByCommaFa, + unit: '(قطعه)', + ), buildRow( title: 'دامپزشک فارم', - value: '${item.vetFarm?.vetFarmFullName}(${item.vetFarm?.vetFarmMobile})', + value: + '${item.vetFarm?.vetFarmFullName}(${item.vetFarm?.vetFarmMobile})', ), buildRow( title: 'شرح بازرسی', - value: item.reportInfo?.image == false ? 'ارسال تصویر جوجه ریزی فارم ' : 'تکمیل شده', + value: item.reportInfo?.image == false + ? 'ارسال تصویر جوجه ریزی فارم ' + : 'تکمیل شده', titleStyle: AppFonts.yekan14.copyWith( - color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark, + color: (item.reportInfo?.image ?? false) + ? AppColor.greenNormal + : AppColor.redDark, ), valueStyle: AppFonts.yekan14.copyWith( - color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark, + color: (item.reportInfo?.image ?? false) + ? AppColor.greenNormal + : AppColor.redDark, ), ), + + RElevated( + height: 40.h, + isFullWidth: true, + onPressed: () { + Get.find().setHatchingModel( + item, + ); + Get.bottomSheet( + CreateInspectionBottomSheet(), + isScrollControlled: true, + ignoreSafeArea: false, + ).then((value) { + if (Get.isRegistered()) { + Get.find().clearForm(); + } + }); + }, + child: Text('ثبت بازرسی'), + ), ], ), ); diff --git a/packages/chicken/lib/features/poultry_science/presentation/pages/home/view.dart b/packages/chicken/lib/features/poultry_science/presentation/pages/home/view.dart index 0820f31..d44d041 100644 --- a/packages/chicken/lib/features/poultry_science/presentation/pages/home/view.dart +++ b/packages/chicken/lib/features/poultry_science/presentation/pages/home/view.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart' hide LinearGradient; import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/features/poultry_science/presentation/routes/routes.dart'; -import 'package:rasadyar_chicken/presentation/routes/routes.dart'; import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart'; import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart'; import 'package:rasadyar_core/core.dart'; diff --git a/packages/chicken/lib/features/poultry_science/presentation/routes/pages.dart b/packages/chicken/lib/features/poultry_science/presentation/routes/pages.dart index b69fdb7..79cdb3b 100644 --- a/packages/chicken/lib/features/poultry_science/presentation/routes/pages.dart +++ b/packages/chicken/lib/features/poultry_science/presentation/routes/pages.dart @@ -14,6 +14,7 @@ import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/pou import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/root/logic.dart'; import 'package:rasadyar_chicken/features/poultry_science/presentation/pages/root/view.dart'; import 'package:rasadyar_chicken/features/poultry_science/presentation/routes/routes.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; import 'package:rasadyar_chicken/presentation/routes/global_binding.dart'; import 'package:rasadyar_core/core.dart'; @@ -38,56 +39,76 @@ class PoultrySciencePages { name: PoultryScienceRoutes.inspectionPoultryScience, page: () => InspectionPoultrySciencePage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => InspectionPoultryScienceLogic()); - }), + bindings: [ + GlobalBinding(), + BindingsBuilder(() { + Get.lazyPut(() => InspectionPoultryScienceLogic()); + }), + ], ), GetPage( name: PoultryScienceRoutes.actionPoultryScience, page: () => PoultryActionPage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => PoultryActionLogic()); - }), + bindings: [ + GlobalBinding(), + BindingsBuilder(() { + Get.lazyPut(() => PoultryActionLogic()); + }), + ], ), GetPage( name: PoultryScienceRoutes.farmPoultryScience, page: () => FarmPage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => FarmLogic()); - Get.lazyPut(() => PoultryScienceHomeLogic()); - Get.lazyPut(() => PoultryScienceRootLogic()); - }), + bindings: [ + GlobalBinding(), + + BindingsBuilder(() { + Get.lazyPut(() => FarmLogic()); + Get.lazyPut(() => PoultryScienceHomeLogic()); + Get.lazyPut(() => PoultryScienceRootLogic()); + }), + ], ), GetPage( name: PoultryScienceRoutes.activeHatchingPoultryScience, page: () => ActiveHatchingPage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => ActiveHatchingLogic()); - Get.lazyPut(() => PoultryScienceRootLogic()); - }), + bindings: [ + GlobalBinding(), + BindingsBuilder(() { + Get.lazyPut(() => ActiveHatchingLogic()); + Get.lazyPut(() => CreateInspectionBottomSheetLogic(), fenix: true); + Get.lazyPut(() => PoultryScienceRootLogic()); + }), + ], ), GetPage( name: PoultryScienceRoutes.genocidePoultryScience, page: () => GenocidePage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => GenocideLogic()); - Get.lazyPut(() => PoultryScienceRootLogic()); - Get.lazyPut(() => KillingRegistrationLogic(), fenix: true); - }), + bindings: [ + GlobalBinding(), + BindingsBuilder(() { + Get.lazyPut(() => GenocideLogic()); + Get.lazyPut(() => PoultryScienceRootLogic()); + Get.lazyPut(() => KillingRegistrationLogic(), fenix: true); + }), + ], ), GetPage( name: PoultryScienceRoutes.killingRegistrationPoultryScience, page: () => KillingRegistrationPage(), middlewares: [AuthMiddleware()], - binding: BindingsBuilder(() { - Get.lazyPut(() => KillingRegistrationLogic()); - Get.lazyPut(() => GenocideLogic()); - Get.lazyPut(() => PoultryScienceRootLogic()); - }), + bindings: [ + GlobalBinding(), + BindingsBuilder(() { + Get.lazyPut(() => KillingRegistrationLogic()); + Get.lazyPut(() => GenocideLogic()); + Get.lazyPut(() => PoultryScienceRootLogic()); + }), + ], ), ]; } diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart new file mode 100644 index 0000000..0ccdc56 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; + +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; +import 'package:rasadyar_core/core.dart'; + +Widget farmInfoWidget({ + required CreateInspectionBottomSheetLogic controller, + required String title, + required Widget child, + EdgeInsets? padding, +}) { + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 0.50, color: AppColor.mediumGrey), + ), + + padding: + padding ?? EdgeInsets.symmetric(horizontal: 12.w, vertical: 11.h), + child: child, + ), + ), + Positioned( + top: -17, + right: 7, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 0.50, color: AppColor.mediumGrey), + ), + child: Text( + title, + style: AppFonts.yekan14.copyWith(color: AppColor.iconColor), + ), + ), + ), + ], + ); +} + +Widget cardInfo({required Widget child, EdgeInsets? padding}) { + return Container( + width: Get.width, + padding: padding ?? EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.h), + decoration: BoxDecoration( + color: AppColor.bgLight, + + borderRadius: BorderRadius.circular(8), + border: Border.all(width: 1, color: AppColor.blackLight), + ), + child: child, + ); +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart new file mode 100644 index 0000000..023a4fd --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet.dart @@ -0,0 +1,233 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; +import 'package:rasadyar_core/core.dart'; +import 'step1_page.dart'; +import 'step2_page.dart'; +import 'step3_page.dart'; +import 'step4_page.dart'; +import 'step5_page.dart'; + +class CreateInspectionBottomSheet + extends GetWidget { + CreateInspectionBottomSheet({super.key}); + + List get pages => [ + step1Page(controller), + step2Page(controller), + step3Page(controller), + step4Page(controller), + step5Page(controller), + ]; + + @override + Widget build(BuildContext context) { + return BaseBottomSheet( + height: Get.height, + rootChild: Column( + children: [ + ObxValue((data) { + return stepper(activeStep: data.value); + }, controller.activeStepperIndex), + Expanded( + child: PageView.builder( + physics: const NeverScrollableScrollPhysics(), + reverse: true, + controller: controller.pageController, + itemBuilder: (context, index) => pages[index], + ), + ), + + ObxValue((data) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + spacing: 16, + children: [ + Expanded( + child: ObxValue((data) { + return RElevated( + height: 40.h, + enabled: data.value, + backgroundColor: AppColor.greenNormal, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + + children: [ + Icon(Icons.arrow_back_ios, color: Colors.white), + + Text('ادامه'), + ], + ), + onPressed: () { + if (controller.activeStepperIndex.value < 4) { + controller.activeStepperIndex.value++; + } + }, + ); + }, controller.nextStepButtonEnabled), + ), + Expanded( + child: ROutlinedElevated( + borderColor: AppColor.error, + height: 40.h, + child: Text('برگشت'), + enabled: controller.activeStepperIndex.value > 0, + onPressed: () { + if (controller.activeStepperIndex.value > 0) { + controller.activeStepperIndex.value--; + } + }, + ), + ), + ], + ), + ); + }, controller.activeStepperIndex), + ], + ), + ); + } +} + +class stepper extends StatelessWidget { + const stepper({super.key, required this.activeStep}); + final int activeStep; + + @override + Widget build(BuildContext context) { + return Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + height: 24, + width: Get.width, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: activeStep >= 0 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + shape: BoxShape.circle, + ), + width: 24.w, + height: 24.h, + child: Text( + '1', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: activeStep >= 0 ? Colors.white : AppColor.iconColor, + ), + ), + ), + Expanded( + child: Divider( + color: activeStep >= 1 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + thickness: 8, + ), + ), + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: activeStep >= 1 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + shape: BoxShape.circle, + ), + width: 24.w, + height: 24.h, + child: Text( + '2', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: activeStep >= 1 ? Colors.white : AppColor.iconColor, + ), + ), + ), + Expanded( + child: Divider( + color: activeStep >= 2 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + thickness: 8, + ), + ), + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: activeStep >= 2 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + shape: BoxShape.circle, + ), + width: 24.w, + height: 24.h, + child: Text( + '3', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: activeStep >= 2 ? Colors.white : AppColor.iconColor, + ), + ), + ), + Expanded( + child: Divider( + color: activeStep >= 3 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + thickness: 8, + ), + ), + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: activeStep >= 3 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + shape: BoxShape.circle, + ), + width: 24.w, + height: 24.h, + child: Text( + '4', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: activeStep >= 3 ? Colors.white : AppColor.iconColor, + ), + ), + ), + Expanded( + child: Divider( + color: activeStep >= 4 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + thickness: 8, + ), + ), + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: activeStep >= 4 + ? AppColor.greenNormalHover + : AppColor.whiteNormalActive, + shape: BoxShape.circle, + ), + width: 24.w, + height: 24.h, + child: Text( + '5', + textAlign: TextAlign.center, + style: AppFonts.yekan16.copyWith( + color: activeStep >= 3 ? Colors.white : AppColor.iconColor, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart new file mode 100644 index 0000000..18d0640 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart @@ -0,0 +1,545 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_chicken/data/di/chicken_di.dart'; +import 'package:rasadyar_chicken/features/poultry_science/data/model/response/hatching/hatching_models.dart'; +import 'package:rasadyar_chicken/features/poultry_science/data/repositories/poultry_science_repository.dart'; +import 'package:rasadyar_core/core.dart'; + +class CreateInspectionBottomSheetLogic extends GetxController + with GetSingleTickerProviderStateMixin { + HatchingModel? hatchingModel; + + PoultryScienceRepository repository = diChicken + .get(); + + TokenStorageService tokenStorageService = Get.find(); + + RxInt selectedSegmentIndex = 0.obs; + + + RxInt expandedIndex = RxInt(-1); + + late TabController tabController; + + RxInt selectedTabIndex = 0.obs; + + RxInt activeStepperIndex = 0.obs; + + PageController pageController = PageController(initialPage: 0); + + RxBool nextStepButtonEnabled = false.obs; + + RxInt casualtiesInformationHeight = 300.obs; + + //step1 + + TextEditingController unitNameController = TextEditingController(); + TextEditingController breedingUniqueIdController = TextEditingController(); + TextEditingController healthLicenseController = TextEditingController(); + TextEditingController tenantStatusController = TextEditingController(); + TextEditingController tenantNameController = TextEditingController(); + TextEditingController tenantNationalIdController = TextEditingController(); + TextEditingController tenantPhoneNumberController = TextEditingController(); + TextEditingController ownerNameController = TextEditingController(); + TextEditingController ownerNationalCodeController = TextEditingController(); + TextEditingController ownerPhoneNumberController = TextEditingController(); + TextEditingController totalCapacityController = TextEditingController(); + + //-------------------------------- + + TextEditingController hatchingDateController = TextEditingController(); + TextEditingController visitDateController = TextEditingController(); + TextEditingController hatchingCountController = TextEditingController(); + TextEditingController hatchingAverageWeightController = + TextEditingController(); + TextEditingController hatchingBreedController = TextEditingController(); + + //step2 + Resource> causeOfUnusualCasualtiesList = Resource.success([ + 'بیماری', + 'قطعی برق', + 'استرس گرمایی', + 'مشکلات دان', + 'کیفیت جوجه', + 'سایر (شرح…)', + ]); + RxnString causeOfUnusualCasualties = RxnString(); + RxBool isOthercauseOfUnusualCasualties = false.obs; + TextEditingController otherCauseOfUnusualCasualtiesController = + TextEditingController(); + + Resource> typeOfDiseaseList = Resource.success([ + 'آنفلوانزا', + 'نیوکاسل', + 'IB', + 'عفونت‌های باکتریایی', + 'مشکلات گوارشی', + 'سایر (شرح)', + ]); + RxnString typeOfDisease = RxnString(); + RxBool isOtherTypeOfDiseaseSelected = false.obs; + TextEditingController otherTypeOfDiseaseController = TextEditingController(); + + RxList pultryImagesUrls = RxList(); + RxMap pultryImages = RxMap(); + + TextEditingController hatchingTemperatureController = TextEditingController(); + TextEditingController waterHardnessController = TextEditingController(); + + TextEditingController normalLossesController = TextEditingController(); + TextEditingController abnormalLossesController = TextEditingController(); + TextEditingController sourceOfHatchingController = TextEditingController(); + + RxBool samplingDone = false.obs; + TextEditingController technicalHealthOfficerNameController = + TextEditingController(); + TextEditingController technicalEngineeringOfficerNameController = + TextEditingController(); + + RxInt sanitaryConditionOfTheHallIndex = (-1).obs; + RxInt ventilationStatusIndex = (-1).obs; + RxnString sanitaryConditionOfTheHall = RxnString(); + RxnString ventilationStatus = RxnString(); + + RxInt beddingStatusIndex = (-1).obs; + RxnString beddingStatus = RxnString(); + RxInt waterQualityIndex = (-1).obs; + RxnString waterQuality = RxnString(); + RxInt fuelTypeIndex = (-1).obs; + + RxInt sampleTypeIndex = (-1).obs; + RxnString sampleType = RxnString(); + + //step3 + + Resource> inputStatusList = Resource.success([ + 'وابسته', + 'مستقل', + ]); + RxnString inputStatus = RxnString(); + TextEditingController companyNameController = TextEditingController(); + TextEditingController trackingCodeController = TextEditingController(); + + Resource> typeOfGrainList = Resource.success([ + 'آردی', + 'پلت', + 'کرامبل و اکسترود ', + 'مش ', + 'پوره و وال', + ]); + RxnString typeOfGrain = RxnString(); + + TextEditingController inputInventoryInWarehouseController = + TextEditingController(); + TextEditingController inputInventoryUntilVisitController = + TextEditingController(); + + TextEditingController generatorTypeController = TextEditingController(); + TextEditingController generatorModelController = TextEditingController(); + TextEditingController generatorCountController = TextEditingController(); + TextEditingController generatorCapacityController = TextEditingController(); + TextEditingController emergencyFuelInventoryController = + TextEditingController(); + TextEditingController powerCutDurationController = TextEditingController(); + TextEditingController powerCutHourController = TextEditingController(); + TextEditingController additionalNotesController = TextEditingController(); + RxnString fuelType = RxnString(); + RxBool powerCutHistory = false.obs; + + RxInt grainQualityInputIndex = (-1).obs; + RxnString grainQualityInput = RxnString(); + RxInt generatorOperatingStatusIndex = (-1).obs; + RxnString generatorOperatingStatus = RxnString(); + RxInt workerContractStatusIndex = (-1).obs; + RxnString workerContractStatus = RxnString(); + RxInt newBeneficiaryRequestIndex = (-1).obs; + RxBool trainingStatus = false.obs; + RxnString newBeneficiaryRequest = RxnString(); + RxBool overdueStatus = false.obs; + TextEditingController paymentYearController = TextEditingController(); + Rx selectedPaymentYear = Jalali.now().obs; + + //step3 - worker fields + TextEditingController employedWorkersCountController = + TextEditingController(); + TextEditingController nativeWorkersCountController = TextEditingController(); + TextEditingController nonNativeWorkersCountController = + TextEditingController(); + + TextEditingController activeFacilityController = TextEditingController(); + TextEditingController facilityTypeController = TextEditingController(); + TextEditingController facilityAmountController = TextEditingController(); + + //step4 + + TextEditingController facilityYearController = TextEditingController(); + Rx selectedFacilityYear = Jalali.now().obs; + + RxInt inspectorConclusionIndex = (-1).obs; + RxnString inspectorConclusion = RxnString(); + + TextEditingController inspectorConclusionDescriptionController = + TextEditingController(); + + RxList hallImagesUrls = RxList(); + RxMap hallImages = RxMap(); + + RxList inputWarehouseImagesUrls = RxList(); + RxMap inputWarehouseImages = RxMap(); + + RxList lossesImagesUrls = RxList(); + RxMap lossesImages = RxMap(); + + //location + Rxn currentLocation = Rxn(); + RxBool isLoadingLocation = false.obs; + + //images + ImagePicker imagePicker = ImagePicker(); + + @override + void onReady() { + super.onReady(); + activeStepperIndex.listen((value) { + pageController.animateToPage( + value, + duration: Duration(milliseconds: 300), + curve: Curves.linear, + ); + }); + + initData(); + setUpNextButtonListeners(); + } + + @override + void onClose() { + // TODO: implement onClose + super.onClose(); + } + + void initData() { + unitNameController.text = + hatchingModel?.poultry?.unitName ?? 'واحد مرغداری نامشخص'; + + breedingUniqueIdController.text = + hatchingModel?.poultry?.breedingUniqueId ?? 'کد یکتا/شناسه واحد نامشخص'; + + healthLicenseController.text = + hatchingModel?.poultry?.healthCertificateNumber ?? + 'پروانه بهداشتی ندارد '; + + tenantStatusController.text = (hatchingModel?.poultry?.hasTenant == true) + ? 'دارد' + : 'ندارد'; + + if (hatchingModel?.poultry?.hasTenant == true) { + tenantNameController.text = + hatchingModel?.tenantFullname ?? 'نام مستاجر نامشخص'; + tenantNationalIdController.text = + hatchingModel?.tenantNationalCode ?? 'کد ملی مستاجر نامشخص'; + tenantPhoneNumberController.text = + hatchingModel?.tenantMobile ?? 'شماره تماس مستاجر نامشخص'; + } + + ownerNameController.text = + hatchingModel?.poultry?.user?.fullname ?? 'مالک واحد مرغداری نامشخص'; + ownerNationalCodeController.text = + hatchingModel?.chainCompany?.user?.nationalId ?? + 'کد ملی مالک واحد مرغداری نامشخص'; + ownerPhoneNumberController.text = + hatchingModel?.poultry?.user?.mobile ?? + 'شماره تماس مالک واحد مرغداری نامشخص'; + totalCapacityController.text = + hatchingModel?.poultry?.totalCapacity?.toString() ?? + 'ظرفیت اسمی سالن‌ها نامشخص'; + + hatchingDateController.text = + hatchingModel?.date?.toJalali.formatCompactDate() ?? + 'تاریخ جوجه ریزی نامشخص'; + hatchingCountController.text = + hatchingModel?.quantity?.separatedByComma ?? 'تعداد جوجه ریزی نامشخص'; + + hatchingBreedController.text = + hatchingModel?.chickenBreed ?? 'نوع نژاد نامشخص'; + + visitDateController.text = Jalali.now().formatCompactDate(); + } + + void toggleExpanded(int index) { + expandedIndex.value = expandedIndex.value == index ? -1 : index; + } + + void setHatchingModel(HatchingModel hatchingModel) { + this.hatchingModel = hatchingModel; + } + + void changeSegmentIndex(int index) { + if (index == selectedSegmentIndex.value) { + return; + } + expandedIndex.value = -1; + selectedSegmentIndex.value = index; + } + + void changeTab(int index) { + if (index == selectedTabIndex.value) { + return; + } + selectedTabIndex.value = index; + } + + void clearForm() { + unitNameController.clear(); + activeStepperIndex.value = 0; + selectedTabIndex.value = 0; + } + + void setSanitaryConditionOfTheHallIndex(int index, String item) { + sanitaryConditionOfTheHall.value = item; + sanitaryConditionOfTheHallIndex.value = + index == sanitaryConditionOfTheHallIndex.value ? -1 : index; + } + + void setFuelTypeIndex(int index, String item) { + fuelType.value = item; + fuelTypeIndex.value = index == fuelTypeIndex.value ? -1 : index; + } + + void setVentilationStatusIndex(int index, String item) { + ventilationStatus.value = item; + ventilationStatusIndex.value = index == ventilationStatusIndex.value + ? -1 + : index; + } + + void setBeddingStatusIndex(int index, String item) { + beddingStatus.value = item; + beddingStatusIndex.value = index == beddingStatusIndex.value ? -1 : index; + } + + void setWaterQualityIndex(int index, String item) { + waterQuality.value = item; + waterQualityIndex.value = index == waterQualityIndex.value ? -1 : index; + } + + void setSampleTypeIndex(int index, String item) { + sampleType.value = item; + sampleTypeIndex.value = index == sampleTypeIndex.value ? -1 : index; + } + + void setGrainQualityInput(int index, String item) { + grainQualityInput.value = item; + grainQualityInputIndex.value = index == grainQualityInputIndex.value + ? -1 + : index; + } + + void setGeneratorOperatingStatusIndex(int index, String item) { + generatorOperatingStatus.value = item; + generatorOperatingStatusIndex.value = + index == generatorOperatingStatusIndex.value ? -1 : index; + } + + void setWorkerContractStatusIndex(int index, String item) { + workerContractStatus.value = item; + + workerContractStatusIndex.value = index == workerContractStatusIndex.value + ? -1 + : index; + } + + void setNewBeneficiaryRequestIndex(int index) { + newBeneficiaryRequestIndex.value = index == newBeneficiaryRequestIndex.value + ? -1 + : index; + } + + void setInspectorConclusionIndex(int index, String item) { + inspectorConclusion.value = item; + inspectorConclusionIndex.value = index == inspectorConclusionIndex.value + ? -1 + : index; + } + + Future getCurrentLocation() async { + isLoadingLocation.value = true; + + try { + final hasPermission = await checkLocationPermission(request: true); + if (!hasPermission) { + throw Exception('دسترسی به موقعیت مکانی داده نشده است'); + } + + // Get current location + final latLng = await determineCurrentLatLng(); + currentLocation.value = latLng; + isLoadingLocation.value = false; + setUpNextButtonListeners(); + } catch (e) { + isLoadingLocation.value = false; + currentLocation.value = null; + nextStepButtonEnabled.value = false; + } + } + + void setUpNextButtonListeners() { + if (activeStepperIndex.value == 0) { + nextStepButtonEnabled.value = currentLocation.value != null; + } else { + nextStepButtonEnabled.value = false; + } + } + + Future pickImageFromCamera() async { + try { + final XFile? image = await imagePicker.pickImage( + source: ImageSource.camera, + imageQuality: 50, + maxWidth: 1080, + maxHeight: 720, + ); + + if (image != null) { + pultryImages[image] = false; + + //await uploadImage(image); + } + } catch (e) { + Get.snackbar( + 'خطا', + 'خطا در باز کردن دوربین', + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.red, + colorText: Colors.white, + ); + } + } + + Future uploadImage(XFile imageFile) async { + await safeCall( + call: () async { + final urls = await repository.uploadImages( + token: tokenStorageService.accessToken.value ?? '', + images: [imageFile], + ); + return urls; + }, + onSuccess: (urls) { + if (urls != null) { + pultryImagesUrls.addAll(urls); + } + pultryImages[imageFile] = true; + }, + onError: (error, e) { + pultryImages[imageFile] = false; + }, + ); + } + + void removeImage(XFile image) { + pultryImages.remove(image); + } + + void setTypeOfDiseaseIndex(String item) { + if (isOtherTypeOfDiseaseSelected.value && item != 'سایر (شرح)') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value - 50; + } + typeOfDisease.value = item; + isOtherTypeOfDiseaseSelected.value = item == 'سایر (شرح)'; + if (isOtherTypeOfDiseaseSelected.value && item == 'سایر (شرح)') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value + 50; + } + } + + void setCauseOfUnusualCasualtiesIndex(String item) { + if (isOthercauseOfUnusualCasualties.value && item != 'سایر (شرح…)') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value - 50; + } + causeOfUnusualCasualties.value = item; + isOthercauseOfUnusualCasualties.value = item == 'سایر (شرح…)'; + if (item == 'سایر (شرح…)') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value + 50; + } + } + + void setSamplingDone(String value) { + if (samplingDone.value && value != 'انجام شد') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value -80; + } + samplingDone.value = value == 'انجام شد'; + if (value == 'انجام شد') { + casualtiesInformationHeight.value = + casualtiesInformationHeight.value + 80; + } + } + + void setInputStatus(String item) { + inputStatus.value = item; + } + + void setTypeOfGrain(String item) { + typeOfGrain.value = item; + } + + void setFuelType(String item) { + fuelType.value = item; + } + + void setPowerCutHistory(String item) { + powerCutHistory.value = item == 'دارد'; + } + + void setTrainingStatus(String item) { + trainingStatus.value = item == 'بله'; + } + + void setNewBeneficiaryRequest(String item) { + newBeneficiaryRequest.value = item; + } + + void setOverdueStatus(String item) { + overdueStatus.value = item == 'دارای معوقه'; + } + + void showPaymentYearDatePicker() { + Get.bottomSheet( + modalDatePicker( + initialDate: selectedPaymentYear.value, + onDateSelected: (value) { + selectedPaymentYear.value = value; + paymentYearController.text = value.formatCompactDate(); + }, + ), + ); + } + + void showFacilityYearDatePicker() { + Get.bottomSheet( + modalDatePicker( + initialDate: selectedFacilityYear.value, + onDateSelected: (value) { + selectedFacilityYear.value = value; + facilityYearController.text = value.formatCompactDate(); + Get.back(); + }, + ), + ); + } + + void removeHallImage(XFile key) { + hallImages.remove(key); + } + + void removeInputWarehouseImage(XFile key) { + inputWarehouseImages.remove(key); + } + + void removeLossesImage(XFile key) { + lossesImages.remove(key); + } +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step1_page.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step1_page.dart new file mode 100644 index 0000000..c848934 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step1_page.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; +import 'package:rasadyar_core/core.dart'; + +Widget step1Page(CreateInspectionBottomSheetLogic controller) { + return SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + children: [ + SizedBox(height: 25.h), + + Container( + height: controller.tenantStatusController.text == 'دارد' + ? 570.h + : 445.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'اطلاعات پایه واحد', + child: basicUnitInformation(controller), + ), + ), + + SizedBox(height: 30.h), + + Container( + height: 280.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'اطلاعات جوجه ریزی', + child: hatchingInformation(controller), + ), + ), + SizedBox(height: 16.h), + ], + ), + ); +} + +Column basicUnitInformation(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + RTextField( + controller: controller.unitNameController, + label: 'نام واحد مرغداری', + filled: true, + filledColor: AppColor.bgLight, + readonly: true, + ), + + RTextField( + controller: controller.breedingUniqueIdController, + label: 'کد یکتا / شناسه واحد', + filled: true, + readonly: true, + filledColor: AppColor.bgLight, + ), + + RTextField( + controller: controller.healthLicenseController, + label: 'پروانه بهداشتی', + filled: true, + filledColor: AppColor.bgLight, + ), + + RTextField( + controller: controller.tenantStatusController, + label: 'وضعیت مستاجر', + filled: true, + filledColor: AppColor.bgLight, + ), + + Visibility( + child: controller.tenantStatusController.text == 'دارد' + ? Column( + spacing: 10, + children: [ + RTextField( + controller: controller.tenantNameController, + label: 'نام مستاجر', + filled: true, + filledColor: AppColor.bgLight, + ), + + RTextField( + controller: controller.tenantNationalIdController, + label: 'کد ملی مستاجر', + filled: true, + filledColor: AppColor.bgLight, + ), + + RTextField( + controller: controller.tenantPhoneNumberController, + label: 'شماره تماس مستاجر', + filled: true, + filledColor: AppColor.bgLight, + ), + ], + ) + : SizedBox.shrink(), + ), + RTextField( + controller: controller.ownerNationalCodeController, + label: 'کد ملی بهره‌بردار', + filled: true, + readonly: true, + filledColor: AppColor.bgLight, + ), + RTextField( + controller: controller.ownerPhoneNumberController, + label: 'شماره تماس بهره‌بردار', + filled: true, + readonly: true, + filledColor: AppColor.bgLight, + ), + RTextField( + controller: controller.totalCapacityController, + label: 'ظرفیت اسمی سالن‌ها', + filled: true, + filledColor: AppColor.bgLight, + ), + + Obx( + () => RElevated( + isFullWidth: true, + height: 40.h, + enabled: !controller.isLoadingLocation.value, + + backgroundColor: AppColor.greenNormal, + onPressed: controller.isLoadingLocation.value + ? null + : () => controller.getCurrentLocation(), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 4, + children: [ + if (controller.isLoadingLocation.value) + SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation(Colors.white), + ), + ) + else + Icon(Icons.my_location_rounded, color: Colors.white, size: 24), + Text( + controller.currentLocation.value == null + ? 'دریافت موقعیت جغرافیایی' + : 'موقعیت جغرافیایی دریافت شد', + + style: AppFonts.yekan14.copyWith(color: Colors.white), + ), + ], + ), + ), + ), + ], + ); +} + +Column hatchingInformation(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + RTextField( + controller: controller.hatchingDateController, + label: 'تاریخ جوجه ریزی', + filled: true, + filledColor: AppColor.bgLight, + readonly: true, + ), + + RTextField( + controller: controller.visitDateController, + label: 'تاریخ بازدید', + filled: true, + filledColor: AppColor.bgLight, + readonly: true, + ), + + RTextField( + controller: controller.hatchingCountController, + label: 'تعداد جوجه‌ریزی اولیه', + filled: true, + filledColor: AppColor.bgLight, + readonly: true, + ), + + /* ResourceOverlayDropdown( + items: Resource.success(['سرابی', 'پژدر', 'روتوایلر', 'دیگر']), + + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'نوع نژاد'), + ), */ + + /* RTextField( + controller: controller.unitNameController, + label: 'گرید جوجه', + filled: true, + filledColor: AppColor.bgLight, + readonly: true, + ), */ + RTextField( + controller: controller.hatchingBreedController, + label: 'نوع نژاد', + filled: true, + filledColor: AppColor.bgLight, + ), + RTextField( + controller: controller.hatchingAverageWeightController, + label: 'میانگین وزن جوجه', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + ), + ], + ); +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart new file mode 100644 index 0000000..efca538 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart @@ -0,0 +1,654 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'create_inspection_bottom_sheet_logic.dart'; + +Widget step2Page(CreateInspectionBottomSheetLogic controller) { + return SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + children: [ + SizedBox(height: 35.h), + + Container( + height: 580.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'وضعیت عمومی سالن', + child: generalConditionOfTheHall(controller), + ), + ), + + SizedBox(height: 30.h), + + ObxValue((data) { + return Container( + height: data.value.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'تلفات', + child: casualtiesInformation(controller), + ), + ); + }, controller.casualtiesInformationHeight), + SizedBox(height: 24.h), + + Container( + height: 130.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'بیماری‌ها و وضعیت سلامت', + child: diseasesAndHealthInformation(controller), + ), + ), + ], + ), + ); +} + +Column generalConditionOfTheHall(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox.shrink(), + cardInfo( + padding: EdgeInsets.fromLTRB(0, 12, 12, 6), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Obx( + () => SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + // Fix: Use spread .entries.map for map iteration, and correct image argument + spacing: 8, + children: [ + ...controller.pultryImages.entries + .map( + (entry) => Stack( + children: [ + Container( + height: 80.h, + width: 80.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(entry.key.path), + fit: BoxFit.cover, + ), + ), + ), + // Delete button + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () => + controller.removeImage(entry.key), + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: Icon( + Icons.close, + color: Colors.white, + size: 16, + ), + ), + ), + ), + // Upload indicator + if (entry.value == false) + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation( + Colors.white, + ), + ), + ), + ), + ), + ), + ], + ), + ) + .toList(), + // Add image button + GestureDetector( + onTap: () => controller.pickImageFromCamera(), + child: Container( + height: 80.h, + width: 80.w, + padding: EdgeInsets.all(22), + decoration: BoxDecoration( + color: Color(0xFFE9E9E9), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Assets.vec.galleryAddSvg.svg( + width: 36, + height: 36, + ), + ), + ), + ], + ), + ), + ), + + Text( + 'تعداد موجود فعلی', + style: AppFonts.yekan14.copyWith(color: AppColor.textColorLight), + ), + ], + ), + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت بهداشتی سالن', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + spacing: 8, + children: [ + Expanded( + child: containerChips( + selectedIndex: data.value, + index: 0, + label: 'عالی', + onTap: (index) => controller + .setSanitaryConditionOfTheHallIndex(index, 'عالی'), + ), + ), + Expanded( + child: containerChips( + selectedIndex: data.value, + index: 1, + label: 'خوب', + onTap: (index) => controller + .setSanitaryConditionOfTheHallIndex(index, 'خوب'), + ), + ), + Expanded( + child: containerChips( + selectedIndex: data.value, + index: 2, + label: 'متوسط', + onTap: (index) => controller + .setSanitaryConditionOfTheHallIndex(index, 'متوسط'), + ), + ), + Expanded( + child: containerChips( + selectedIndex: data.value, + index: 3, + label: 'ضعیف', + onTap: (index) => controller + .setSanitaryConditionOfTheHallIndex(index, 'ضعیف'), + ), + ), + ], + ); + }, controller.sanitaryConditionOfTheHallIndex), + ], + ), + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت تهویه', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Expanded( + child: containerChips( + onTap: (index) => + controller.setVentilationStatusIndex(index, 'عالی'), + selectedIndex: data.value, + index: 0, + label: 'عالی', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setVentilationStatusIndex(index, 'خوب'), + selectedIndex: data.value, + index: 1, + label: 'خوب', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setVentilationStatusIndex(index, 'متوسط'), + selectedIndex: data.value, + index: 2, + label: 'متوسط', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setVentilationStatusIndex(index, 'ضعیف'), + selectedIndex: data.value, + index: 3, + label: 'ضعیف', + ), + ), + ], + ); + }, controller.ventilationStatusIndex), + ], + ), + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت بستر', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + spacing: 8, + children: [ + Expanded( + child: containerChips( + onTap: (index) => + controller.setBeddingStatusIndex(index, 'خشک'), + selectedIndex: data.value, + index: 0, + label: 'خشک', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setBeddingStatusIndex(index, 'نیمه‌مرطوب'), + selectedIndex: data.value, + index: 1, + label: 'نیمه‌مرطوب', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setBeddingStatusIndex(index, 'مرطوب'), + selectedIndex: data.value, + index: 2, + label: 'مرطوب', + ), + ), + ], + ); + }, controller.beddingStatusIndex), + ], + ), + ), + + RTextField( + controller: controller.hatchingTemperatureController, + label: 'دمای سالن', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + minLines: 1, + keyboardType: TextInputType.number, + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + ' آب مصرفی', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 10, + children: [ + Expanded( + child: containerChips( + onTap: (index) => + controller.setWaterQualityIndex(index, 'چاه'), + selectedIndex: data.value, + index: 0, + label: 'چاه', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setWaterQualityIndex(index, 'شهری'), + selectedIndex: data.value, + index: 1, + label: 'شهری', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setWaterQualityIndex(index, 'تصفیه‌شده'), + selectedIndex: data.value, + index: 2, + label: 'تصفیه‌شده', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setWaterQualityIndex(index, 'حمل تانکر'), + selectedIndex: data.value, + index: 3, + label: 'حمل تانکر', + ), + ), + ], + ); + }, controller.waterQualityIndex), + ], + ), + ), + RTextField( + controller: controller.waterHardnessController, + label: 'درصد سختی آب (PPM)', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + minLines: 1, + keyboardType: TextInputType.numberWithOptions(decimal: true), + ), + ], + ); +} + +ChoiceChip formChips({ + required int selectedIndex, + required int index, + required String label, + required Function(int) onTap, +}) { + return ChoiceChip( + selectedColor: AppColor.green1Normal, + labelStyle: index == selectedIndex + ? AppFonts.yekan14Bold.copyWith(color: Colors.white) + : AppFonts.yekan14.copyWith(color: AppColor.textColor), + surfaceTintColor: Colors.white, + checkmarkColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: index == selectedIndex + ? BorderSide.none + : BorderSide(width: 1, color: AppColor.blackLightHover), + ), + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), + + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + label: Text(label), + selected: index == selectedIndex, + onSelected: (value) => onTap(index), + ); +} + +Column casualtiesInformation(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + RTextField( + controller: controller.normalLossesController, + label: 'تعداد تلفات عادی دوره', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + maxLines: 1, + minLines: 1, + ), + + RTextField( + controller: controller.abnormalLossesController, + label: 'تلفات غیرعادی', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + maxLines: 1, + minLines: 1, + ), + + ResourceOverlayDropdown( + items: controller.causeOfUnusualCasualtiesList, + onChanged: (item) => controller.setCauseOfUnusualCasualtiesIndex(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'علت تلفات غیرعادی'), + ), + + ObxValue((data) { + return Visibility( + visible: data.value, + child: RTextField( + controller: controller.otherCauseOfUnusualCasualtiesController, + label: 'علت تلفات غیرعادی', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + minLines: 1, + ), + ); + }, controller.isOthercauseOfUnusualCasualties), + + ResourceOverlayDropdown( + items: controller.typeOfDiseaseList, + onChanged: (item) => controller.setTypeOfDiseaseIndex(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => + Text(selected ?? 'نوع بیماری تشخیص داده‌شده / مشکوک'), + ), + + ObxValue((data) { + return Visibility( + visible: data.value, + child: RTextField( + controller: controller.otherTypeOfDiseaseController, + label: 'نوع بیماری', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + minLines: 1, + ), + ); + }, controller.isOtherTypeOfDiseaseSelected), + + ResourceOverlayDropdown( + items: Resource.success(['انجام شد', 'انجام نشد']), + onChanged: (item) => controller.setSamplingDone(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'نمونه‌برداری انجام‌شده'), + ), + + ObxValue((data) { + return Visibility( + visible: data.value, + child: cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'نوع نمونه', + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.textColor2, + ), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Expanded( + child: containerChips( + onTap: (index) => + controller.setSampleTypeIndex(index, 'لاشه'), + selectedIndex: data.value, + index: 0, + label: 'لاشه', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setSampleTypeIndex(index, 'آب'), + selectedIndex: data.value, + index: 1, + label: 'آب', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setSampleTypeIndex(index, 'دانه'), + selectedIndex: data.value, + index: 2, + label: 'دانه', + ), + ), + ], + ); + }, controller.sampleTypeIndex), + ], + ), + ), + ); + }, controller.samplingDone), + ], + ); +} + +Column diseasesAndHealthInformation( + CreateInspectionBottomSheetLogic controller, +) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + + RTextField( + controller: controller.technicalHealthOfficerNameController, + label: 'نام مسئول فنی بهداشتی', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + + RTextField( + controller: controller.technicalEngineeringOfficerNameController, + label: 'نام مسئول فنی نظام مهندسی', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + ], + ); +} + +GestureDetector containerChips({ + required int selectedIndex, + required int index, + required String label, + required Function(int) onTap, +}) { + return GestureDetector( + onTap: () => onTap(index), + child: Container( + height: 24.h, + decoration: BoxDecoration( + color: index == selectedIndex + ? AppColor.green1Normal + : AppColor.whiteGreyNormal, + borderRadius: BorderRadius.circular(8), + border: index == selectedIndex + ? Border.fromBorderSide(BorderSide.none) + : Border.all(width: 1, color: AppColor.blackLightHover), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 5, + children: [ + if (index == selectedIndex) + Icon(Icons.check, color: Colors.white, size: 16), + Text( + label, + style: index == selectedIndex + ? AppFonts.yekan14Bold.copyWith(color: Colors.white) + : AppFonts.yekan14.copyWith(color: AppColor.textColor), + ), + ], + ), + ), + ); +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step3_page.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step3_page.dart new file mode 100644 index 0000000..343c2d6 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step3_page.dart @@ -0,0 +1,517 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'create_inspection_bottom_sheet_logic.dart'; + +Widget step3Page(CreateInspectionBottomSheetLogic controller) { + return SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + children: [ + SizedBox(height: 35.h), + + Container( + height: 350.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'نهاده و خوراک', + child: agriculturalInput(controller), + ), + ), + + SizedBox(height: 30.h), + + Container( + height: 600.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'زیرساخت و انرژی', + child: infrastructureAndEnergy(controller), + ), + ), + SizedBox(height: 24.h), + + Container( + height: 310.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'نیروی انسانی', + child: humanResources(controller), + ), + ), + SizedBox(height: 24.h), + + Container( + height: 320.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'تسهیلات و حمایت‌ها', + child: facilitiesAndSupport(controller), + ), + ), + SizedBox(height: 24.h), + ], + ), + ); +} + +Column infrastructureAndEnergy(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + RTextField( + controller: controller.generatorTypeController, + label: 'نوع ژنراتور', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + RTextField( + controller: controller.generatorModelController, + label: 'مدل ژنراتور', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + RTextField( + controller: controller.generatorCountController, + label: 'تعداد ژنراتور', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + keyboardType: TextInputType.number, + ), + + ResourceOverlayDropdown( + items: Resource.success(['گازوئیل', 'نفت گاز']), + + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'نوع سوخت'), + onChanged: (item) => controller.setFuelType(item), + ), + + RTextField( + controller: controller.generatorCapacityController, + label: 'ظرفیت (KVA)', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت عملکرد ژنراتور', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 10, + children: [ + Expanded( + child: containerChips( + onTap: (index) => controller + .setGeneratorOperatingStatusIndex(index, 'سالم'), + selectedIndex: data.value, + index: 0, + label: 'سالم', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller + .setGeneratorOperatingStatusIndex(index, 'نیمه‌سالم'), + selectedIndex: data.value, + index: 1, + label: 'نیمه‌سالم', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller + .setGeneratorOperatingStatusIndex(index, 'معیوب'), + selectedIndex: data.value, + index: 2, + label: 'معیوب', + ), + ), + ], + ); + }, controller.generatorOperatingStatusIndex), + ], + ), + ), + + RTextField( + controller: controller.emergencyFuelInventoryController, + label: 'میزان موجودی سوخت اضطراری (لیتر)', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + ResourceOverlayDropdown( + items: Resource.success(['ندارد', 'دارد']), + onChanged: (item) => controller.setPowerCutHistory(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => + Text(selected ?? 'سابقه قطعی برق دوره جاری'), + ), + + RTextField( + controller: controller.powerCutDurationController, + label: 'مدت قطعی', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + RTextField( + controller: controller.powerCutHourController, + label: 'ساعت قطعی', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + RTextField( + controller: controller.additionalNotesController, + label: 'توضیحات تکمیلی', + filled: true, + maxLines: 5, + minLines: 5, + filledColor: AppColor.bgLight, + ), + ], + ); +} + +Column agriculturalInput(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox.shrink(), + + ResourceOverlayDropdown( + items: controller.inputStatusList, + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'وضعیت نهاده'), + onChanged: (item) => controller.setInputStatus(item), + ), + + ObxValue((data) { + if (data.value == 'وابسته') { + return RTextField( + controller: controller.companyNameController, + label: 'نام کارخانه', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ); + } else { + return RTextField( + controller: controller.trackingCodeController, + label: 'شناسه خرید یا کد پیگیری', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ); + } + }, controller.inputStatus), + + RTextField( + controller: controller.inputInventoryUntilVisitController, + label: 'موجودی نهاده مصرفی تا روز بازدید (کیلوگرم)', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + ResourceOverlayDropdown( + items: controller.typeOfGrainList, + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'نوع دان'), + onChanged: (item) => controller.setTypeOfGrain(item), + ), + + RTextField( + controller: controller.inputInventoryInWarehouseController, + label: 'موجودی نهاده موجود در انبار (کیلوگرم)', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'کیفیت دانه', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 10, + children: [ + Expanded( + child: containerChips( + onTap: (index) => + controller.setGrainQualityInput(index, 'متوسط'), + selectedIndex: data.value, + index: 0, + label: 'خوب', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setGrainQualityInput(index, 'خوب'), + selectedIndex: data.value, + index: 1, + label: 'متوسط', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => + controller.setGrainQualityInput(index, 'ضعیف'), + selectedIndex: data.value, + index: 2, + label: 'ضعیف', + ), + ), + ], + ); + }, controller.grainQualityInputIndex), + ], + ), + ), + ], + ); +} + +Column humanResources(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + + RTextField( + controller: controller.employedWorkersCountController, + label: 'تعداد افراد شاغل', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + RTextField( + controller: controller.nativeWorkersCountController, + label: 'تعداد افراد بومی', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + RTextField( + controller: controller.nonNativeWorkersCountController, + label: 'تعداد افراد غیر بومی', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت قرارداد کارگران', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Expanded( + child: containerChips( + onTap: (index) => controller.setWorkerContractStatusIndex( + index, + 'دائم', + ), + selectedIndex: data.value, + index: 0, + label: 'دائم', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller.setWorkerContractStatusIndex( + index, + 'موقت', + ), + selectedIndex: data.value, + index: 1, + label: 'موقت', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller.setWorkerContractStatusIndex( + index, + 'روزمزدی', + ), + selectedIndex: data.value, + index: 2, + label: 'روزمزدی', + ), + ), + ], + ); + }, controller.workerContractStatusIndex), + ], + ), + ), + + ResourceOverlayDropdown( + items: Resource.success(['بله', 'خیر']), + onChanged: (item) => controller.setTrainingStatus(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => + Text(selected ?? 'آموزش‌دیده در حوزه بهداشت و امنیت زیستی'), + ), + ], + ); +} + +Column facilitiesAndSupport(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + + RTextField( + controller: controller.activeFacilityController, + label: 'تسهیلات دریافتی فعال', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + + RTextField( + controller: controller.facilityTypeController, + label: 'نوع تسهیلات', + filled: true, + filledColor: AppColor.bgLight, + maxLines: 1, + ), + + RTextField( + controller: controller.facilityAmountController, + label: 'مبلغ', + filled: true, + filledColor: AppColor.bgLight, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + SeparatorInputFormatter(), + ], + maxLines: 1, + ), + RTextField( + controller: controller.paymentYearController, + label: 'سال دریافت', + filled: true, + readonly: true, + onTap: () => controller.showPaymentYearDatePicker(), + filledColor: AppColor.bgLight, + maxLines: 1, + ), + + ResourceOverlayDropdown( + items: Resource.success(['دارای معوقه', 'منظم']), + onChanged: (item) => controller.setOverdueStatus(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'وضعیت بازپرداخت'), + ), + + ResourceOverlayDropdown( + items: Resource.success(['نهاده', 'تسهیلات', 'واکسن', 'تجهیزات']), + onChanged: (item) => controller.setNewBeneficiaryRequest(item), + itemBuilder: (item) => Text(item), + labelBuilder: (selected) => Text(selected ?? 'درخواست جدید بهره بردار'), + ), + ], + ); +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step4_page.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step4_page.dart new file mode 100644 index 0000000..156329e --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step4_page.dart @@ -0,0 +1,495 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart'; +import 'package:rasadyar_core/core.dart'; + +import 'create_inspection_bottom_sheet_logic.dart'; + +Widget step4Page(CreateInspectionBottomSheetLogic controller) { + return SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: Column( + children: [ + SizedBox(height: 35.h), + + Container( + height: 430.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'مستندات', + child: documents(controller), + ), + ), + + SizedBox(height: 30.h), + + Container( + height: 235.h, + clipBehavior: Clip.none, + width: Get.width, + child: farmInfoWidget( + controller: controller, + title: 'جمع‌بندی بازرس', + child: inspectorConclusion(controller), + ), + ), + SizedBox(height: 24.h), + ], + ), + ); +} + +Column documents(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + cardInfo( + padding: EdgeInsets.fromLTRB(0, 12, 12, 6), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + SizedBox(height: 10.h), + Obx( + () => SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + spacing: 8, + children: [ + ...controller.hallImages.entries + .map( + (entry) => Stack( + children: [ + Container( + height: 80.h, + width: 80.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(entry.key.path), + fit: BoxFit.cover, + ), + ), + ), + // Delete button + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () => + controller.removeImage(entry.key), + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: Icon( + Icons.close, + color: Colors.white, + size: 16, + ), + ), + ), + ), + // Upload indicator + if (entry.value == false) + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation( + Colors.white, + ), + ), + ), + ), + ), + ), + ], + ), + ) + .toList(), + // Add image button + GestureDetector( + onTap: () => controller.pickImageFromCamera(), + child: Container( + height: 80.h, + width: 80.w, + padding: EdgeInsets.all(22), + decoration: BoxDecoration( + color: Color(0xFFE9E9E9), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Assets.vec.galleryAddSvg.svg( + width: 36, + height: 36, + ), + ), + ), + ], + ), + ), + ), + + RichText( + text: TextSpan( + children: [ + TextSpan( + text: 'ثبت عکس سالن (حداقل ۳ زاویه) ', + style: AppFonts.yekan14.copyWith( + color: AppColor.textColorLight, + ), + ), + TextSpan( + text: '*', + style: AppFonts.yekan14.copyWith(color: Colors.red), + ), + ], + ), + ), + ], + ), + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(0, 12, 12, 6), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Obx( + () => SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + spacing: 8, + children: [ + ...controller.inputWarehouseImages.entries + .map( + (entry) => Stack( + children: [ + Container( + height: 80.h, + width: 80.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(entry.key.path), + fit: BoxFit.cover, + ), + ), + ), + // Delete button + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () => controller + .removeInputWarehouseImage(entry.key), + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: Icon( + Icons.close, + color: Colors.white, + size: 16, + ), + ), + ), + ), + // Upload indicator + if (entry.value == false) + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation( + Colors.white, + ), + ), + ), + ), + ), + ), + ], + ), + ) + .toList(), + // Add image button + GestureDetector( + onTap: () => controller.pickImageFromCamera(), + child: Container( + height: 80.h, + width: 80.w, + padding: EdgeInsets.all(22), + decoration: BoxDecoration( + color: Color(0xFFE9E9E9), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Assets.vec.galleryAddSvg.svg( + width: 36, + height: 36, + ), + ), + ), + ], + ), + ), + ), + + Text( + 'ثبت عکس انبار نهاده‌ها', + style: AppFonts.yekan14.copyWith(color: AppColor.textColorLight), + ), + ], + ), + ), + + cardInfo( + padding: EdgeInsets.fromLTRB(0, 12, 12, 6), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Obx( + () => SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + spacing: 8, + children: [ + ...controller.lossesImages.entries + .map( + (entry) => Stack( + children: [ + Container( + height: 80.h, + width: 80.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + File(entry.key.path), + fit: BoxFit.cover, + ), + ), + ), + // Delete button + Positioned( + top: -4, + right: -4, + child: GestureDetector( + onTap: () => controller + .removeInputWarehouseImage(entry.key), + child: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + color: Colors.red, + shape: BoxShape.circle, + ), + child: Icon( + Icons.close, + color: Colors.white, + size: 16, + ), + ), + ), + ), + // Upload indicator + if (entry.value == false) + Positioned.fill( + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.5), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: + AlwaysStoppedAnimation( + Colors.white, + ), + ), + ), + ), + ), + ), + ], + ), + ) + .toList(), + // Add image button + GestureDetector( + onTap: () => controller.pickImageFromCamera(), + child: Container( + height: 80.h, + width: 80.w, + padding: EdgeInsets.all(22), + decoration: BoxDecoration( + color: Color(0xFFE9E9E9), + border: Border.all( + width: 1, + color: AppColor.blackLightHover, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Assets.vec.galleryAddSvg.svg( + width: 36, + height: 36, + ), + ), + ), + ], + ), + ), + ), + + Text( + 'ثبت عکس تلفات', + style: AppFonts.yekan14.copyWith(color: AppColor.textColorLight), + ), + ], + ), + ), + ], + ); +} + +Column inspectorConclusion(CreateInspectionBottomSheetLogic controller) { + return Column( + spacing: 10, + children: [ + SizedBox(height: 1.h), + + cardInfo( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 9, + children: [ + Text( + 'وضعیت کلی واحد', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2), + ), + + ObxValue((data) { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 8, + children: [ + Expanded( + child: containerChips( + onTap: (index) => controller.setInspectorConclusionIndex( + index, + 'تایید شده', + ), + selectedIndex: data.value, + index: 0, + label: 'تایید شده', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller.setInspectorConclusionIndex( + index, + 'نیازمند اصلاح', + ), + selectedIndex: data.value, + index: 1, + label: 'نیازمند اصلاح', + ), + ), + Expanded( + child: containerChips( + onTap: (index) => controller.setInspectorConclusionIndex( + index, + 'پرریسک', + ), + selectedIndex: data.value, + index: 2, + label: 'پرریسک', + ), + ), + ], + ); + }, controller.inspectorConclusionIndex), + ], + ), + ), + + RTextField( + height: 100.h, + controller: controller.inspectorConclusionDescriptionController, + hintText: 'توصیه‌ها / اخطارها / اقدامات اصلاحی ...', + hintStyle: AppFonts.yekan14.copyWith(color: AppColor.textColorLight), + maxLines: 5, + minLines: 5, + filled: true, + filledColor: AppColor.bgLight, + ), + ], + ); +} diff --git a/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step5_page.dart b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step5_page.dart new file mode 100644 index 0000000..0ded870 --- /dev/null +++ b/packages/chicken/lib/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step5_page.dart @@ -0,0 +1,599 @@ +import 'package:flutter/material.dart'; +import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/create_inspection_bottom_sheet_logic.dart'; +import 'package:rasadyar_core/core.dart'; + + + +Widget step5Page(CreateInspectionBottomSheetLogic controller) { + return SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: detailsWidget(controller), + ); +} + +Widget detailsWidget(CreateInspectionBottomSheetLogic controller) { + return Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 10, + ), + child: Text( + 'جزییات', + style: AppFonts.yekan18Bold.copyWith( + color: AppColor.iconColor, + ), + ), + ), + ], + ), + Divider(color: AppColor.blackLightHover, height: 1, thickness: 1), + ObxValue((data) { + return tabBarWidget( + ['اطلاعات', 'پاییش سلامت', 'زیرساخت', 'مستندات'], + controller.selectedTabIndex.value, + (index) => controller.changeTab(index), + ); + }, controller.selectedTabIndex), + + ObxValue((data) { + switch (data.value) { + case 0: + return infoTable(); + case 1: + return healthTable(); + case 2: + return infrastructureTable(); + case 3: + return documentsTable(); + default: + return infoTable(); + } + }, controller.selectedTabIndex), + ], + ), + + // Expanded در سطح بالاتر + ], + ); +} + +Column infoTable() { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 10), + Row( + children: [ + Text( + 'مشخصات کلی', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.iconColor), + ), + ], + ), + SizedBox(height: 10), + + Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + rTableRow(title: 'نام واحد مرغداری', value: 'لذیذ'), + rTableRow(title: 'کد یکتا / شناسه واحد', value: '2541415'), + rTableRow(title: 'نام مالک / بهره‌بردار', value: 'مرغداری احمدی'), + rTableRow(title: 'موجودی سوخت اضطراری', value: '200 لیتر'), + + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + ], + ), + ), + ], + ); +} + +Row rTableRow({String? title, String? value}) { + return Row( + children: [ + Expanded( + flex: 1, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 9, vertical: 11), + alignment: Alignment.centerRight, + decoration: BoxDecoration( + color: AppColor.bgLight2, + border: Border( + bottom: BorderSide(color: AppColor.blackLightHover, width: 1), + ), + ), + child: Text( + title ?? '', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.iconColor), + ), + ), + ), + Expanded( + flex: 1, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 9, vertical: 11), + alignment: Alignment.centerRight, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(color: AppColor.blackLightHover, width: 1), + ), + ), + child: Text( + value ?? '', + style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor), + ), + ), + ), + ], + ); +} + +Widget tabBarWidget( + List tabs, + int selectedIndex, + Function(int) onTabSelected, +) { + return SizedBox( + height: 38.h, + width: Get.width, + child: Stack( + fit: StackFit.expand, + children: [ + Positioned( + right: 0, + top: 0, + bottom: 0, + child: Row( + children: [ + ...tabs.map( + (tab) => GestureDetector( + onTap: () => onTabSelected(tabs.indexOf(tab)), + behavior: HitTestBehavior.opaque, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10, vertical: 11), + decoration: BoxDecoration( + border: tab == tabs[selectedIndex] + ? Border( + bottom: BorderSide( + color: AppColor.blueNormalOld, + width: 3, + ), + ) + : null, + ), + child: Text( + tab, + style: AppFonts.yekan12Bold.copyWith( + color: tab == tabs[selectedIndex] + ? AppColor.blueNormalOld + : AppColor.mediumGrey, + ), + ), + ), + ), + ), + ], + ), + ), + + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Divider( + color: AppColor.blackLightHover, + height: 1, + thickness: 1, + ), + ), + ], + ), + ); +} + +Widget healthTable() { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 10), + Row( + children: [ + Text( + 'پاییش سلامت', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.iconColor), + ), + ], + ), + SizedBox(height: 10), + + Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + rTableRow(title: 'نام واحد مرغداری', value: 'لذیذ'), + rTableRow(title: 'کد یکتا / شناسه واحد', value: '2541415'), + rTableRow(title: 'نام مالک / بهره‌بردار', value: 'مرغداری احمدی'), + rTableRow(title: 'موجودی سوخت اضطراری', value: '200 لیتر'), + + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + ], + ), + ), + ], + ); +} + +Widget infrastructureTable() { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 10), + Row( + children: [ + Text( + 'زیرساخت', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.iconColor), + ), + ], + ), + SizedBox(height: 10), + + Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + rTableRow(title: 'نام واحد مرغداری', value: 'لذیذ'), + rTableRow(title: 'کد یکتا / شناسه واحد', value: '2541415'), + rTableRow(title: 'نام مالک / بهره‌بردار', value: 'مرغداری احمدی'), + rTableRow(title: 'موجودی سوخت اضطراری', value: '200 لیتر'), + + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + rTableRow(title: 'شهر/تعاونی', value: 'خرم آباد/تعاونی خرم آباد'), + + rTableRow(title: 'شماره تلفن واحد', value: '021-12345678'), + rTableRow(title: 'دامپزشک فارم', value: 'dd dd (05218569685)'), + + rTableRow(title: 'سالن', value: '2'), + rTableRow( + title: 'تاریخ ثبت جوجه ریزی', + value: '1402/09/19 (10:12)', + ), + ], + ), + ), + ], + ); +} + +Widget documentsTable() { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox(height: 10), + Row( + children: [ + Text( + 'مستندات', + style: AppFonts.yekan16Bold.copyWith(color: AppColor.iconColor), + ), + ], + ), + + SizedBox(height: 16), + + Container( + height: 135.h, + width: Get.width, + decoration: BoxDecoration( + color: AppColor.bgLight, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + spacing: 10, + children: [ + SizedBox( + height: 100.h, + width: Get.width, + child: ListView.separated( + itemCount: 10, + padding: EdgeInsets.symmetric(horizontal: 12), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return Container( + width: 80.w, + height: 80.h, + decoration: BoxDecoration( + color: Color(0x33000000), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + "https://picsum.photos/150/150?random=$index", + ), + ), + borderRadius: BorderRadius.circular(8), + ), + child: Stack( + fit: StackFit.expand, + children: [ + Positioned( + top: 6, + left: 6, + child: Container( + width: 24.w, + height: 24.h, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.80), + borderRadius: BorderRadius.circular(4), + ), + child: Assets.vec.trashSvg.svg( + width: 16.w, + height: 16.h, + colorFilter: ColorFilter.mode( + AppColor.redNormal, + BlendMode.srcIn, + ), + ), + ), + ), + ], + ), + ); + }, + separatorBuilder: (context, index) => SizedBox(width: 10), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Row( + children: [ + Text( + '200 فارم در این سالن تخمین زده شده است.', + textAlign: TextAlign.right, + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.textColor, + ), + ), + ], + ), + ), + ], + ), + ), + + SizedBox(height: 16), + + Container( + height: 135.h, + width: Get.width, + decoration: BoxDecoration( + color: AppColor.bgLight, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + spacing: 10, + children: [ + SizedBox( + height: 100.h, + width: Get.width, + child: ListView.separated( + itemCount: 10, + padding: EdgeInsets.symmetric(horizontal: 12), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return Container( + width: 80.w, + height: 80.h, + decoration: BoxDecoration( + color: Color(0x33000000), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + "https://picsum.photos/150/150?random=${index * 2 + 1}", + ), + ), + + borderRadius: BorderRadius.circular(8), + ), + child: Stack( + fit: StackFit.expand, + children: [ + Positioned( + top: 6, + left: 6, + child: Container( + width: 24.w, + height: 24.h, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.80), + borderRadius: BorderRadius.circular(4), + ), + child: Assets.vec.trashSvg.svg( + width: 16.w, + height: 16.h, + colorFilter: ColorFilter.mode( + AppColor.redNormal, + BlendMode.srcIn, + ), + ), + ), + ), + ], + ), + ); + }, + separatorBuilder: (context, index) => SizedBox(width: 10), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Row( + children: [ + Text( + 'انبار نهاده ها', + textAlign: TextAlign.right, + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.textColor, + ), + ), + ], + ), + ), + ], + ), + ), + + SizedBox(height: 16), + + Container( + height: 135.h, + width: Get.width, + decoration: BoxDecoration( + color: AppColor.bgLight, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + spacing: 10, + children: [ + SizedBox( + height: 100.h, + width: Get.width, + child: ListView.separated( + itemCount: 10, + padding: EdgeInsets.symmetric(horizontal: 12), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + return Container( + width: 80.w, + height: 80.h, + decoration: BoxDecoration( + color: Color(0x33000000), + image: DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + "https://picsum.photos/150/150?random=${index * 3 + 1}", + ), + ), + + borderRadius: BorderRadius.circular(8), + ), + child: Stack( + fit: StackFit.expand, + children: [ + Positioned( + top: 6, + left: 6, + child: Container( + width: 24.w, + height: 24.h, + padding: EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.white.withValues(alpha: 0.80), + borderRadius: BorderRadius.circular(4), + ), + child: Assets.vec.trashSvg.svg( + width: 16.w, + height: 16.h, + colorFilter: ColorFilter.mode( + AppColor.redNormal, + BlendMode.srcIn, + ), + ), + ), + ), + ], + ), + ); + }, + separatorBuilder: (context, index) => SizedBox(width: 10), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 18), + child: Row( + children: [ + Text( + 'تلفات', + textAlign: TextAlign.right, + style: AppFonts.yekan14Bold.copyWith( + color: AppColor.textColor, + ), + ), + ], + ), + ), + ], + ), + ), + ], + ); +} diff --git a/packages/chicken/lib/presentation/routes/global_binding.dart b/packages/chicken/lib/presentation/routes/global_binding.dart index 8afbee3..992603f 100644 --- a/packages/chicken/lib/presentation/routes/global_binding.dart +++ b/packages/chicken/lib/presentation/routes/global_binding.dart @@ -1,10 +1,15 @@ import 'package:rasadyar_chicken/features/common/presentation/page/profile/logic.dart'; +import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart'; import 'package:rasadyar_core/core.dart'; class GlobalBinding extends Bindings { @override void dependencies() { - Get.lazyPut(() => BaseLogic(), fenix: true); + // Register ChickenBaseLogic and also as BasePageLogic/BaseLogic for compatibility + // Since ChickenBaseLogic extends BasePageLogic, we can use the same instance + Get.lazyPut(() => ChickenBaseLogic(), fenix: true); + // Register the same instance as BasePageLogic/BaseLogic + Get.lazyPut(() => Get.find(), fenix: true); Get.lazyPut(() => ProfileLogic(), fenix: true); //root logics