feat: new date picker and new logic
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
sdk.dir=C:/Users/Housh11/AppData/Local/Android/Sdk
|
sdk.dir=C:/Users/Housh11/AppData/Local/Android/Sdk
|
||||||
flutter.sdk=C:\\src\\flutter
|
flutter.sdk=C:\\src\\flutter
|
||||||
flutter.buildMode=release
|
flutter.buildMode=debug
|
||||||
flutter.versionName=1.3.28
|
flutter.versionName=1.3.28
|
||||||
flutter.versionCode=25
|
flutter.versionCode=25
|
||||||
@@ -69,9 +69,10 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
physics: BouncingScrollPhysics(),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
rolesWidget(),
|
rolesWidget(),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12.h),
|
||||||
@@ -82,8 +83,7 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
} else if (data.value.status == ResourceStatus.error) {
|
} else if (data.value.status == ResourceStatus.error) {
|
||||||
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
|
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
|
||||||
} else if (data.value.status == ResourceStatus.success) {
|
} else if (data.value.status == ResourceStatus.success) {
|
||||||
return SingleChildScrollView(
|
return Column(
|
||||||
child: Column(
|
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
children: [
|
children: [
|
||||||
ObxValue((isOpen) {
|
ObxValue((isOpen) {
|
||||||
@@ -122,7 +122,6 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
}, controller.isUnitInformationOpen),
|
}, controller.isUnitInformationOpen),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return SizedBox.shrink();
|
return SizedBox.shrink();
|
||||||
@@ -193,6 +192,7 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,11 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
|
|
||||||
Rx<Jalali> fromDateFilter = Jalali.now().obs;
|
Rx<Jalali> fromDateFilter = Jalali.now().obs;
|
||||||
Rx<Jalali> toDateFilter = Jalali.now().obs;
|
Rx<Jalali> toDateFilter = Jalali.now().obs;
|
||||||
Rxn<Jalali?> productionData = Rxn();
|
|
||||||
Rxn<ProductModel> selectedProductModel = Rxn<ProductModel>();
|
Rxn<ProductModel> selectedProductModel = Rxn<ProductModel>();
|
||||||
Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
|
Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
|
||||||
Rxn<GuildProfile> guildProfile = Rxn<GuildProfile>();
|
Rxn<GuildProfile> guildProfile = Rxn<GuildProfile>();
|
||||||
RxInt saleType = 1.obs;
|
RxInt saleType = 1.obs;
|
||||||
RxInt priceType = 1.obs;
|
RxInt priceType = 2.obs;
|
||||||
RxInt quotaType = 1.obs;
|
RxInt quotaType = 1.obs;
|
||||||
RxInt weight = 0.obs;
|
RxInt weight = 0.obs;
|
||||||
RxInt pricePerKilo = 0.obs;
|
RxInt pricePerKilo = 0.obs;
|
||||||
@@ -59,6 +58,10 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
Rxn<AllocatedMadeModel> selectedAllocationModelForUpdate = Rxn<AllocatedMadeModel>();
|
Rxn<AllocatedMadeModel> selectedAllocationModelForUpdate = Rxn<AllocatedMadeModel>();
|
||||||
SubmitStewardAllocation? tmpStewardAllocation;
|
SubmitStewardAllocation? tmpStewardAllocation;
|
||||||
|
|
||||||
|
Rxn<Jalali> productionDate = Rxn(null);
|
||||||
|
Map<String, DayData> freeProductionDateData = {};
|
||||||
|
Map<String, DayData> governmentalProductionDateData = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -97,6 +100,7 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
totalCost,
|
totalCost,
|
||||||
selectedProductModel,
|
selectedProductModel,
|
||||||
selectedGuildModel,
|
selectedGuildModel,
|
||||||
|
productionDate,
|
||||||
], (callback) => checkVerification());
|
], (callback) => checkVerification());
|
||||||
|
|
||||||
scrollControllerAllocationsMade.addListener(() {
|
scrollControllerAllocationsMade.addListener(() {
|
||||||
@@ -112,6 +116,45 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
(callback) => getAllocatedMade(),
|
(callback) => getAllocatedMade(),
|
||||||
time: Duration(milliseconds: timeDebounce),
|
time: Duration(milliseconds: timeDebounce),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
ever(rootLogic.stewardSalesInfoDashboard, (callback) {
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateGovernmentalProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
governmentalProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateFreeProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
freeProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getAllocatedMade([bool isLoadingMore = false]) async {
|
Future<void> getAllocatedMade([bool isLoadingMore = false]) async {
|
||||||
@@ -168,10 +211,18 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkVerification() {
|
void checkVerification() {
|
||||||
|
var hasWeight = quotaType.value == 1
|
||||||
|
? weight.value <=
|
||||||
|
(governmentalProductionDateData[productionDate.value?.formatCompactDate()]?.value ??
|
||||||
|
0)
|
||||||
|
: weight.value <=
|
||||||
|
(freeProductionDateData[productionDate.value?.formatCompactDate()]?.value ?? 0);
|
||||||
|
|
||||||
isValid.value =
|
isValid.value =
|
||||||
weight.value > 0 &&
|
weight.value > 0 &&
|
||||||
pricePerKilo.value > 0 &&
|
pricePerKilo.value > 0 &&
|
||||||
totalCost.value > 0 &&
|
totalCost.value > 0 &&
|
||||||
|
hasWeight &&
|
||||||
selectedProductModel.value != null &&
|
selectedProductModel.value != null &&
|
||||||
selectedGuildModel.value != null;
|
selectedGuildModel.value != null;
|
||||||
}
|
}
|
||||||
@@ -285,7 +336,7 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
weightOfCarcasses: weight.value,
|
weightOfCarcasses: weight.value,
|
||||||
sellType: saleType.value == 2 ? "free" : 'exclusive',
|
sellType: saleType.value == 2 ? "free" : 'exclusive',
|
||||||
numberOfCarcasses: 0,
|
numberOfCarcasses: 0,
|
||||||
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
|
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
|
||||||
quota: quotaType.value == 1 ? 'governmental' : 'free',
|
quota: quotaType.value == 1 ? 'governmental' : 'free',
|
||||||
guildKey: selectedGuildModel.value?.key,
|
guildKey: selectedGuildModel.value?.key,
|
||||||
productKey: selectedProductModel.value?.key,
|
productKey: selectedProductModel.value?.key,
|
||||||
@@ -308,6 +359,8 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
clearForm();
|
clearForm();
|
||||||
onRefresh();
|
onRefresh();
|
||||||
rootLogic.onRefresh();
|
rootLogic.onRefresh();
|
||||||
|
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ثبت موفق بود"));
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
onError: (error, stackTrace) {},
|
onError: (error, stackTrace) {},
|
||||||
);
|
);
|
||||||
@@ -345,7 +398,7 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
|
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
|
||||||
totalCostController.text = totalCost.value.toString().separatedByComma;
|
totalCostController.text = totalCost.value.toString().separatedByComma;
|
||||||
isValid.value = true;
|
isValid.value = true;
|
||||||
productionData.value = item.productionDate.toJalali;
|
productionDate.value = item.productionDate.toJalali;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearForm() {
|
void clearForm() {
|
||||||
@@ -359,7 +412,10 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
}
|
}
|
||||||
totalCostController.clear();
|
totalCostController.clear();
|
||||||
isValid.value = false;
|
isValid.value = false;
|
||||||
productionData.value = null;
|
productionDate.value = null;
|
||||||
|
quotaType.value = 1;
|
||||||
|
priceType.value = 2;
|
||||||
|
saleType.value = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateAllocation() async {
|
Future<void> updateAllocation() async {
|
||||||
@@ -382,6 +438,8 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
clearForm();
|
clearForm();
|
||||||
onRefresh();
|
onRefresh();
|
||||||
rootLogic.onRefresh();
|
rootLogic.onRefresh();
|
||||||
|
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ویرایش موفق بود"));
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
onError: (error, stackTrace) {},
|
onError: (error, stackTrace) {},
|
||||||
);
|
);
|
||||||
@@ -427,6 +485,7 @@ class SalesInProvinceLogic extends GetxController {
|
|||||||
if (broadcastPrice.value?.active == true) {
|
if (broadcastPrice.value?.active == true) {
|
||||||
pricePerKilo.value = broadcastPrice.value?.stewardPrice ?? 0;
|
pricePerKilo.value = broadcastPrice.value?.stewardPrice ?? 0;
|
||||||
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
|
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
|
||||||
|
priceType.value = 2;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: (error, stacktrace) {},
|
onError: (error, stacktrace) {},
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
|
|
||||||
Widget addOrEditBottomSheet([bool isEditMode = false]) {
|
Widget addOrEditBottomSheet([bool isEditMode = false]) {
|
||||||
return BaseBottomSheet(
|
return BaseBottomSheet(
|
||||||
height: Get.height * (isEditMode ? 0.55 : 0.75),
|
height: Get.height * (isEditMode ? 0.60 : 0.75),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: controller.formKey,
|
key: controller.formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -528,32 +528,25 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
label: 'وزن لاشه (کیلوگرم)',
|
label: 'وزن لاشه (کیلوگرم)',
|
||||||
),
|
),
|
||||||
|
|
||||||
ObxValue((data) {
|
Obx(() {
|
||||||
return RTextField(
|
return MonthlyDataCalendar(
|
||||||
controller: TextEditingController(),
|
|
||||||
filledColor: AppColor.bgLight,
|
|
||||||
filled: true,
|
|
||||||
label: 'تاریخ تولید گوشت',
|
label: 'تاریخ تولید گوشت',
|
||||||
onTap: () {
|
selectedDate: controller.productionDate.value?.formatCompactDate(),
|
||||||
Get.bottomSheet(
|
onDateSelect: (value) {
|
||||||
modalDatePicker((value) {
|
controller.productionDate.value = value.date;
|
||||||
controller.productionData.value = value;
|
|
||||||
controller.productionData.refresh();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
borderColor: AppColor.darkGreyLight,
|
dayData: controller.quotaType.value == 1
|
||||||
initText: data.value?.formatCompactDate(),
|
? controller.governmentalProductionDateData
|
||||||
|
: controller.freeProductionDateData,
|
||||||
);
|
);
|
||||||
}, controller.productionData),
|
}),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: isEditMode == false,
|
visible: isEditMode == false,
|
||||||
child: Column(
|
child: Column(
|
||||||
spacing: 12,
|
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
height: 58.h,
|
height: 50.h,
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@@ -574,28 +567,104 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
return RadioGroup(
|
return RadioGroup(
|
||||||
groupValue: controller.quotaType.value,
|
groupValue: controller.quotaType.value,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
controller.quotaType.value = value!;
|
controller.quotaType.value = value ?? 0;
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
|
controller.quotaType.value = 1;
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 1),
|
Radio(
|
||||||
Text('انبار دولتی', style: AppFonts.yekan14),
|
value: 1,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار دولتی',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
|
controller.quotaType.value = 2;
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 2),
|
Radio(
|
||||||
Text('انبار آزاد', style: AppFonts.yekan14),
|
value: 2,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار آزاد',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -603,7 +672,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 12.h),
|
SizedBox(height: 12),
|
||||||
Container(
|
Container(
|
||||||
height: 58.h,
|
height: 58.h,
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
@@ -631,15 +700,40 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: (controller.broadcastPrice.value?.active ?? false)
|
||||||
|
? () {
|
||||||
|
controller.priceType.value = 1;
|
||||||
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 1),
|
Radio(
|
||||||
Text('قیمت دولتی', style: AppFonts.yekan14),
|
value: 1,
|
||||||
|
enabled:
|
||||||
|
controller.broadcastPrice.value?.active ??
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'قیمت دولتی',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
(controller.broadcastPrice.value?.active ??
|
||||||
|
false)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
controller.priceType.value = 2;
|
||||||
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 2),
|
Radio(value: 2),
|
||||||
@@ -647,6 +741,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -657,10 +752,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
RTextField(
|
||||||
return Visibility(
|
|
||||||
visible: controller.broadcastPrice.value?.active == true,
|
|
||||||
child: RTextField(
|
|
||||||
variant: RTextFieldVariant.noBorder,
|
variant: RTextFieldVariant.noBorder,
|
||||||
controller: controller.pricePerKiloController,
|
controller: controller.pricePerKiloController,
|
||||||
borderColor: AppColor.darkGreyLight,
|
borderColor: AppColor.darkGreyLight,
|
||||||
@@ -679,8 +771,6 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
label: 'قیمت هر کیلو (ريال)',
|
label: 'قیمت هر کیلو (ريال)',
|
||||||
),
|
),
|
||||||
);
|
|
||||||
}),
|
|
||||||
|
|
||||||
RTextField(
|
RTextField(
|
||||||
variant: RTextFieldVariant.noBorder,
|
variant: RTextFieldVariant.noBorder,
|
||||||
@@ -711,11 +801,9 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
|
|||||||
onPressed: isEditMode
|
onPressed: isEditMode
|
||||||
? () async {
|
? () async {
|
||||||
await controller.updateAllocation();
|
await controller.updateAllocation();
|
||||||
Get.back();
|
|
||||||
}
|
}
|
||||||
: () async {
|
: () async {
|
||||||
await controller.submitAllocation();
|
await controller.submitAllocation();
|
||||||
Get.back();
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}, controller.isValid),
|
}, controller.isValid),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
|
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
|
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
|
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
|
||||||
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||||
@@ -30,7 +31,7 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
RxList<String> routesName = RxList();
|
RxList<String> routesName = RxList();
|
||||||
RxBool isLoadingMoreAllocationsMade = false.obs;
|
RxBool isLoadingMoreAllocationsMade = false.obs;
|
||||||
Rxn<IranProvinceCityModel> selectedCity = Rxn();
|
Rxn<IranProvinceCityModel> selectedCity = Rxn();
|
||||||
Rxn<Jalali?> productionData = Rxn();
|
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
|
||||||
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
TextEditingController quarantineCodeController = TextEditingController();
|
TextEditingController quarantineCodeController = TextEditingController();
|
||||||
TextEditingController saleWeightController = TextEditingController();
|
TextEditingController saleWeightController = TextEditingController();
|
||||||
@@ -46,6 +47,9 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
|
|
||||||
RxInt saleType = 2.obs;
|
RxInt saleType = 2.obs;
|
||||||
RxInt quotaType = 1.obs;
|
RxInt quotaType = 1.obs;
|
||||||
|
Rxn<Jalali> productionDate = Rxn();
|
||||||
|
Map<String, DayData> freeProductionDateData = {};
|
||||||
|
Map<String, DayData> governmentalProductionDateData = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@@ -57,6 +61,7 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
void onReady() {
|
void onReady() {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
getOutProvinceSales();
|
getOutProvinceSales();
|
||||||
|
getBroadcastPrice();
|
||||||
selectedProduct.value = rootLogic.rolesProductsModel.first;
|
selectedProduct.value = rootLogic.rolesProductsModel.first;
|
||||||
debounce(
|
debounce(
|
||||||
searchedValue,
|
searchedValue,
|
||||||
@@ -64,6 +69,46 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
time: Duration(milliseconds: timeDebounce),
|
time: Duration(milliseconds: timeDebounce),
|
||||||
);
|
);
|
||||||
setupListeners();
|
setupListeners();
|
||||||
|
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
ever(rootLogic.stewardSalesInfoDashboard, (callback) {
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateGovernmentalProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
|
||||||
|
governmentalProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateFreeProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
freeProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSearchValue(String? value) {
|
void setSearchValue(String? value) {
|
||||||
@@ -151,7 +196,7 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
saleType.value = item.saleType == 'free' ? 2 : 1;
|
saleType.value = item.saleType == 'free' ? 2 : 1;
|
||||||
quotaType.value = item.quota == 'governmental' ? 1 : 2;
|
quotaType.value = item.quota == 'governmental' ? 1 : 2;
|
||||||
isSaleSubmitButtonEnabled.value = true;
|
isSaleSubmitButtonEnabled.value = true;
|
||||||
productionData.value = item.productionDate.toJalali;
|
productionDate.value = item.productionDate.toJalali;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
|
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
|
||||||
@@ -174,6 +219,7 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
productKey: selectedProduct.value?.key,
|
productKey: selectedProduct.value?.key,
|
||||||
saleType: saleType.value == 2 ? 'free' : 'exclusive',
|
saleType: saleType.value == 2 ? 'free' : 'exclusive',
|
||||||
quota: quotaType.value == 1 ? 'governmental' : 'free',
|
quota: quotaType.value == 1 ? 'governmental' : 'free',
|
||||||
|
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
|
||||||
);
|
);
|
||||||
await safeCall(
|
await safeCall(
|
||||||
showError: true,
|
showError: true,
|
||||||
@@ -185,6 +231,11 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
res = true;
|
res = true;
|
||||||
onRefresh();
|
onRefresh();
|
||||||
rootLogic.onRefresh();
|
rootLogic.onRefresh();
|
||||||
|
Future.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
|
||||||
|
);
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
@@ -194,9 +245,9 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
quarantineCodeController.clear();
|
quarantineCodeController.clear();
|
||||||
saleWeightController.clear();
|
saleWeightController.clear();
|
||||||
saleDate.value = Jalali.now();
|
saleDate.value = Jalali.now();
|
||||||
productionData.value = null;
|
productionDate.value = null;
|
||||||
saleType.value = 2;
|
saleType.value = 2;
|
||||||
quotaType.value = 1;
|
quotaType.value = 2;
|
||||||
selectedBuyer.value = null;
|
selectedBuyer.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +270,11 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
onSuccess: (_) {
|
onSuccess: (_) {
|
||||||
res = true;
|
res = true;
|
||||||
onRefresh();
|
onRefresh();
|
||||||
|
Future.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
|
||||||
|
);
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
@@ -246,4 +302,16 @@ class SalesOutOfProvinceLogic extends GetxController {
|
|||||||
expandedListIndex.value = index;
|
expandedListIndex.value = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> getBroadcastPrice() async {
|
||||||
|
safeCall(
|
||||||
|
call: () async => await rootLogic.chickenRepository.getBroadcastPrice(
|
||||||
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
|
),
|
||||||
|
onSuccess: (result) {
|
||||||
|
broadcastPrice.value = result;
|
||||||
|
},
|
||||||
|
onError: (error, stacktrace) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
|
|
||||||
Widget addOrEditSaleBottomSheet([bool isOnEdit = false]) {
|
Widget addOrEditSaleBottomSheet([bool isOnEdit = false]) {
|
||||||
return BaseBottomSheet(
|
return BaseBottomSheet(
|
||||||
height: 600.h,
|
height: 670.h,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Form(
|
child: Form(
|
||||||
key: controller.formKey,
|
key: controller.formKey,
|
||||||
@@ -357,13 +357,12 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
Get.bottomSheet(
|
Get.bottomSheet(
|
||||||
modalDatePicker((value) {
|
modalDatePicker((value) {
|
||||||
controller.saleDate.value = value;
|
controller.saleDate.value = value;
|
||||||
|
|
||||||
controller.saleDate.refresh();
|
controller.saleDate.refresh();
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
borderColor: AppColor.darkGreyLight,
|
borderColor: AppColor.darkGreyLight,
|
||||||
initText: data.value?.formatCompactDate(),
|
initText: data.value.formatCompactDate(),
|
||||||
);
|
);
|
||||||
}, controller.saleDate),
|
}, controller.saleDate),
|
||||||
Visibility(visible: isOnEdit == false, child: _buyerWidget()),
|
Visibility(visible: isOnEdit == false, child: _buyerWidget()),
|
||||||
@@ -386,24 +385,18 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
children: [
|
children: [
|
||||||
ObxValue((data) {
|
Obx(() {
|
||||||
return RTextField(
|
return MonthlyDataCalendar(
|
||||||
controller: TextEditingController(),
|
|
||||||
filledColor: AppColor.bgLight,
|
|
||||||
filled: true,
|
|
||||||
label: 'تاریخ تولید گوشت',
|
label: 'تاریخ تولید گوشت',
|
||||||
onTap: () {
|
selectedDate: controller.productionDate.value?.formatCompactDate(),
|
||||||
Get.bottomSheet(
|
onDateSelect: (value) {
|
||||||
modalDatePicker((value) {
|
controller.productionDate.value = value.date;
|
||||||
controller.productionData.value = value;
|
|
||||||
controller.productionData.refresh();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
borderColor: AppColor.darkGreyLight,
|
dayData: controller.quotaType.value == 1
|
||||||
initText: data.value?.formatCompactDate(),
|
? controller.governmentalProductionDateData
|
||||||
|
: controller.freeProductionDateData,
|
||||||
);
|
);
|
||||||
}, controller.productionData),
|
}),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 50.h,
|
height: 50.h,
|
||||||
@@ -434,13 +427,46 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
controller.quotaType.value = 1;
|
controller.quotaType.value = 1;
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 1),
|
Radio(
|
||||||
Text('انبار دولتی', style: AppFonts.yekan14),
|
value: 1,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار دولتی',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -448,13 +474,46 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
controller.quotaType.value = 2;
|
controller.quotaType.value = 2;
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 2),
|
Radio(
|
||||||
Text('انبار آزاد', style: AppFonts.yekan14),
|
value: 2,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار آزاد',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -496,13 +555,30 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap:
|
||||||
|
(controller.broadcastPrice.value?.active ?? false)
|
||||||
|
? () {
|
||||||
controller.saleType.value = 1;
|
controller.saleType.value = 1;
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 1),
|
Radio(
|
||||||
Text('قیمت دولتی', style: AppFonts.yekan14),
|
value: 1,
|
||||||
|
enabled:
|
||||||
|
(controller.broadcastPrice.value?.active ??
|
||||||
|
false),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'قیمت دولتی',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
(controller.broadcastPrice.value?.active ??
|
||||||
|
false)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -594,9 +670,6 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
|
|||||||
onPressed: data.value
|
onPressed: data.value
|
||||||
? () async {
|
? () async {
|
||||||
var res = isOnEdit ? await controller.editSale() : await controller.createSale();
|
var res = isOnEdit ? await controller.editSale() : await controller.createSale();
|
||||||
if (res) {
|
|
||||||
Get.back();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class SegmentationLogic extends GetxController {
|
|||||||
RxnString searchedValue = RxnString();
|
RxnString searchedValue = RxnString();
|
||||||
RxInt segmentType = 1.obs;
|
RxInt segmentType = 1.obs;
|
||||||
RxInt saleType = 2.obs;
|
RxInt saleType = 2.obs;
|
||||||
RxInt quotaType = 1.obs;
|
RxInt quotaType = 2.obs;
|
||||||
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
TextEditingController weightController = TextEditingController(text: '0');
|
TextEditingController weightController = TextEditingController(text: '0');
|
||||||
RxBool isSubmitButtonEnabled = false.obs;
|
RxBool isSubmitButtonEnabled = false.obs;
|
||||||
@@ -35,9 +35,12 @@ class SegmentationLogic extends GetxController {
|
|||||||
Resource<PaginationModel<SegmentationModel>>.loading().obs;
|
Resource<PaginationModel<SegmentationModel>>.loading().obs;
|
||||||
|
|
||||||
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
|
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
|
||||||
Rxn<Jalali?> productionData = Rxn();
|
|
||||||
Rx<Jalali> saleDate = Jalali.now().obs;
|
Rx<Jalali> saleDate = Jalali.now().obs;
|
||||||
|
|
||||||
|
Rxn<Jalali?> productionDate = Rxn(null);
|
||||||
|
Map<String, DayData> freeProductionDateData = {};
|
||||||
|
Map<String, DayData> governmentalProductionDateData = {};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
@@ -45,6 +48,46 @@ class SegmentationLogic extends GetxController {
|
|||||||
once(rootLogic.rolesProductsModel, (callback) => selectedProduct.value = callback.first);
|
once(rootLogic.rolesProductsModel, (callback) => selectedProduct.value = callback.first);
|
||||||
getAllSegmentation();
|
getAllSegmentation();
|
||||||
getGuilds();
|
getGuilds();
|
||||||
|
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
|
||||||
|
ever(rootLogic.stewardSalesInfoDashboard, (callback) {
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateGovernmentalProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
governmentalProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateFreeProductionDateData() {
|
||||||
|
var today = Jalali.now();
|
||||||
|
freeProductionDateData = {
|
||||||
|
today.formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-1).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
today.addDays(-2).formatCompactDate(): DayData(
|
||||||
|
value: rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight?.toInt(),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -55,7 +98,6 @@ class SegmentationLogic extends GetxController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
// TODO: implement onClose
|
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +111,8 @@ class SegmentationLogic extends GetxController {
|
|||||||
(callback) => getAllSegmentation(),
|
(callback) => getAllSegmentation(),
|
||||||
time: Duration(milliseconds: timeDebounce),
|
time: Duration(milliseconds: timeDebounce),
|
||||||
);
|
);
|
||||||
ever(selectedSegment, (_) {
|
|
||||||
|
everAll([selectedSegment, quotaType, saleType], (_) {
|
||||||
validateForm();
|
validateForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -85,17 +128,26 @@ class SegmentationLogic extends GetxController {
|
|||||||
weightController.text = '0';
|
weightController.text = '0';
|
||||||
selectedSegment.value = null;
|
selectedSegment.value = null;
|
||||||
selectedGuildModel.value = null;
|
selectedGuildModel.value = null;
|
||||||
productionData.value = null;
|
productionDate.value = Jalali.now();
|
||||||
segmentType.value = 1;
|
segmentType.value = 1;
|
||||||
saleType.value = 1;
|
saleType.value = 2;
|
||||||
quotaType.value = 1;
|
quotaType.value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validateForm() {
|
void validateForm() {
|
||||||
var weight = int.tryParse(weightController.text.trim().clearComma);
|
var weight = int.tryParse(weightController.text.trim().clearComma);
|
||||||
|
var hasWeight = quotaType.value == 2
|
||||||
|
? ((weight ?? 0) <= (rootLogic.stewardSalesInfoDashboard.value?.totalFreeRemainWeight ?? 0))
|
||||||
|
: ((weight ?? 0) <=
|
||||||
|
(rootLogic.stewardSalesInfoDashboard.value?.totalGovernmentalRemainWeight ?? 0));
|
||||||
|
if (!hasWeight) {
|
||||||
|
defaultShowErrorMessage("میزان وزن تخیصصی شده بیشتر از وزن باقیمانده است!");
|
||||||
|
}
|
||||||
|
|
||||||
isSubmitButtonEnabled.value =
|
isSubmitButtonEnabled.value =
|
||||||
selectedProduct.value != null &&
|
selectedProduct.value != null &&
|
||||||
weightController.text.isNotEmpty &&
|
weightController.text.isNotEmpty &&
|
||||||
|
hasWeight &&
|
||||||
weight! > 0 &&
|
weight! > 0 &&
|
||||||
(segmentType.value == 1 || (segmentType.value == 2 && selectedGuildModel.value != null));
|
(segmentType.value == 1 || (segmentType.value == 2 && selectedGuildModel.value != null));
|
||||||
}
|
}
|
||||||
@@ -115,7 +167,6 @@ class SegmentationLogic extends GetxController {
|
|||||||
|
|
||||||
await safeCall(
|
await safeCall(
|
||||||
showError: true,
|
showError: true,
|
||||||
showSuccess: true,
|
|
||||||
call: () async => await rootLogic.chickenRepository.getSegmentation(
|
call: () async => await rootLogic.chickenRepository.getSegmentation(
|
||||||
token: rootLogic.tokenService.accessToken.value!,
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
queryParameters: buildQueryParams(
|
queryParameters: buildQueryParams(
|
||||||
@@ -171,7 +222,7 @@ class SegmentationLogic extends GetxController {
|
|||||||
model: SegmentationModel(
|
model: SegmentationModel(
|
||||||
key: selectedSegment.value?.key,
|
key: selectedSegment.value?.key,
|
||||||
weight: int.tryParse(weightController.text.clearComma) ?? 0,
|
weight: int.tryParse(weightController.text.clearComma) ?? 0,
|
||||||
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
|
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSuccess: (result) {
|
onSuccess: (result) {
|
||||||
@@ -196,22 +247,24 @@ class SegmentationLogic extends GetxController {
|
|||||||
if (segmentType.value == 2) {
|
if (segmentType.value == 2) {
|
||||||
segmentationModel = segmentationModel.copyWith(guildKey: selectedGuildModel.value?.key);
|
segmentationModel = segmentationModel.copyWith(guildKey: selectedGuildModel.value?.key);
|
||||||
}
|
}
|
||||||
if (productionData.value != null) {
|
|
||||||
segmentationModel = segmentationModel.copyWith(
|
segmentationModel = segmentationModel.copyWith(
|
||||||
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
|
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
await safeCall(
|
await safeCall(
|
||||||
showError: true,
|
showError: true,
|
||||||
showSuccess: true,
|
|
||||||
call: () async => await rootLogic.chickenRepository.createSegmentation(
|
call: () async => await rootLogic.chickenRepository.createSegmentation(
|
||||||
token: rootLogic.tokenService.accessToken.value!,
|
token: rootLogic.tokenService.accessToken.value!,
|
||||||
model: segmentationModel,
|
model: segmentationModel,
|
||||||
),
|
),
|
||||||
onSuccess: (result) {
|
onSuccess: (result) async {
|
||||||
res = true;
|
res = true;
|
||||||
isSubmitButtonEnabled.value = true;
|
isSubmitButtonEnabled.value = false;
|
||||||
onRefresh();
|
onRefresh();
|
||||||
|
Future.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() => defaultShowSuccessMessage("قطعهبندی با موفقیت ثبت شد!"),
|
||||||
|
);
|
||||||
|
Get.back();
|
||||||
},
|
},
|
||||||
onError: (error, stacktrace) {
|
onError: (error, stacktrace) {
|
||||||
res = false;
|
res = false;
|
||||||
@@ -241,6 +294,8 @@ class SegmentationLogic extends GetxController {
|
|||||||
currentPage.value = 1;
|
currentPage.value = 1;
|
||||||
await rootLogic.onRefresh();
|
await rootLogic.onRefresh();
|
||||||
await getAllSegmentation();
|
await getAllSegmentation();
|
||||||
|
_updateFreeProductionDateData();
|
||||||
|
_updateGovernmentalProductionDateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleExpansion({int? index}) {
|
void toggleExpansion({int? index}) {
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import 'package:rasadyar_core/core.dart';
|
|||||||
import 'logic.dart';
|
import 'logic.dart';
|
||||||
|
|
||||||
class SegmentationPage extends GetView<SegmentationLogic> {
|
class SegmentationPage extends GetView<SegmentationLogic> {
|
||||||
|
final today = Jalali.now();
|
||||||
|
final oneDayAgo = Jalali.now().addDays(-1);
|
||||||
|
final twoDaysAgo = Jalali.now().addDays(-2);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChickenBasePage(
|
return ChickenBasePage(
|
||||||
@@ -342,24 +346,6 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ObxValue((data) {
|
|
||||||
return RTextField(
|
|
||||||
controller: TextEditingController(),
|
|
||||||
filledColor: AppColor.bgLight,
|
|
||||||
filled: true,
|
|
||||||
label: 'تاریخ تولید گوشت',
|
|
||||||
onTap: () {
|
|
||||||
Get.bottomSheet(
|
|
||||||
modalDatePicker((value) {
|
|
||||||
controller.productionData.value = value;
|
|
||||||
controller.productionData.refresh();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
borderColor: AppColor.darkGreyLight,
|
|
||||||
initText: data.value?.formatCompactDate(),
|
|
||||||
);
|
|
||||||
}, controller.productionData),
|
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 50.h,
|
height: 50.h,
|
||||||
@@ -458,13 +444,46 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
controller.quotaType.value = 1;
|
controller.quotaType.value = 1;
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 1),
|
Radio(
|
||||||
Text('انبار دولتی', style: AppFonts.yekan14),
|
value: 1,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار دولتی',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalGovernmentalRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -472,13 +491,46 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0
|
||||||
|
? () {
|
||||||
controller.quotaType.value = 2;
|
controller.quotaType.value = 2;
|
||||||
},
|
}
|
||||||
|
: null,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Radio(value: 2),
|
Radio(
|
||||||
Text('انبار آزاد', style: AppFonts.yekan14),
|
value: 2,
|
||||||
|
enabled:
|
||||||
|
(controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'انبار آزاد',
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color:
|
||||||
|
((controller
|
||||||
|
.rootLogic
|
||||||
|
.stewardSalesInfoDashboard
|
||||||
|
.value
|
||||||
|
?.totalFreeRemainWeight ??
|
||||||
|
-1) >
|
||||||
|
0)
|
||||||
|
? AppColor.textColor
|
||||||
|
: AppColor.labelTextColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -490,6 +542,17 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Obx(() {
|
||||||
|
return MonthlyDataCalendar(
|
||||||
|
label: 'تاریخ تولید گوشت',
|
||||||
|
selectedDate: controller.productionDate.value?.formatCompactDate(),
|
||||||
|
onDateSelect: (value) => controller.productionDate..value = value.date,
|
||||||
|
dayData: controller.quotaType.value == 1
|
||||||
|
? controller.governmentalProductionDateData
|
||||||
|
: controller.freeProductionDateData,
|
||||||
|
);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -609,6 +672,7 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Container modalDatePicker(ValueChanged<Jalali> onDateSelected) {
|
Container modalDatePicker(ValueChanged<Jalali> onDateSelected) {
|
||||||
|
Jalali currentDate = Jalali.now();
|
||||||
Jalali? tempPickedDate;
|
Jalali? tempPickedDate;
|
||||||
return Container(
|
return Container(
|
||||||
height: 250,
|
height: 250,
|
||||||
@@ -652,6 +716,14 @@ class SegmentationPage extends GetView<SegmentationLogic> {
|
|||||||
child: PersianCupertinoDatePicker(
|
child: PersianCupertinoDatePicker(
|
||||||
initialDateTime: controller.saleDate.value,
|
initialDateTime: controller.saleDate.value,
|
||||||
mode: PersianCupertinoDatePickerMode.date,
|
mode: PersianCupertinoDatePickerMode.date,
|
||||||
|
maximumDate: currentDate.addDays(3),
|
||||||
|
minimumDate: currentDate
|
||||||
|
.toDateTime()
|
||||||
|
.subtract(Duration(days: 1))
|
||||||
|
.toString()
|
||||||
|
.toJalali,
|
||||||
|
maximumYear: currentDate.year,
|
||||||
|
minimumYear: currentDate.year,
|
||||||
onDateTimeChanged: (dateTime) {
|
onDateTimeChanged: (dateTime) {
|
||||||
tempPickedDate = dateTime;
|
tempPickedDate = dateTime;
|
||||||
},
|
},
|
||||||
|
|||||||
427
packages/core/lib/presentation/widget/monthly_calender.dart
Normal file
427
packages/core/lib/presentation/widget/monthly_calender.dart
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
/// MonthlyDataCalendar - A Persian calendar date picker that displays data values under each day
|
||||||
|
/// Shows a full month grid with day numbers and associated data values
|
||||||
|
/// Only today and 2 days ago are enabled
|
||||||
|
class MonthlyDataCalendar extends StatefulWidget {
|
||||||
|
final Function(DayInfo)? onDateSelect;
|
||||||
|
final Map<String, DayData>? dayData; // Map with date keys and data objects
|
||||||
|
final String? selectedDate;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
const MonthlyDataCalendar({
|
||||||
|
super.key,
|
||||||
|
this.onDateSelect,
|
||||||
|
this.dayData,
|
||||||
|
this.selectedDate,
|
||||||
|
this.label = 'انتخاب تاریخ',
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MonthlyDataCalendar> createState() => _MonthlyDataCalendarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MonthlyDataCalendarState extends State<MonthlyDataCalendar> {
|
||||||
|
late Jalali _currentMonth;
|
||||||
|
List<DayInfo?> _calendarDays = [];
|
||||||
|
final TextEditingController _textController = TextEditingController();
|
||||||
|
|
||||||
|
// Persian month names
|
||||||
|
final List<String> _monthNames = [
|
||||||
|
'فروردین',
|
||||||
|
'اردیبهشت',
|
||||||
|
'خرداد',
|
||||||
|
'تیر',
|
||||||
|
'مرداد',
|
||||||
|
'شهریور',
|
||||||
|
'مهر',
|
||||||
|
'آبان',
|
||||||
|
'آذر',
|
||||||
|
'دی',
|
||||||
|
'بهمن',
|
||||||
|
'اسفند',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Day names for header
|
||||||
|
final List<String> _dayNames = ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_currentMonth = Jalali.now();
|
||||||
|
_generateCalendar();
|
||||||
|
_updateDisplayValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(MonthlyDataCalendar oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.selectedDate != widget.selectedDate || oldWidget.dayData != widget.dayData) {
|
||||||
|
_generateCalendar();
|
||||||
|
_updateDisplayValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DayData? _getDayData(String formattedDate) {
|
||||||
|
return widget.dayData?[formattedDate];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a date is enabled (today or 2 days ago)
|
||||||
|
bool _isDateEnabled(Jalali date) {
|
||||||
|
final today = Jalali.now();
|
||||||
|
final twoDaysAgo = today.addDays(-2);
|
||||||
|
final oneDayAgo = today.addDays(-1);
|
||||||
|
|
||||||
|
final dateStr = date.formatCompactDate();
|
||||||
|
final todayStr = today.formatCompactDate();
|
||||||
|
final twoDaysAgoStr = twoDaysAgo.formatCompactDate();
|
||||||
|
final oneDayAgoStr = oneDayAgo.formatCompactDate();
|
||||||
|
|
||||||
|
return dateStr == todayStr || dateStr == twoDaysAgoStr || dateStr == oneDayAgoStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _generateCalendar() {
|
||||||
|
final days = <DayInfo?>[];
|
||||||
|
final year = _currentMonth.year;
|
||||||
|
final month = _currentMonth.month;
|
||||||
|
final daysInMonth = _currentMonth.monthLength;
|
||||||
|
|
||||||
|
// Get first day of month to determine starting position
|
||||||
|
final firstDayOfMonth = Jalali(year, month, 1);
|
||||||
|
final dayOfWeek = firstDayOfMonth.weekDay; // 1 = Saturday in shamsi_date
|
||||||
|
|
||||||
|
// Add empty cells for days before the first day of month
|
||||||
|
for (int i = 1; i < dayOfWeek; i++) {
|
||||||
|
days.add(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all days of the month
|
||||||
|
for (int day = 1; day <= daysInMonth; day++) {
|
||||||
|
final date = Jalali(year, month, day);
|
||||||
|
final today = Jalali.now();
|
||||||
|
final isEnabled = _isDateEnabled(date);
|
||||||
|
final formattedDate = date.formatCompactDate();
|
||||||
|
final data = _getDayData(formattedDate);
|
||||||
|
final hasZeroValue = isEnabled && data != null && data.value == 0;
|
||||||
|
|
||||||
|
days.add(
|
||||||
|
DayInfo(
|
||||||
|
date: date,
|
||||||
|
day: day,
|
||||||
|
formattedDate: formattedDate,
|
||||||
|
isToday: date.year == today.year && date.month == today.month && date.day == today.day,
|
||||||
|
isEnabled: isEnabled,
|
||||||
|
hasZeroValue: hasZeroValue,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_calendarDays = days;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleDayClick(DayInfo dayInfo) {
|
||||||
|
if (dayInfo.isEnabled && !dayInfo.hasZeroValue && widget.onDateSelect != null) {
|
||||||
|
widget.onDateSelect!(dayInfo);
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleNextMonth() {
|
||||||
|
setState(() {
|
||||||
|
if (_currentMonth.month == 12) {
|
||||||
|
_currentMonth = Jalali(_currentMonth.year + 1, 1, 1);
|
||||||
|
} else {
|
||||||
|
_currentMonth = Jalali(_currentMonth.year, _currentMonth.month + 1, 1);
|
||||||
|
}
|
||||||
|
_generateCalendar();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handlePrevMonth() {
|
||||||
|
setState(() {
|
||||||
|
if (_currentMonth.month == 1) {
|
||||||
|
_currentMonth = Jalali(_currentMonth.year - 1, 12, 1);
|
||||||
|
} else {
|
||||||
|
_currentMonth = Jalali(_currentMonth.year, _currentMonth.month - 1, 1);
|
||||||
|
}
|
||||||
|
_generateCalendar();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isSelected(String formattedDate) {
|
||||||
|
return widget.selectedDate != null && widget.selectedDate == formattedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatNumber(int? num) {
|
||||||
|
if (num == null) return '';
|
||||||
|
final formatter = intl.NumberFormat('#,###', 'fa');
|
||||||
|
return formatter.format(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateDisplayValue() {
|
||||||
|
if (widget.selectedDate == null || widget.selectedDate!.isEmpty) {
|
||||||
|
_textController.text = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final dayInfo = _calendarDays.firstWhere(
|
||||||
|
(d) => d != null && d.formattedDate == widget.selectedDate,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dayInfo != null) {
|
||||||
|
final persianDay = _toPersianNumber(dayInfo.day);
|
||||||
|
_textController.text = '$persianDay ${_monthNames[dayInfo.date.month - 1]}';
|
||||||
|
} else {
|
||||||
|
_textController.text = widget.selectedDate ?? '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _toPersianNumber(int number) {
|
||||||
|
const english = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
const persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
|
||||||
|
|
||||||
|
String result = number.toString();
|
||||||
|
for (int i = 0; i < english.length; i++) {
|
||||||
|
result = result.replaceAll(english[i], persian[i]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showCalendarDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Dialog(
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 650, maxHeight: 650),
|
||||||
|
child: Card(
|
||||||
|
elevation: 3,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
_buildHeader(),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildDayNamesHeader(),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
_buildCalendarGrid(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeader() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.only(bottom: 16),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(bottom: BorderSide(color: Color(0xFFF0F0F0), width: 2)),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
IconButton(onPressed: _handlePrevMonth, icon: const Icon(Icons.chevron_right)),
|
||||||
|
Text(
|
||||||
|
'${_monthNames[_currentMonth.month - 1]} ${_toPersianNumber(_currentMonth.year)}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 20,
|
||||||
|
color: Color(0xFF333333),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(onPressed: _handleNextMonth, icon: const Icon(Icons.chevron_left)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDayNamesHeader() {
|
||||||
|
return Row(
|
||||||
|
children: _dayNames.map((dayName) {
|
||||||
|
return Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
dayName,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF666666),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCalendarGrid() {
|
||||||
|
return GridView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
|
crossAxisCount: 7,
|
||||||
|
crossAxisSpacing: 4,
|
||||||
|
mainAxisSpacing: 4,
|
||||||
|
childAspectRatio: 1,
|
||||||
|
),
|
||||||
|
itemCount: _calendarDays.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final dayInfo = _calendarDays[index];
|
||||||
|
|
||||||
|
if (dayInfo == null) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _buildDayCell(dayInfo);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildDayCell(DayInfo dayInfo) {
|
||||||
|
final data = _getDayData(dayInfo.formattedDate);
|
||||||
|
final isSelectedDay = _isSelected(dayInfo.formattedDate);
|
||||||
|
|
||||||
|
Color bgColor = Colors.white;
|
||||||
|
Color borderColor = const Color(0xFFE0E0E0);
|
||||||
|
double opacity = 1.0;
|
||||||
|
bool isClickable = true;
|
||||||
|
|
||||||
|
if (!dayInfo.isEnabled || dayInfo.hasZeroValue) {
|
||||||
|
bgColor = const Color(0xFFF5F5F5);
|
||||||
|
borderColor = const Color(0xFFD0D0D0);
|
||||||
|
opacity = dayInfo.hasZeroValue ? 0.4 : 0.25;
|
||||||
|
isClickable = false;
|
||||||
|
} else if (isSelectedDay) {
|
||||||
|
bgColor = const Color(0xFFE3F2FD);
|
||||||
|
borderColor = const Color(0xFF1976D2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dayInfo.isToday && dayInfo.isEnabled && !dayInfo.hasZeroValue) {
|
||||||
|
borderColor = const Color(0xFFFF9800);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Opacity(
|
||||||
|
opacity: opacity,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: isClickable ? () => _handleDayClick(dayInfo) : null,
|
||||||
|
child: AnimatedContainer(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: bgColor,
|
||||||
|
border: Border.all(color: borderColor, width: 2),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
_toPersianNumber(dayInfo.day),
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 14,
|
||||||
|
color: dayInfo.isToday ? const Color(0xFFFF9800) : const Color(0xFF333333),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (data != null && data.value != null) ...[
|
||||||
|
Text(
|
||||||
|
_formatNumber(data.value),
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
color: Color(0xFF1976D2),
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return TextField(
|
||||||
|
controller: _textController,
|
||||||
|
readOnly: true,
|
||||||
|
onTap: _showCalendarDialog,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: widget.label,
|
||||||
|
hintText: 'انتخاب تاریخ...',
|
||||||
|
prefixIcon: IconButton(
|
||||||
|
icon: const Icon(Icons.calendar_month_outlined),
|
||||||
|
onPressed: _showCalendarDialog,
|
||||||
|
),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.darkGreyLight, width: 1),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.darkGreyLight, width: 1),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
borderSide: BorderSide(color: AppColor.darkGreyLight, width: 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper classes
|
||||||
|
class DayInfo {
|
||||||
|
final Jalali date;
|
||||||
|
final int day;
|
||||||
|
final String formattedDate;
|
||||||
|
final bool isToday;
|
||||||
|
final bool isEnabled;
|
||||||
|
final bool hasZeroValue;
|
||||||
|
|
||||||
|
DayInfo({
|
||||||
|
required this.date,
|
||||||
|
required this.day,
|
||||||
|
required this.formattedDate,
|
||||||
|
required this.isToday,
|
||||||
|
required this.isEnabled,
|
||||||
|
required this.hasZeroValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class DayData {
|
||||||
|
final int? value;
|
||||||
|
|
||||||
|
DayData({this.value});
|
||||||
|
|
||||||
|
factory DayData.fromJson(Map<String, dynamic> json) {
|
||||||
|
return DayData(value: json['value1'] as int?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {'value1': value};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'DayData{value: $value}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ export 'loading/loading_widget.dart';
|
|||||||
// other
|
// other
|
||||||
export 'logo_widget.dart';
|
export 'logo_widget.dart';
|
||||||
export 'marquee/r_marquee.dart';
|
export 'marquee/r_marquee.dart';
|
||||||
|
export 'monthly_calender.dart';
|
||||||
export 'overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown.dart';
|
export 'overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown.dart';
|
||||||
export 'overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown_logic.dart';
|
export 'overlay_dropdown_widget/multi_select_dropdown/multi_select_dropdown_logic.dart';
|
||||||
export 'overlay_dropdown_widget/overlay_dropdown.dart';
|
export 'overlay_dropdown_widget/overlay_dropdown.dart';
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ Future<T?> gSafeCall<T>({
|
|||||||
|
|
||||||
if (error is DioException && error.response?.statusCode == 401) {
|
if (error is DioException && error.response?.statusCode == 401) {
|
||||||
if (showError) {
|
if (showError) {
|
||||||
(onShowErrorMessage ?? _defaultShowErrorMessage)('خطا در احراز هویت');
|
(onShowErrorMessage ?? defaultShowErrorMessage)('خطا در احراز هویت');
|
||||||
}
|
}
|
||||||
onError?.call(error, stackTrace);
|
onError?.call(error, stackTrace);
|
||||||
return null;
|
return null;
|
||||||
@@ -76,7 +76,7 @@ Future<T?> gSafeCall<T>({
|
|||||||
if (retryCount > maxRetries || !_isRetryableError(error)) {
|
if (retryCount > maxRetries || !_isRetryableError(error)) {
|
||||||
if (showError) {
|
if (showError) {
|
||||||
final message = _getErrorMessage(error);
|
final message = _getErrorMessage(error);
|
||||||
(onShowErrorMessage ?? _defaultShowErrorMessage)(message);
|
(onShowErrorMessage ?? defaultShowErrorMessage)(message);
|
||||||
}
|
}
|
||||||
onError?.call(error, stackTrace);
|
onError?.call(error, stackTrace);
|
||||||
return null;
|
return null;
|
||||||
@@ -171,7 +171,7 @@ void defaultShowSuccessMessage(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _defaultShowErrorMessage(String message) {
|
void defaultShowErrorMessage(String message) {
|
||||||
Get.snackbar(
|
Get.snackbar(
|
||||||
'خطا',
|
'خطا',
|
||||||
message,
|
message,
|
||||||
|
|||||||
12
pubspec.lock
12
pubspec.lock
@@ -101,10 +101,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "4e54dbeefdc70691ba80b3bce3976af63b5425c8c07dface348dfee664a0edc1"
|
sha256: a9461b8e586bf018dd4afd2e13b49b08c6a844a4b226c8d1d10f3a723cdd78c3
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.9.0"
|
version: "2.10.1"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -739,10 +739,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: hive_ce
|
name: hive_ce
|
||||||
sha256: d678b1b2e315c18cd7ed8fd79eda25d70a1f3852d6988bfe5461cffe260c60aa
|
sha256: "81d39a03c4c0ba5938260a8c3547d2e71af59defecea21793d57fc3551f0d230"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.14.0"
|
version: "2.15.1"
|
||||||
hive_ce_flutter:
|
hive_ce_flutter:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -755,10 +755,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: hive_ce_generator
|
name: hive_ce_generator
|
||||||
sha256: "8c677690c8ead43778ddf7ed8ff17e852dd5d22d082c75182b072842c0dc5055"
|
sha256: b19ac263cb37529513508ba47352c41e6de72ba879952898d9c18c9c8a955921
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.5"
|
version: "1.10.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: rasadyar_app
|
name: rasadyar_app
|
||||||
description: "A new Flutter project."
|
description: "A new Flutter project."
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 1.3.28+25
|
version: 1.3.29+26
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.9.2
|
sdk: ^3.9.2
|
||||||
@@ -38,8 +38,8 @@ dev_dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^6.0.0
|
flutter_lints: ^6.0.0
|
||||||
##code generation
|
##code generation
|
||||||
build_runner: ^2.9.0
|
build_runner: ^2.10.1
|
||||||
hive_ce_generator: ^1.9.5
|
hive_ce_generator: ^1.10.0
|
||||||
freezed: ^3.2.3
|
freezed: ^3.2.3
|
||||||
json_serializable: ^6.11.1
|
json_serializable: ^6.11.1
|
||||||
flutter_gen_runner: ^5.12.0
|
flutter_gen_runner: ^5.12.0
|
||||||
|
|||||||
Reference in New Issue
Block a user