import 'dart:io'; import 'package:flutter/material.dart'; import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart'; import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.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'; import 'logic.dart'; class InspectionPoultrySciencePage extends GetView { const InspectionPoultrySciencePage({super.key}); @override Widget build(BuildContext context) { return ChickenBasePage( hasBack: true, hasFilter: true, hasSearch: true, onFilterTap: () { Get.bottomSheet(filterBottomSheet()); }, onRefresh: controller.onRefresh, onSearchChanged: (data) => controller.setSearchValue(data), backId: poultryFirstKey, routesWidget: ContainerBreadcrumb(rxRoutes: controller.routesName), child: Column( children: [ SizedBox(height: 50, child: segmentWidget()), ObxValue((data) { return data.value == 0 ? hatchingWidget() : reportWidget(); }, controller.selectedSegmentIndex), ], ), ); } Widget hatchingWidget() { return Expanded( child: ObxValue((data) { return RPaginatedListView( listType: ListType.separated, resource: data.value, hasMore: data.value.data?.next != null, padding: EdgeInsets.fromLTRB(8, 8, 8, 80), itemBuilder: (context, index) { var item = data.value.data!.results![index]; return ObxValue((val) { return ExpandableListItem2( selected: val.value.isEqual(index), onTap: () => controller.toggleExpanded(index), index: index, child: itemListWidget(item), secondChild: itemListExpandedWidget(item), labelColor: AppColor.blueLight, labelIcon: item.reportInfo?.image == false ? Assets.vec.timerSvg.path : Assets.vec.checkSquareSvg.path, labelIconColor: item.reportInfo?.image == false ? AppColor.yellowNormal2 : AppColor.mediumGreyDarkHover, ); }, controller.expandedIndex); }, itemCount: data.value.data?.results?.length ?? 0, separatorBuilder: (context, index) => SizedBox(height: 8.h), onLoadMore: () async => controller.getHatchingList(true), ); }, controller.hatchingList), ); } Container itemListExpandedWidget(HatchingModel item) { return Container( padding: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)), child: Column( spacing: 8, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Text( item.poultry?.user?.fullname ?? 'N/A', textAlign: TextAlign.center, style: AppFonts.yekan16.copyWith(color: AppColor.greenDark), ), Spacer(), Visibility( child: Text( item.violation == true ? 'پیگیری' : 'عادی', textAlign: TextAlign.center, style: AppFonts.yekan10.copyWith(color: AppColor.redDark), ), ), ], ), Container( height: 32, padding: EdgeInsets.symmetric(horizontal: 8), decoration: ShapeDecoration( color: AppColor.blueLight, shape: RoundedRectangleBorder( side: BorderSide(width: 1, color: AppColor.blueLightHover), borderRadius: BorderRadius.circular(8), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'نژاد:${item.breed?.first.breed ?? 'N/A'}', style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), Text( ' سن ${item.age} (روزه)', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), ), Text( ' دوره جوجه ریزی:${item.period}', style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), ], ), ), buildRow(title: 'شماره مجوز جوجه ریزی', value: item.licenceNumber ?? 'N/A'), buildUnitRow( title: 'حجم جوجه ریزی', value: item.quantity.separatedByCommaFa, unit: '(قطعه)', ), buildUnitRow( title: 'مانده در سالن', value: item.leftOver.separatedByCommaFa, unit: '(قطعه)', ), buildUnitRow(title: 'تلفات', value: item.losses.separatedByCommaFa, unit: '(قطعه)'), buildRow( title: 'دامپزشک فارم', value: '${item.vetFarm?.vetFarmFullName}(${item.vetFarm?.vetFarmMobile})', ), buildRow( title: 'شرح بازرسی', value: item.reportInfo?.image == false ? 'ارسال تصویر جوجه ریزی فارم ' : 'تکمیل شده', titleStyle: AppFonts.yekan14.copyWith( color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark, ), valueStyle: AppFonts.yekan14.copyWith( color: (item.reportInfo?.image ?? false) ? AppColor.greenNormal : AppColor.redDark, ), ), Visibility( visible: (item.reportInfo?.image == false), child: RElevated( text: 'ثبت بازرسی', isFullWidth: true, width: 150.w, height: 40.h, onPressed: () { cameraBottomSheet(item.id!); }, textStyle: AppFonts.yekan20.copyWith(color: Colors.white), backgroundColor: AppColor.greenNormal, ), ), ], ), ); } void cameraBottomSheet(int id) { Get.bottomSheet( isDismissible: false, isScrollControlled: false, BaseBottomSheet( height: 350.h, child: Column( children: [ ObxValue((data) { return GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, mainAxisSpacing: 8, crossAxisSpacing: 8, childAspectRatio: 1, ), shrinkWrap: true, itemCount: controller.pickedImages.length + 1, itemBuilder: (context, index) { if (index + 1 < 7 && index == data.length) { return GestureDetector( onTap: () async { await controller.pickImages(); }, child: Container( width: 80.h, height: 80.h, decoration: BoxDecoration( color: AppColor.lightGreyNormal, borderRadius: BorderRadius.circular(8.r), ), child: Center( child: Icon( Icons.add_a_photo, color: AppColor.lightGreyDarker, size: 32.h, ), ), ), ); } else { return Container( width: 80.h, height: 80.h, decoration: BoxDecoration( color: AppColor.lightGreyNormal, borderRadius: BorderRadius.circular(8.r), ), child: Stack( children: [ Positioned.fill( child: Image.file(File(data[index].path), fit: BoxFit.cover), ), Positioned( top: 4, left: 4, child: GestureDetector( onTap: () { controller.removeImage(index); }, child: Container( width: 24.w, height: 24.h, clipBehavior: Clip.antiAlias, padding: EdgeInsets.all(4), decoration: ShapeDecoration( color: Colors.white.withValues(alpha: 0.80), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(4), ), ), child: Assets.vec.trashSvg.svg( width: 8.w, height: 8.h, colorFilter: ColorFilter.mode( AppColor.redNormal, BlendMode.srcIn, ), ), ), ), ), ], ), ); } }, ); }, controller.pickedImages), SizedBox(height: 35.h), Text( 'حداقل ۲ تصویر برای ثبت بازرسی لازم است', style: AppFonts.yekan12.copyWith(color: AppColor.textColor), ), SizedBox(height: 8.h), Row( spacing: 16, mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() { return RElevated( height: 40.h, text: 'ارسال', backgroundColor: AppColor.greenNormal, progress: controller.presentUpload.value, isLoading: controller.isOnUpload.value, enabled: controller.pickedImages.length >= 2, onPressed: () async { controller.submitInspectionReport(id: id); }, ); }), ObxValue((data) { return RElevated( height: 40.h, text: 'انصراف', backgroundColor: AppColor.redNormal, enabled: !data.value, onPressed: () { if (!data.value) { controller.clearImages(); Get.back(); } }, ); }, controller.isOnUpload), ], ), SizedBox(height: 8.h), ], ), ), ).whenComplete(() { controller.pickedImages.clear(); }); } Padding segmentWidget() { return Padding( padding: const EdgeInsets.fromLTRB(8, 0, 8, 8), child: Row( children: [ Expanded( child: RSegment( children: ['بازرسی', 'بایگانی'], selectedIndex: 0, borderColor: const Color(0xFFB4B4B4), selectedBorderColor: AppColor.blueNormal, selectedBackgroundColor: AppColor.blueLight, onSegmentSelected: (index) => controller.selectedSegmentIndex.value = index, backgroundColor: AppColor.whiteGreyNormal, ), ), ], ), ); } Widget reportWidget() { return Expanded( child: ObxValue((data) { return RPaginatedListView( listType: ListType.separated, resource: data.value, hasMore: data.value.data?.next != null, padding: EdgeInsets.fromLTRB(8, 8, 8, 80), itemBuilder: (context, index) { var item = data.value.data!.results![index]; return ObxValue((val) { return ExpandableListItem2( selected: val.value.isEqual(index), onTap: () => controller.toggleExpanded(index), index: index, child: itemListWidgetReport(item), secondChild: itemListExpandedWidgetReport(item), labelColor: item.state == 'rejected' ? AppColor.redLight : AppColor.greenLight, labelIcon: Assets.vec.cubeSearchSvg.path, ); }, controller.expandedIndex); }, itemCount: data.value.data?.results?.length ?? 0, separatorBuilder: (context, index) => SizedBox(height: 8.h), onLoadMore: () async => controller.getHatchingReport(true), ); }, controller.hatchingReportList), ); } Widget itemListExpandedWidgetReport(HatchingReport item) { return Container( padding: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)), child: Column( spacing: 8, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Text( item.hatching?.poultry?.user?.fullname ?? 'N/A', textAlign: TextAlign.center, style: AppFonts.yekan16.copyWith(color: AppColor.greenDark), ), Spacer(), Visibility( child: Text( item.hatching?.violation == true ? 'پیگیری' : 'عادی', textAlign: TextAlign.center, style: AppFonts.yekan10.copyWith(color: AppColor.redDark), ), ), ], ), Container( height: 32, padding: EdgeInsets.symmetric(horizontal: 8), decoration: ShapeDecoration( color: AppColor.blueLight, shape: RoundedRectangleBorder( side: BorderSide(width: 1, color: AppColor.blueLightHover), borderRadius: BorderRadius.circular(8), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( spacing: 3, children: [ Text('نژاد:', style: AppFonts.yekan14.copyWith(color: AppColor.textColor)), Text( item.hatching?.chickenBreed ?? 'N/A', style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), ], ), Text( ' سن ${item.hatching?.chickenAge} (روزه)', style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal), ), Text( ' دوره جوجه ریزی:${item.hatching?.period}', style: AppFonts.yekan14.copyWith(color: AppColor.textColor), ), ], ), ), buildRow(title: 'شماره مجوز جوجه ریزی', value: item.hatching?.licenceNumber ?? 'N/A'), buildUnitRow( title: 'حجم جوجه ریزی', value: item.hatching?.quantity.separatedByCommaFa ?? 'N/A', unit: '(قطعه)', ), buildUnitRow( title: 'مانده در سالن', value: item.hatching?.leftOver.separatedByCommaFa ?? 'N/A', unit: '(قطعه)', ), buildUnitRow( title: 'تلفات', value: item.hatching?.losses.separatedByCommaFa ?? 'N/A', unit: '(قطعه)', ), buildRow( title: 'دامپزشک فارم', value: '${item.hatching?.vetFarm?.vetFarmFullName}(${item.hatching?.vetFarm?.vetFarmMobile})', ), buildRow( title: 'شرح بازرسی', value: controller.getStatus(item), titleStyle: AppFonts.yekan14.copyWith(color: controller.getStatusColor(item)), valueStyle: AppFonts.yekan14.copyWith(color: controller.getStatusColor(item)), ), if (item.state == 'accepted') ...{ Visibility( visible: item.realQuantityAi != null, child: buildRow( title: 'تعداد تاییده هوش مصنوعی', value: item.realQuantityAi.separatedByComma, ), ), Visibility( visible: item.realQuantity != null, child: buildRow( title: 'تعداد تاییده', value: item.realQuantity.separatedByComma, ), ), }, if (item.state == 'rejected') ...{ Visibility( visible: item.messageAi != null, child: buildRow(title: 'پیام هوش مصنوعی', value: item.messageAi ?? '-'), ), Visibility( visible: item.message != null, child: buildRow(title: 'پیام', value: item.message ?? '-'), ), Visibility( visible: item.messageRegistererFullname != null, child: buildRow( title: 'ثبت کننده گزارش', value: item.messageRegistererFullname ?? '-', ), ), Visibility( visible: item.messageRegistererMobile != null, child: buildRow( title: 'موبایل کننده گزارش', value: item.messageRegistererMobile ?? '-', ), ), Visibility( visible: item.messageRegistererRole != null, child: buildRow(title: 'نقش کننده گزارش', value: item.messageRegistererRole ?? '-'), ), }, SizedBox( height: 140.h, child: GridView.builder( shrinkWrap: true, itemCount: item.image?.length ?? 0, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 10, crossAxisSpacing: 10, ), itemBuilder: (context, index) => Container( height: 100.h, clipBehavior: Clip.hardEdge, child: Image.network( item.image?[index] ?? '', loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Padding( padding: EdgeInsetsGeometry.all(80), child: CircularProgressIndicator( color: AppColor.blueDark, value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / (loadingProgress.expectedTotalBytes ?? 1) : null, ), ); }, ), decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.r)), ), ), ), ], ), ); } Widget itemListWidget(HatchingModel item) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ SizedBox(width: 20), Expanded( flex: 2, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, spacing: 5, children: [ Text( item.poultry?.user?.fullname ?? 'N/A', textAlign: TextAlign.start, style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal), ), Text( item.poultry?.user?.mobile ?? 'N/A', textAlign: TextAlign.center, style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), ), ], ), ), Expanded( flex: 3, child: Column( spacing: 5, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( item.poultry?.unitName ?? 'N/Aaq', textAlign: TextAlign.start, style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal), ), Text( item.poultry?.licenceNumber ?? 'N/A', textAlign: TextAlign.left, style: AppFonts.yekan12.copyWith(color: AppColor.bgDark), ), ], ), ), Expanded( flex: 1, child: Assets.vec.scanSvg.svg( width: 32.w, height: 32.h, colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), ), ), ], ); } Row itemListWidgetReport(HatchingReport item) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ SizedBox(width: 20), Expanded( flex: 2, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, spacing: 5, children: [ Text( item.hatching?.poultry?.user?.fullname ?? 'N/A', textAlign: TextAlign.start, style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal), ), Text( item.hatching?.poultry?.user?.mobile ?? 'N/A', textAlign: TextAlign.center, style: AppFonts.yekan14.copyWith(color: AppColor.bgDark), ), ], ), ), Expanded( flex: 3, child: Column( spacing: 5, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( item.hatching?.poultry?.unitName ?? 'N/Aaq', textAlign: TextAlign.start, style: AppFonts.yekan12.copyWith(color: AppColor.blueNormal), ), Text( item.hatching?.licenceNumber ?? 'N/A', textAlign: TextAlign.left, style: AppFonts.yekan12.copyWith(color: AppColor.bgDark), ), ], ), ), Expanded( flex: 1, child: Assets.vec.scanSvg.svg( width: 32.w, height: 32.h, colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn), ), ), ], ); } Widget filterBottomSheet() { return BaseBottomSheet( height: 200, child: Column( spacing: 16, children: [ Text('فیلترها', style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal)), Row( spacing: 8, children: [ Expanded( child: dateFilterWidget( date: controller.fromDateFilter, onChanged: (jalali) => controller.fromDateFilter.value = jalali, ), ), Expanded( child: dateFilterWidget( isFrom: false, date: controller.toDateFilter, onChanged: (jalali) => controller.toDateFilter.value = jalali, ), ), ], ), RElevated( text: 'اعمال فیلتر', isFullWidth: true, backgroundColor: AppColor.greenNormal, onPressed: () { final isReporter = controller.selectedSegmentIndex.value == 0; if (isReporter) { controller.getHatchingReport(); } else { controller.getHatchingList(); } Get.back(); }, height: 40, ), ], ), ); } }