feat : new ui

This commit is contained in:
2025-09-21 14:32:58 +03:30
parent bbd572c579
commit 50d708469c
23 changed files with 872 additions and 502 deletions

View File

@@ -100,4 +100,33 @@ class GenocideLogic extends GetxController {
void toggleExpanded(int index) {
expandedIndex.value = expandedIndex.value == index ? -1 : index;
}
String getRequestType(PoultryOrder item) {
if (item.market ?? false) {
return 'پنل معاملات';
} else if (item.union ?? false) {
return 'اتحادیه';
} else {
return 'خرید مستقیم';
}
}
String getKillType(PoultryOrder item) {
if (item.export ?? false) {
return 'صادرات';
} else if (item.freezing ?? false) {
return 'انجماد';
} else {
return 'عادی';
}
}
String getState(PoultryOrder item) {
if (item.stateProcess == 'pending') {
return 'در انتظار تایید';
} else {
return 'تایید شده';
}
}
}

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_order/poultry_order.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/pages/poultry_science/killing_registration/view.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/filter_bottom_sheet.dart';
@@ -23,48 +23,59 @@ class GenocidePage extends GetView<GenocideLogic> {
},
filteringWidget: filterBottomSheet(),
onBackPressed: () => Get.back(id: poultryFirstKey),
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
floatingActionButton: RFab.add(
onPressed: () {
Get.toNamed(ChickenRoutes.killingRegistrationPoultryScience, id: poultryFirstKey);
},
child: Stack(
fit: StackFit.expand,
children: [
Positioned.fill(child: poultryOrderListWidget()),
Positioned(
bottom: 130,
right: 16,
child: RFab.add(
onPressed: () {
Get.bottomSheet(
isScrollControlled: true,
backgroundColor: Colors.transparent,
killRegistrationBottomSheet(),
);
},
),
),
],
),
widgets: [poultryOrderListWidget()],
);
}
//region List and Items
Widget poultryOrderListWidget() {
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: Assets.vec.cubeScanSvg.path,
);
}, controller.expandedIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getPoultryOrderList(true),
onRefresh: () async {
controller.currentPage.value = 1;
await controller.getPoultryOrderList();
},
);
}, controller.poultryOrderList),
);
return 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: Assets.vec.cubeScanSvg.path,
);
}, controller.expandedIndex);
},
itemCount: data.value.data?.results?.length ?? 0,
separatorBuilder: (context, index) => SizedBox(height: 8.h),
onLoadMore: () async => controller.getPoultryOrderList(true),
onRefresh: () async {
controller.currentPage.value = 1;
await controller.getPoultryOrderList();
},
);
}, controller.poultryOrderList);
}
Container itemListExpandedWidget(PoultryOrder item) {
@@ -129,8 +140,8 @@ class GenocidePage extends GetView<GenocideLogic> {
title: 'نوع فروش',
value: (item.freeSaleInProvince ?? false) ? 'آزاد' : 'دولتی ',
),
buildRow(title: 'نوع کشتار ', value: getKillType(item)),
buildRow(title: 'درخواست', value: getRequestType(item) ?? 'N/A'),
buildRow(title: 'نوع کشتار ', value: controller.getKillType(item)),
buildRow(title: 'درخواست', value: controller.getRequestType(item) ?? 'N/A'),
buildRow(title: 'میانگین وزنی', value: '${(item.indexWeight)} (کیلوگرم)'),
buildRow(title: 'قیمت مرغدار', value: '${item.amount.separatedByComma} (ریال)'),
@@ -138,7 +149,7 @@ class GenocidePage extends GetView<GenocideLogic> {
title: 'مانده در سالن ',
value: '${item.hatching?.leftOver.separatedByComma ?? 0} (قطعه)',
),
buildRow(title: ' وضعیت', value: getState(item)),
buildRow(title: ' وضعیت', value: controller.getState(item)),
Visibility(
visible: item.stateProcess == 'pending',
@@ -159,13 +170,12 @@ class GenocidePage extends GetView<GenocideLogic> {
onPressed: data.value
? null
: () => _buildDeleteDialog(
onConfirm: () async {
Get.back();
await controller.deletePoultryOrder(item.id!);
controller.getPoultryOrderList();
},
),
onConfirm: () async {
Get.back();
await controller.deletePoultryOrder(item.id!);
controller.getPoultryOrderList();
},
),
);
}, controller.isLoadingDelete),
),
@@ -231,34 +241,9 @@ class GenocidePage extends GetView<GenocideLogic> {
);
}
String getRequestType(PoultryOrder item) {
if (item.market ?? false) {
return 'پنل معاملات';
} else if (item.union ?? false) {
return 'اتحادیه';
} else {
return 'خرید مستقیم';
}
}
String getKillType(PoultryOrder item) {
if (item.export ?? false) {
return 'صادرات';
} else if (item.freezing ?? false) {
return 'انجماد';
} else {
return 'عادی';
}
}
String getState(PoultryOrder item) {
if (item.stateProcess == 'pending') {
return 'در انتظار تایید';
} else {
return 'تایید شده';
}
}
//endregion
//region other widgets
void _buildDeleteDialog({required VoidCallback onConfirm}) {
Get.defaultDialog(
title: 'حذف درخواست کشتار',
@@ -280,7 +265,6 @@ class GenocidePage extends GetView<GenocideLogic> {
);
}
Widget filterBottomSheet() => filterBottomSheetWidget(
fromDate: controller.fromDateFilter,
onChangedFromDate: (jalali) => controller.fromDateFilter.value = jalali,
@@ -289,4 +273,16 @@ class GenocidePage extends GetView<GenocideLogic> {
onSubmit: () => controller.getPoultryOrderList(),
);
//endregion
//region kill registration bottom sheet
Widget killRegistrationBottomSheet() {
return BaseBottomSheet(
height: Get.height * 0.9,
bgColor: Color(0x66E4E4E4),
child: KillingRegistrationPage(),
);
}
//endregion
}

View File

@@ -4,8 +4,6 @@ import 'package:rasadyar_chicken/data/models/response/all_poultry/all_poultry.da
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_request_poultry.dart';
import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.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';
@@ -15,12 +13,8 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
@override
Widget build(BuildContext context) {
return BasePageWithScroll(
hasSearch: false,
hasFilter: false,
routes: controller.routes,
onBackPressed: () => Get.back(id: poultryFirstKey),
widgets: [
return Column(
children: [
poultryFarmWidget(),
poultryUserListWidget(),
poultryHatchingWidget(),
@@ -38,7 +32,6 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
controller.killsDate.value = jalali;
},
),
loseWidget(),
quantityKillsWidget(),
averageWeightKillsWidget(),
saleTypeWidget(),
@@ -55,57 +48,9 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
);
}
Widget informationWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
child: ObxValue(
(data) => Column(
spacing: 8,
children: [
buildUnitRow(
title: 'تعداد جوجه ریزی',
value: data.value?.quantity.separatedByCommaFa,
unit: 'قطعه',
),
buildUnitRow(
title: 'جمع تلفات ثبت شده دامپزشک و مرغدار',
value: data.value?.losses.separatedByCommaFa,
unit: 'قطعه',
),
buildUnitRow(
title: 'باقیمانده',
value: data.value?.leftOver.separatedByCommaFa,
unit: 'قطعه',
),
buildUnitRow(
title: 'سن مرغ',
value: data.value?.chickenAge.separatedByCommaFa,
unit: 'روز',
),
buildUnitRow(
title: 'مجوز فروش آزاد',
value: data.value?.freeGovernmentalInfo?.totalFreeCommitmentQuantity.separatedByCommaFa,
unit: 'قطعه',
),
buildUnitRow(
title: 'مانده فروش آزاد',
value: data
.value
?.freeGovernmentalInfo
?.leftTotalFreeCommitmentQuantity
.separatedByCommaFa,
unit: 'قطعه',
),
],
),
controller.selectedPoultryHatching,
),
);
}
Widget poultryFarmWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 10.h),
child: ObxValue((data) {
return ResourceOverlayDropdown<AllPoultry>(
items: data.value,
@@ -116,67 +61,203 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
controller.getUserPoultryList();
},
selectedItem: controller.selectedPoultry.value,
itemBuilder: (item) => Text(labelPoultry(item), maxLines: 2),
labelBuilder: (item) => Text(labelPoultry(item)),
itemBuilder: (item) => labelPoultryWidget(item),
labelBuilder: (item) => labelPoultryWidget(item),
);
}, controller.allPoultryList),
);
}
String labelPoultry(AllPoultry? item) {
Widget labelPoultryWidget(AllPoultry? item) {
if (item == null) {
return 'انتخاب مرغداری';
return Row(
children: [
Assets.vec.farmSvg.svg(
width: 28.w,
height: 28.h,
colorFilter: const ColorFilter.mode(AppColor.darkGreyDark, BlendMode.srcIn),
),
SizedBox(width: 4.w),
Text('انتخاب مرغداری', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)),
],
);
} else {
return '${item.unitName} (${item.address?.city?.name}) / ${item.user?.fullname} (${item.user?.mobile}) / ${item.lastHatchingRemainQuantity} قطعه ';
return Text(
'${item.unitName} (${item.address?.city?.name})',
maxLines: 2,
);
}
}
Widget poultryUserListWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: ObxValue((data) {
return ResourceOverlayDropdown<KillRequestPoultry>(
items: data.value,
background: Colors.white,
onChanged: (value) {
controller.clearSelectedStep2();
controller.selectedKillRequestPoultry.value = value;
controller.getPoultryHatchingList();
},
selectedItem: controller.selectedKillRequestPoultry.value,
itemBuilder: (item) => Text(item.unitName ?? '-'),
labelBuilder: (item) => Text(item?.unitName ?? 'محل پرورش'),
);
}, controller.poultryList),
);
return ObxValue((data) {
if (data.value == null) {
return SizedBox.shrink();
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: ObxValue((data) {
return ResourceOverlayDropdown<KillRequestPoultry>(
items: data.value,
background: Colors.white,
onChanged: (value) {
controller.clearSelectedStep2();
controller.selectedKillRequestPoultry.value = value;
controller.getPoultryHatchingList();
},
selectedItem: controller.selectedKillRequestPoultry.value,
itemBuilder: (item) => labelPoultryUser(item),
labelBuilder: (item) => labelPoultryUser(item),
);
}, controller.poultryList),
);
}, controller.selectedPoultry);
}
Widget labelPoultryUser(KillRequestPoultry? item) {
if (item == null) {
return Row(
children: [
Assets.vec.chickenHouseSvg.svg(
width: 28.w,
height: 28.h,
colorFilter: const ColorFilter.mode(AppColor.darkGreyDark, BlendMode.srcIn),
),
SizedBox(width: 6.w),
Text('محل پرورش', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)),
],
);
} else {
return Text(item.unitName ?? '-');
}
}
Widget poultryHatchingWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
child: ObxValue((data) {
return ResourceOverlayDropdown<PoultryHatching>(
items: data.value,
background: Colors.white,
onChanged: (value) {
controller.selectedPoultryHatching.value = value;
},
selectedItem: controller.selectedPoultryHatching.value,
itemBuilder: (item) => Text(labelPoultryHatching(item)),
labelBuilder: (item) => Text(labelPoultryHatching(item)),
);
}, controller.poultryHatchingList),
);
return ObxValue((data) {
if (data.value == null) {
return SizedBox.shrink();
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 10.h),
child: ObxValue((data) {
return ResourceOverlayDropdown<PoultryHatching>(
items: data.value,
background: Colors.white,
onChanged: (value) {
controller.selectedPoultryHatching.value = value;
},
selectedItem: controller.selectedPoultryHatching.value,
itemBuilder: (item) => labelPoultryHatching(item),
labelBuilder: (item) => labelPoultryHatching(item),
);
}, controller.poultryHatchingList),
);
}, controller.selectedKillRequestPoultry);
}
String labelPoultryHatching(PoultryHatching? item) {
Widget labelPoultryHatching(PoultryHatching? item) {
if (item == null) {
return 'دوره جوجه ریزی';
return Row(
children: [
Assets.vec.calendarSvg.svg(
width: 28.w,
height: 28.h,
colorFilter: const ColorFilter.mode(AppColor.darkGreyDark, BlendMode.srcIn),
),
SizedBox(width: 6.w),
Text('دوره جوجه ریزی', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)),
],
);
} else {
return ' دوره ${item.period} سالن ${item.hall} نژاد ${item.chickenBreed} باقیمانده ${item.leftOver} قطعه ';
return Text(
' دوره ${item.period} سالن ${item.hall} نژاد ${item.chickenBreed} باقیمانده ${item.leftOver} قطعه ',
);
}
}
Widget informationWidget() {
return Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
margin: EdgeInsets.fromLTRB(8.w, 0, 8.w, 10.h),
padding: EdgeInsets.all(7),
child: ObxValue(
(data) => Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text(
'اطلاعات مرغداری',
textAlign: TextAlign.right,
style: AppFonts.yekan14Bold.copyWith(color: AppColor.blueNormal),
),
),
Container(
decoration: ShapeDecoration(
color: const Color(0xFFEAEFFF),
shape: RoundedRectangleBorder(
side: BorderSide(width: 1, color: const Color(0xFFE0E7FF)),
borderRadius: BorderRadius.circular(8),
),
),
padding: EdgeInsets.all(4),
child: buildUnitRow(
title: 'تعداد جوجه ریزی',
value: data.value?.quantity.separatedByCommaFa,
unit: 'قطعه',
),
),
buildUnitRow(
title: 'جمع تلفات ثبت شده دامپزشک و مرغدار',
value: data.value?.losses.separatedByCommaFa,
unit: 'قطعه',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
buildUnitRow(
title: 'باقیمانده',
value: data.value?.leftOver.separatedByCommaFa,
unit: 'قطعه',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
buildUnitRow(
title: 'سن مرغ',
value: data.value?.chickenAge.separatedByCommaFa,
unit: 'روز',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
buildUnitRow(
title: 'مجوز فروش آزاد',
value:
data.value?.freeGovernmentalInfo?.totalFreeCommitmentQuantity.separatedByCommaFa,
unit: 'قطعه',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
buildUnitRow(
title: 'مانده فروش آزاد',
value: data
.value
?.freeGovernmentalInfo
?.leftTotalFreeCommitmentQuantity
.separatedByCommaFa,
unit: 'قطعه',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
buildUnitRow(
title: 'تلفن مرغدار',
value: data.value?.poultry?.userprofile?.mobile,
unit: '',
padding: EdgeInsetsGeometry.symmetric(horizontal: 4),
),
],
),
controller.selectedPoultryHatching,
),
);
}
Widget killDateWidget({required Rx<Jalali> date, required Function(Jalali jalali) onChanged}) {
return GestureDetector(
onTap: () {
@@ -184,7 +265,7 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
},
child: Container(
height: 40,
margin: EdgeInsets.symmetric(horizontal: 20.w),
margin: EdgeInsets.symmetric(horizontal: 8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
@@ -214,22 +295,9 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
);
}
Widget loseWidget() {
return Padding(
padding: EdgeInsets.fromLTRB(20.w, 10.h, 20.w, 0),
child: RTextField(
label: 'تعداد تلفات (قطعه)',
filled: true,
filledColor: Colors.white,
keyboardType: TextInputType.number,
controller: controller.quantityLoseController,
),
);
}
Widget quantityKillsWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 10.h),
child: RTextField(
label: 'تعداد کشتار (قطعه)',
filled: true,
@@ -266,7 +334,7 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
Widget averageWeightKillsWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w),
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: RTextField(
label: 'میانگین وزن (کیلوگرم)',
filled: true,
@@ -299,30 +367,35 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
}
Widget saleTypeWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
return Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
margin: EdgeInsets.symmetric(horizontal: 8.w, vertical: 10.h),
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.h),
child: ObxValue((data) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [
CustomChip(
title: 'فروش دولتی',
index: 0,
onTap: (int p1) {
controller.changeSaleType();
},
isSelected: !(data.value),
Text(
'نوع فروش',
textAlign: TextAlign.center,
style: AppFonts.yekan14Bold.copyWith(color: AppColor.blueNormal),
),
CustomChip(
title: 'فروش آزاد',
index: 1,
onTap: (int p1) {
RadioGroup(
groupValue: data.value ? 1 : 0,
onChanged: (value) {
controller.changeSaleType();
},
isSelected: data.value,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Radio(value: 0, activeColor: AppColor.blueNormal),
Text('دولتی', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)),
Spacer(),
Radio(value: 1, activeColor: AppColor.blueNormal),
Text('آزاد', style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark)),
],
),
),
],
);
@@ -331,36 +404,36 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
}
Widget priceWidget() {
return ObxValue((data){
if(!data.value){
return ObxValue((data) {
if (!data.value) {
return Container(
height: 40.h,
margin: EdgeInsets.symmetric(horizontal: 20.w),
margin: EdgeInsets.symmetric(horizontal: 8.w),
decoration: BoxDecoration(
color: Colors.white,
color: AppColor.greenLight,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1.w, color: AppColor.darkGreyLight),
border: Border.all(width: 1.w, color: AppColor.whiteNormalHover),
),
padding: EdgeInsets.symmetric(horizontal: 11.w, vertical: 4.h),
child: Row(
spacing: 8,
children: [
Text('قیمت مصوب', style: AppFonts.yekan14.copyWith(color: AppColor.bgDark)),
Text('قیمت مصوب', style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
Spacer(),
ObxValue((data) {
return Text(
' ${data.value.separatedByCommaFa} ریال',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.darkGreyDark),
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
);
}, controller.generatedApprovedPrice),
],
),
);
}else{
} else {
return Padding(
padding: EdgeInsets.fromLTRB(20.w, 10.h, 20.w, 0),
padding: EdgeInsets.fromLTRB(8.w, 0, 8.w, 0),
child: RTextField(
label: 'قیمت پیشنهادی (ریال)',
validator: (value) {
@@ -368,29 +441,27 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
return 'قیمت پیشنهادی را وارد کنید';
}
final price = double.tryParse(value.replaceAll(',', ''));
dLog(controller.priceFreeSaleController.text);
fLog(value);
if (price == null || price <= 0) {
return 'قیمت پیشنهادی باید عددی بزرگتر از صفر باشد';
}
return null;
},
filled: true,
filledColor: Colors.white,
borderColor: AppColor.whiteNormalHover,
filledColor: AppColor.accent1,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly, SeparatorInputFormatter()],
controller: controller.priceFreeSaleController,
),
);
}
}, controller.isFreeSale);
}
Widget buyerListWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w),
child: ObxValue((data) {
return Visibility(
visible: data.value?.provinceAllowChooseKillHouse?.allowState ?? false,
@@ -420,56 +491,62 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
}
Widget slaughterhouseSelectedWidget() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Wrap(
spacing: 10,
runSpacing: 10,
return Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
margin: EdgeInsets.symmetric(horizontal: 8.w),
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ObxValue((data) {
return Visibility(
visible: data.value?.permission ?? false,
child: ObxValue(
(data) => CheckBoxChips(
title: 'کشتار برای انجماد',
data: data.value,
onTap: (p1) {
controller.isFreezedSelected.value = !controller.isFreezedSelected.value;
},
isSelected: data.value,
),
controller.isFreezedSelected,
),
);
}, controller.sellForFreezing),
SizedBox(height: 8.h),
Text('عملیات کشتار', style: AppFonts.yekan14Bold.copyWith(color: AppColor.blueNormal)),
SizedBox(height: 8.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ObxValue((data) {
return Visibility(
visible: data.value?.permission ?? false,
child: ObxValue(
(data) => TitleCheckBox(
title: ' انجماد',
onChanged: (_) {
controller.isFreezedSelected.value = !controller.isFreezedSelected.value;
},
isSelected: data.value,
),
controller.isFreezedSelected,
),
);
}, controller.sellForFreezing),
ObxValue((data) {
return CheckBoxChips(
title: 'نمایش در پنل معاملات',
data: 0,
onTap: (int p1) {
controller.isMarketSelected.value = !controller.isMarketSelected.value;
},
isSelected: data.value,
);
}, controller.isMarketSelected),
ObxValue((data) {
return Visibility(
visible: data.value?.allow ?? false,
child: ObxValue((data) {
return CheckBoxChips(
title: 'کشتار برای صادرات',
data: data.value,
onTap: (_) {
controller.isExportSelected.value = !controller.isExportSelected.value;
ObxValue((data) {
return TitleCheckBox(
title: 'پنل معاملات',
onChanged: (_) {
controller.isMarketSelected.value = !controller.isMarketSelected.value;
},
isSelected: data.value,
);
}, controller.isExportSelected),
);
}, controller.poultryExport),
}, controller.isMarketSelected),
ObxValue((data) {
return Visibility(
visible: data.value?.allow ?? false,
child: ObxValue((data) {
return TitleCheckBox(
title: 'صادرات',
isSelected: data.value,
onChanged: (_) {
controller.isExportSelected.value = !controller.isExportSelected.value;
},
);
}, controller.isExportSelected),
);
}, controller.poultryExport),
],
),
SizedBox(height: 8.h),
],
),
);
@@ -478,11 +555,12 @@ class KillingRegistrationPage extends GetView<KillingRegistrationLogic> {
Widget submitButtonWidget() {
return ObxValue((data) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 20.h),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 12.h),
child: RElevated(
enabled: data.value,
height: 45.h,
isFullWidth: true,
disabledBackgroundColor: AppColor.greenDarkHover,
backgroundColor: AppColor.greenNormal,
textStyle: AppFonts.yekan16Bold.copyWith(color: Colors.white),
onPressed: () {

View File

@@ -11,56 +11,42 @@ class PoultryActionPage extends GetView<PoultryActionLogic> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: chickenAppBar(
hasBack: false,
hasFilter: false,
hasSearch: false,
isBase: false,
),
body: Column(
children: [
bannerWidget(),
itemGridWidget(),
],
appBar: chickenAppBar(hasBack: false, hasFilter: false, hasSearch: false, isBase: false),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(Assets.images.bgChickenPattern.path),
fit: BoxFit.cover,
),
),
child: gridWidget(),
),
);
}
Image bannerWidget() {
return Assets.images.poultryAction.image(
height: 212.h,
width: Get.width.w,
fit: BoxFit.cover,
);
}
Widget itemGridWidget() {
Widget gridWidget() {
return ObxValue((data) {
return Expanded(
child: GridView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 31.w),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 24.h,
crossAxisSpacing: 24.w,
),
itemCount: data.length,
hitTestBehavior: HitTestBehavior.opaque,
itemBuilder: (BuildContext context, int index) {
var item = data[index];
return CardIcon(
title: item.title,
vecIcon: item.icon,
iconColor: AppColor.blueNormal,
onTap: () async {
Get.toNamed(item.route, id: poultryFirstKey);
},
);
},
),
return GridView.builder(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 16.h,
crossAxisSpacing: 16.w,
),
itemCount: data.length,
hitTestBehavior: HitTestBehavior.opaque,
itemBuilder: (BuildContext context, int index) {
var item = data[index];
return GlassMorphismCardIcon(
title: item.title,
vecIcon: item.icon,
onTap: () async {
Get.toNamed(item.route, id: poultryFirstKey);
},
);
}, controller.items);
},
);
}, controller.items);
}
}

View File

@@ -42,65 +42,83 @@ class PoultryScienceRootPage extends GetView<PoultryScienceRootLogic> {
},
child: Scaffold(
backgroundColor: AppColor.bgLight,
body: IndexedStack(
body: Stack(
children: [
Navigator(
key: Get.nestedKey(poultryFirstKey),
onGenerateRoute: (settings) {
final page = ChickenPages.pages.firstWhere(
(e) => e.name == settings.name,
orElse: () => ChickenPages.pages.firstWhere(
(e) => e.name == ChickenRoutes.actionPoultryScience,
IndexedStack(
children: [
Navigator(
key: Get.nestedKey(poultryFirstKey),
onGenerateRoute: (settings) {
final page = ChickenPages.pages.firstWhere(
(e) => e.name == settings.name,
orElse: () => ChickenPages.pages.firstWhere(
(e) => e.name == ChickenRoutes.actionPoultryScience,
),
);
return buildRouteFromGetPage(page);
},
),
Navigator(
key: Get.nestedKey(poultrySecondKey),
onGenerateRoute: (settings) => GetPageRoute(page: () => controller.pages[1]),
),
Navigator(
key: Get.nestedKey(poultryThirdKey),
onGenerateRoute: (settings) => GetPageRoute(page: () => controller.pages[2]),
),
],
index: data.value,
),
Positioned(
right: 0,
left: 0,
bottom: 0,
child: RBottomNavigation(
mainAxisAlignment: MainAxisAlignment.spaceAround,
items: [
RBottomNavigationItem(
label: 'اقدام',
icon: Assets.vec.settingSvg.path,
isSelected: controller.currentPage.value == 0,
onTap: () {
Get.nestedKey(
poultrySecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(0);
},
),
);
return buildRouteFromGetPage(page);
},
),
Navigator(
key: Get.nestedKey(poultrySecondKey),
onGenerateRoute: (settings) => GetPageRoute(page: () => controller.pages[1]),
),
Navigator(
key: Get.nestedKey(poultryThirdKey),
onGenerateRoute: (settings) => GetPageRoute(page: () => controller.pages[2]),
),
],
index: data.value,
),
bottomNavigationBar: RBottomNavigation(
mainAxisAlignment: MainAxisAlignment.spaceAround,
items: [
RBottomNavigationItem(
label: 'اقدام',
icon: Assets.vec.settingSvg.path,
isSelected: controller.currentPage.value == 0,
onTap: () {
Get.nestedKey(poultrySecondKey)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(0);
},
),
RBottomNavigationItem(
label: 'خانه',
icon: Assets.vec.homeSvg.path,
isSelected: controller.currentPage.value == 1,
onTap: () {
Get.nestedKey(poultryFirstKey)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(poultryThirdKey)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(1);
},
),
RBottomNavigationItem(
label: 'پروفایل',
icon: Assets.vec.profileCircleSvg.path,
isSelected: controller.currentPage.value == 2,
onTap: () {
Get.nestedKey(poultryFirstKey)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(poultrySecondKey)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(2);
},
RBottomNavigationItem(
label: 'خانه',
icon: Assets.vec.homeSvg.path,
isSelected: controller.currentPage.value == 1,
onTap: () {
Get.nestedKey(
poultryFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
poultryThirdKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(1);
},
),
RBottomNavigationItem(
label: 'پروفایل',
icon: Assets.vec.profileCircleSvg.path,
isSelected: controller.currentPage.value == 2,
onTap: () {
Get.nestedKey(
poultryFirstKey,
)?.currentState?.popUntil((route) => route.isFirst);
Get.nestedKey(
poultrySecondKey,
)?.currentState?.popUntil((route) => route.isFirst);
controller.changePage(2);
},
),
],
),
),
],
),

View File

@@ -216,6 +216,7 @@ sealed class ChickenPages {
binding: BindingsBuilder(() {
Get.lazyPut(() => GenocideLogic());
Get.lazyPut(() => PoultryScienceRootLogic());
Get.put( KillingRegistrationLogic());
}),
),
GetPage(

View File

@@ -10,11 +10,12 @@ class BasePage extends StatefulWidget {
const BasePage({
super.key,
this.routes,
required this.widgets,
this.widgets,
this.routesWidget,
this.floatingActionButtonLocation,
this.floatingActionButton,
this.onSearchChanged,
this.child,
this.hasBack = true,
this.hasFilter = true,
this.hasSearch = true,
@@ -30,7 +31,8 @@ class BasePage extends StatefulWidget {
final List<String>? routes;
final Widget? routesWidget;
final List<Widget> widgets;
final List<Widget>? widgets;
final Widget? child;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final Widget? floatingActionButton;
final Widget? filteringWidget;
@@ -135,7 +137,9 @@ class _BasePageState extends State<BasePage> {
if (!widget.isBase && widget.hasSearch) ...{
SearchWidget(onSearchChanged: widget.onSearchChanged),
},
...widget.widgets,
if (widget.child != null) ...{Expanded(child: widget.child!)},
...?widget.widgets,
],
),
floatingActionButtonLocation: widget.floatingActionButtonLocation,

View File

@@ -171,6 +171,9 @@ class AppColor {
static const Color textColorLight = Color(0xFFB2B2B2);
static const Color iconColor = Color(0xFF444444); // #444444 rgb(68, 68, 68)
static const Color borderColor = Color(0xFFC7CFCD); // #C7CFCD rgb(199, 207, 205)`
static const Color unselectTextColor = Color(0xFF888888); //
static const Color accent1 = Color(0xffffe5ce); //
//endregion

View File

@@ -68,6 +68,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/calendar_search_outline.svg
SvgGenImage get calendarSearchOutline => const SvgGenImage('assets/icons/calendar_search_outline.svg');
/// File path: assets/icons/calendar_tick.svg
SvgGenImage get calendarTick => const SvgGenImage('assets/icons/calendar_tick.svg');
/// File path: assets/icons/call.svg
SvgGenImage get call => const SvgGenImage('assets/icons/call.svg');
@@ -80,6 +83,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/chicken.svg
SvgGenImage get chicken => const SvgGenImage('assets/icons/chicken.svg');
/// File path: assets/icons/chicken_house.svg
SvgGenImage get chickenHouse => const SvgGenImage('assets/icons/chicken_house.svg');
/// File path: assets/icons/chicken_map_marker.svg
SvgGenImage get chickenMapMarker => const SvgGenImage('assets/icons/chicken_map_marker.svg');
@@ -149,6 +155,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/excel_download.svg
SvgGenImage get excelDownload => const SvgGenImage('assets/icons/excel_download.svg');
/// File path: assets/icons/farm.svg
SvgGenImage get farm => const SvgGenImage('assets/icons/farm.svg');
/// File path: assets/icons/filter.svg
SvgGenImage get filter => const SvgGenImage('assets/icons/filter.svg');
@@ -334,10 +343,12 @@ class $AssetsIconsGen {
calendar,
calendarSearch,
calendarSearchOutline,
calendarTick,
call,
check,
checkSquare,
chicken,
chickenHouse,
chickenMapMarker,
clipboardEye,
clipboardTask,
@@ -361,6 +372,7 @@ class $AssetsIconsGen {
edit,
empty,
excelDownload,
farm,
filter,
filterOutline,
gps,
@@ -424,6 +436,9 @@ class $AssetsIconsGen {
class $AssetsImagesGen {
const $AssetsImagesGen();
/// File path: assets/images/bg_chicken_pattern.webp
AssetGenImage get bgChickenPattern => const AssetGenImage('assets/images/bg_chicken_pattern.webp');
/// File path: assets/images/chicken.png
AssetGenImage get chicken => const AssetGenImage('assets/images/chicken.png');
@@ -439,20 +454,17 @@ class $AssetsImagesGen {
/// File path: assets/images/place_holder.png
AssetGenImage get placeHolder => const AssetGenImage('assets/images/place_holder.png');
/// File path: assets/images/poultry_action.webp
AssetGenImage get poultryAction => const AssetGenImage('assets/images/poultry_action.webp');
/// File path: assets/images/select_role.webp
AssetGenImage get selectRole => const AssetGenImage('assets/images/select_role.webp');
/// List of all assets
List<AssetGenImage> get values => [
bgChickenPattern,
chicken,
innerSplash,
liveChicken,
outterSplash,
placeHolder,
poultryAction,
selectRole,
];
}
@@ -516,6 +528,9 @@ class $AssetsVecGen {
/// File path: assets/vec/calendar_search_outline.svg.vec
SvgGenImage get calendarSearchOutlineSvg => const SvgGenImage.vec('assets/vec/calendar_search_outline.svg.vec');
/// File path: assets/vec/calendar_tick.svg.vec
SvgGenImage get calendarTickSvg => const SvgGenImage.vec('assets/vec/calendar_tick.svg.vec');
/// File path: assets/vec/call.svg.vec
SvgGenImage get callSvg => const SvgGenImage.vec('assets/vec/call.svg.vec');
@@ -528,6 +543,9 @@ class $AssetsVecGen {
/// File path: assets/vec/chicken.svg.vec
SvgGenImage get chickenSvg => const SvgGenImage.vec('assets/vec/chicken.svg.vec');
/// File path: assets/vec/chicken_house.svg.vec
SvgGenImage get chickenHouseSvg => const SvgGenImage.vec('assets/vec/chicken_house.svg.vec');
/// File path: assets/vec/chicken_map_marker.svg.vec
SvgGenImage get chickenMapMarkerSvg => const SvgGenImage.vec('assets/vec/chicken_map_marker.svg.vec');
@@ -597,6 +615,9 @@ class $AssetsVecGen {
/// File path: assets/vec/excel_download.svg.vec
SvgGenImage get excelDownloadSvg => const SvgGenImage.vec('assets/vec/excel_download.svg.vec');
/// File path: assets/vec/farm.svg.vec
SvgGenImage get farmSvg => const SvgGenImage.vec('assets/vec/farm.svg.vec');
/// File path: assets/vec/filter.svg.vec
SvgGenImage get filterSvg => const SvgGenImage.vec('assets/vec/filter.svg.vec');
@@ -782,10 +803,12 @@ class $AssetsVecGen {
calendarSvg,
calendarSearchSvg,
calendarSearchOutlineSvg,
calendarTickSvg,
callSvg,
checkSvg,
checkSquareSvg,
chickenSvg,
chickenHouseSvg,
chickenMapMarkerSvg,
clipboardEyeSvg,
clipboardTaskSvg,
@@ -809,6 +832,7 @@ class $AssetsVecGen {
editSvg,
emptySvg,
excelDownloadSvg,
farmSvg,
filterSvg,
filterOutlineSvg,
gpsSvg,

View File

@@ -20,7 +20,7 @@ class CardIcon extends StatelessWidget {
this.borderWidth = 1,
this.iconWidth = 48,
this.iconHeight = 48,
this.iconColor ,
this.iconColor,
}) : assert((svgIcon != null) || (vecIcon != null), 'Either svgIcon or vecIcon must be provided');
final String title;
@@ -39,10 +39,11 @@ class CardIcon extends StatelessWidget {
final double width;
final double height;
//icon
final double iconWidth;
final double iconHeight;
final Color? iconColor ;
final Color? iconColor;
@override
Widget build(BuildContext context) {
@@ -67,13 +68,17 @@ class CardIcon extends StatelessWidget {
fit: BoxFit.cover,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: iconColor!= null ? ColorFilter.mode(iconColor!, BlendMode.srcIn) : null,
colorFilter: iconColor != null
? ColorFilter.mode(iconColor!, BlendMode.srcIn)
: null,
)
: SvgGenImage.vec(vecIcon!).svg(
fit: BoxFit.fill,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: iconColor!= null ? ColorFilter.mode(iconColor!, BlendMode.srcIn) : null,
colorFilter: iconColor != null
? ColorFilter.mode(iconColor!, BlendMode.srcIn)
: null,
),
Text(
title,
@@ -86,3 +91,146 @@ class CardIcon extends StatelessWidget {
);
}
}
class GlassMorphismCardIcon extends StatelessWidget {
const GlassMorphismCardIcon({
super.key,
required this.title,
this.svgIcon,
this.vecIcon,
this.onTap,
this.titleColor = AppColor.iconColor,
this.spacing = 20,
this.titleStyle,
this.borderColor = AppColor.blueNormal,
this.backgroundColor = Colors.white,
this.borderRadius = 35,
this.width = 180,
this.labelHeight = 80,
this.height = 180,
this.borderWidth = 1,
this.iconWidth = 48,
this.iconHeight = 48,
this.iconColor,
}) : assert((svgIcon != null) || (vecIcon != null), 'Either svgIcon or vecIcon must be provided');
final String title;
final int spacing;
final String? svgIcon;
final String? vecIcon;
final VoidCallback? onTap;
final Color titleColor;
final TextStyle? titleStyle;
final Color borderColor;
final Color backgroundColor;
final double borderRadius;
final double borderWidth;
final double width;
final double height;
final double labelHeight;
//icon
final double iconWidth;
final double iconHeight;
final Color? iconColor;
@override
Widget build(BuildContext context) {
return Container(
width: width.w,
height: height.h,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(35.r)),
child: InkWell(
onTap: onTap,
child: Stack(
children: [
Positioned.fill(
child: Container(
width: width.w,
height: height.h,
decoration: BoxDecoration(
color: Colors.white54,
border: Border.all(width: 1, color: Colors.white),
borderRadius: BorderRadius.circular(borderRadius),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 5,
offset: Offset(10, 12),
),
],
),
child: InkWell(
onTap: onTap,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: labelHeight.h + 35.h),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w),
child: Text(
title,
textAlign: TextAlign.center,
style:
titleStyle ??
AppFonts.yekan20Bold.copyWith(color: titleColor, height: 1.20),
),
),
],
),
),
),
),
Positioned(
top: 0,
left: 0,
right: 0,
child: Container(
height: labelHeight.h,
width: width.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius),
),
gradient: LinearGradient(
colors: [Color(0xff00b6bc), Color(0xff003ae0)],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
child: Center(
child: svgIcon != null
? SvgGenImage(svgIcon!).svg(
fit: BoxFit.cover,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: ColorFilter.mode(iconColor ?? Colors.white, BlendMode.srcIn),
)
: SvgGenImage.vec(vecIcon!).svg(
fit: BoxFit.fill,
width: iconWidth.w,
height: iconHeight.h,
colorFilter: ColorFilter.mode(iconColor ?? Colors.white, BlendMode.srcIn),
),
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_core/core.dart';
class TitleCheckBox extends StatelessWidget {
const TitleCheckBox({
super.key,
this.selectedColor,
this.unSelectedColor,
required this.title,
required this.isSelected,
required this.onChanged,
});
final Color? selectedColor;
final Color? unSelectedColor;
final String title;
final bool isSelected;
final Function(bool?) onChanged;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
onChanged(!isSelected);
},
child: Row(
children: [
Checkbox(
value: isSelected,
onChanged: onChanged,
activeColor: selectedColor ?? AppColor.blueNormal,
visualDensity: VisualDensity.compact,
side: BorderSide(width: 1.w, color: AppColor.unselectTextColor),
),
Text(
title,
style: isSelected
? AppFonts.yekan14Bold.copyWith(color: AppColor.blueNormal)
: AppFonts.yekan12.copyWith(color: AppColor.unselectTextColor),
),
],
),
);
}
}

View File

@@ -82,9 +82,10 @@ Widget buildUnitRow({
TextStyle? titleStyle,
TextStyle? valueStyle,
TextStyle? unitStyle,
EdgeInsetsGeometry? padding,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
padding: padding ?? const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

View File

@@ -3,6 +3,7 @@ export 'bottom_navigation/r_bottom_navigation.dart';
export 'bottom_navigation/wave_bottom_navigation.dart';
export 'bottom_sheet/base_bottom_sheet.dart';
export 'bottom_sheet/date_picker_bottom_sheet.dart';
export 'check_box/check_box_widget.dart';
//buttons
export 'buttons/buttons.dart';
export 'card/card_icon_widget.dart';