feat: new date picker and new logic

This commit is contained in:
2025-11-02 15:45:31 +03:30
parent 627497a840
commit 858fb48f68
13 changed files with 1090 additions and 247 deletions

View File

@@ -1,5 +1,5 @@
sdk.dir=C:/Users/Housh11/AppData/Local/Android/Sdk
flutter.sdk=C:\\src\\flutter
flutter.buildMode=release
flutter.buildMode=debug
flutter.versionName=1.3.28
flutter.versionCode=25

View File

@@ -69,21 +69,21 @@ class ProfilePage extends GetView<ProfileLogic> {
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
rolesWidget(),
SizedBox(height: 12.h),
children: [
rolesWidget(),
SizedBox(height: 12.h),
ObxValue((data) {
if (data.value.status == ResourceStatus.loading) {
return LoadingWidget();
} else if (data.value.status == ResourceStatus.error) {
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
} else if (data.value.status == ResourceStatus.success) {
return SingleChildScrollView(
child: Column(
ObxValue((data) {
if (data.value.status == ResourceStatus.loading) {
return LoadingWidget();
} else if (data.value.status == ResourceStatus.error) {
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
} else if (data.value.status == ResourceStatus.success) {
return Column(
spacing: 6,
children: [
ObxValue((isOpen) {
@@ -122,75 +122,75 @@ class ProfilePage extends GetView<ProfileLogic> {
}, controller.isUnitInformationOpen),
),
],
);
} else {
return SizedBox.shrink();
}
}, controller.userProfile),
GestureDetector(
onTap: () {
Get.bottomSheet(changePasswordBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8.h),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.lockSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
Text(
'تغییر رمز عبور',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
);
} else {
return SizedBox.shrink();
}
}, controller.userProfile),
GestureDetector(
onTap: () {
Get.bottomSheet(changePasswordBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8.h),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.lockSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
Text(
'تغییر رمز عبور',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
),
],
),
),
),
GestureDetector(
onTap: () {
Get.bottomSheet(exitBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.logoutSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.redNormal, BlendMode.srcIn),
),
Text(
'خروج',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.redNormal),
),
],
GestureDetector(
onTap: () {
Get.bottomSheet(exitBottomSheet(), isScrollControlled: true);
},
child: Container(
height: 47.h,
margin: EdgeInsets.symmetric(horizontal: 8),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
),
child: Row(
spacing: 6,
children: [
Assets.vec.logoutSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.redNormal, BlendMode.srcIn),
),
Text(
'خروج',
textAlign: TextAlign.center,
style: AppFonts.yekan14.copyWith(color: AppColor.redNormal),
),
],
),
),
),
),
SizedBox(height: 100),
],
SizedBox(height: 100),
],
),
),
),
],

View File

@@ -35,12 +35,11 @@ class SalesInProvinceLogic extends GetxController {
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
Rxn<Jalali?> productionData = Rxn();
Rxn<ProductModel> selectedProductModel = Rxn<ProductModel>();
Rxn<GuildModel> selectedGuildModel = Rxn<GuildModel>();
Rxn<GuildProfile> guildProfile = Rxn<GuildProfile>();
RxInt saleType = 1.obs;
RxInt priceType = 1.obs;
RxInt priceType = 2.obs;
RxInt quotaType = 1.obs;
RxInt weight = 0.obs;
RxInt pricePerKilo = 0.obs;
@@ -59,6 +58,10 @@ class SalesInProvinceLogic extends GetxController {
Rxn<AllocatedMadeModel> selectedAllocationModelForUpdate = Rxn<AllocatedMadeModel>();
SubmitStewardAllocation? tmpStewardAllocation;
Rxn<Jalali> productionDate = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
super.onInit();
@@ -97,6 +100,7 @@ class SalesInProvinceLogic extends GetxController {
totalCost,
selectedProductModel,
selectedGuildModel,
productionDate,
], (callback) => checkVerification());
scrollControllerAllocationsMade.addListener(() {
@@ -112,6 +116,45 @@ class SalesInProvinceLogic extends GetxController {
(callback) => getAllocatedMade(),
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 {
@@ -168,10 +211,18 @@ class SalesInProvinceLogic extends GetxController {
}
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 =
weight.value > 0 &&
pricePerKilo.value > 0 &&
totalCost.value > 0 &&
hasWeight &&
selectedProductModel.value != null &&
selectedGuildModel.value != null;
}
@@ -285,7 +336,7 @@ class SalesInProvinceLogic extends GetxController {
weightOfCarcasses: weight.value,
sellType: saleType.value == 2 ? "free" : 'exclusive',
numberOfCarcasses: 0,
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
quota: quotaType.value == 1 ? 'governmental' : 'free',
guildKey: selectedGuildModel.value?.key,
productKey: selectedProductModel.value?.key,
@@ -308,6 +359,8 @@ class SalesInProvinceLogic extends GetxController {
clearForm();
onRefresh();
rootLogic.onRefresh();
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ثبت موفق بود"));
Get.back();
},
onError: (error, stackTrace) {},
);
@@ -345,7 +398,7 @@ class SalesInProvinceLogic extends GetxController {
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
totalCostController.text = totalCost.value.toString().separatedByComma;
isValid.value = true;
productionData.value = item.productionDate.toJalali;
productionDate.value = item.productionDate.toJalali;
}
void clearForm() {
@@ -359,7 +412,10 @@ class SalesInProvinceLogic extends GetxController {
}
totalCostController.clear();
isValid.value = false;
productionData.value = null;
productionDate.value = null;
quotaType.value = 1;
priceType.value = 2;
saleType.value = 2;
}
Future<void> updateAllocation() async {
@@ -382,6 +438,8 @@ class SalesInProvinceLogic extends GetxController {
clearForm();
onRefresh();
rootLogic.onRefresh();
Future.delayed(Duration(seconds: 1), () => defaultShowSuccessMessage("ویرایش موفق بود"));
Get.back();
},
onError: (error, stackTrace) {},
);
@@ -427,6 +485,7 @@ class SalesInProvinceLogic extends GetxController {
if (broadcastPrice.value?.active == true) {
pricePerKilo.value = broadcastPrice.value?.stewardPrice ?? 0;
pricePerKiloController.text = pricePerKilo.value.toString().separatedByComma;
priceType.value = 2;
}
},
onError: (error, stacktrace) {},

View File

@@ -404,7 +404,7 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
Widget addOrEditBottomSheet([bool isEditMode = false]) {
return BaseBottomSheet(
height: Get.height * (isEditMode ? 0.55 : 0.75),
height: Get.height * (isEditMode ? 0.60 : 0.75),
child: Form(
key: controller.formKey,
child: Column(
@@ -528,32 +528,25 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
label: 'وزن لاشه (کیلوگرم)',
),
ObxValue((data) {
return RTextField(
controller: TextEditingController(),
filledColor: AppColor.bgLight,
filled: true,
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
onTap: () {
Get.bottomSheet(
modalDatePicker((value) {
controller.productionData.value = value;
controller.productionData.refresh();
}),
);
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) {
controller.productionDate.value = value.date;
},
borderColor: AppColor.darkGreyLight,
initText: data.value?.formatCompactDate(),
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}, controller.productionData),
}),
Visibility(
visible: isEditMode == false,
child: Column(
spacing: 12,
children: [
SizedBox(height: 12.h),
SizedBox(height: 12),
Container(
height: 58.h,
height: 50.h,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
@@ -574,26 +567,102 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
return RadioGroup(
groupValue: controller.quotaType.value,
onChanged: (value) {
controller.quotaType.value = value!;
controller.quotaType.value = value ?? 0;
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: Row(
children: [
Radio(value: 1),
Text('انبار دولتی', style: AppFonts.yekan14),
],
child: GestureDetector(
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(
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(
child: Row(
children: [
Radio(value: 2),
Text('انبار آزاد', style: AppFonts.yekan14),
],
child: GestureDetector(
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(
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(
height: 58.h,
clipBehavior: Clip.none,
@@ -631,20 +700,46 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
child: Row(
children: [
Expanded(
child: Row(
children: [
Radio(value: 1),
Text('قیمت دولتی', style: AppFonts.yekan14),
],
child: GestureDetector(
onTap: (controller.broadcastPrice.value?.active ?? false)
? () {
controller.priceType.value = 1;
}
: null,
child: Row(
children: [
Radio(
value: 1,
enabled:
controller.broadcastPrice.value?.active ??
false,
),
Text(
'قیمت دولتی',
style: AppFonts.yekan14.copyWith(
color:
(controller.broadcastPrice.value?.active ??
false)
? AppColor.textColor
: AppColor.labelTextColor,
),
),
],
),
),
),
Expanded(
child: Row(
children: [
Radio(value: 2),
Text('قیمت آزاد', style: AppFonts.yekan14),
],
child: GestureDetector(
onTap: () {
controller.priceType.value = 2;
},
child: Row(
children: [
Radio(value: 2),
Text('قیمت آزاد', style: AppFonts.yekan14),
],
),
),
),
],
@@ -657,30 +752,25 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
],
),
),
Obx(() {
return Visibility(
visible: controller.broadcastPrice.value?.active == true,
child: RTextField(
variant: RTextFieldVariant.noBorder,
controller: controller.pricePerKiloController,
borderColor: AppColor.darkGreyLight,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
filledColor: AppColor.bgLight,
filled: true,
enabled:
(controller.priceType.value == 2 ||
(controller.selectedProductModel.value?.approvedPriceStatus == false)),
onChanged: (p0) {
controller.pricePerKilo.value = int.tryParse(p0.clearComma) ?? 0;
},
keyboardType: TextInputType.number,
label: 'قیمت هر کیلو (ريال)',
),
);
}),
RTextField(
variant: RTextFieldVariant.noBorder,
controller: controller.pricePerKiloController,
borderColor: AppColor.darkGreyLight,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
SeparatorInputFormatter(),
],
filledColor: AppColor.bgLight,
filled: true,
enabled:
(controller.priceType.value == 2 ||
(controller.selectedProductModel.value?.approvedPriceStatus == false)),
onChanged: (p0) {
controller.pricePerKilo.value = int.tryParse(p0.clearComma) ?? 0;
},
keyboardType: TextInputType.number,
label: 'قیمت هر کیلو (ريال)',
),
RTextField(
variant: RTextFieldVariant.noBorder,
@@ -711,11 +801,9 @@ class SalesInProvincePage extends GetView<SalesInProvinceLogic> {
onPressed: isEditMode
? () async {
await controller.updateAllocation();
Get.back();
}
: () async {
await controller.submitAllocation();
Get.back();
},
);
}, controller.isValid),

View File

@@ -1,5 +1,6 @@
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/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/out_province_carcasses_buyer/out_province_carcasses_buyer.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();
RxBool isLoadingMoreAllocationsMade = false.obs;
Rxn<IranProvinceCityModel> selectedCity = Rxn();
Rxn<Jalali?> productionData = Rxn();
Rxn<BroadcastPrice> broadcastPrice = Rxn<BroadcastPrice>();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController quarantineCodeController = TextEditingController();
TextEditingController saleWeightController = TextEditingController();
@@ -46,6 +47,9 @@ class SalesOutOfProvinceLogic extends GetxController {
RxInt saleType = 2.obs;
RxInt quotaType = 1.obs;
Rxn<Jalali> productionDate = Rxn();
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
@@ -57,6 +61,7 @@ class SalesOutOfProvinceLogic extends GetxController {
void onReady() {
super.onReady();
getOutProvinceSales();
getBroadcastPrice();
selectedProduct.value = rootLogic.rolesProductsModel.first;
debounce(
searchedValue,
@@ -64,6 +69,46 @@ class SalesOutOfProvinceLogic extends GetxController {
time: Duration(milliseconds: timeDebounce),
);
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) {
@@ -151,7 +196,7 @@ class SalesOutOfProvinceLogic extends GetxController {
saleType.value = item.saleType == 'free' ? 2 : 1;
quotaType.value = item.quota == 'governmental' ? 1 : 2;
isSaleSubmitButtonEnabled.value = true;
productionData.value = item.productionDate.toJalali;
productionDate.value = item.productionDate.toJalali;
}
Future<void> deleteStewardPurchaseOutOfProvince(String key) async {
@@ -174,6 +219,7 @@ class SalesOutOfProvinceLogic extends GetxController {
productKey: selectedProduct.value?.key,
saleType: saleType.value == 2 ? 'free' : 'exclusive',
quota: quotaType.value == 1 ? 'governmental' : 'free',
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
);
await safeCall(
showError: true,
@@ -185,6 +231,11 @@ class SalesOutOfProvinceLogic extends GetxController {
res = true;
onRefresh();
rootLogic.onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
);
Get.back();
},
);
return res;
@@ -194,9 +245,9 @@ class SalesOutOfProvinceLogic extends GetxController {
quarantineCodeController.clear();
saleWeightController.clear();
saleDate.value = Jalali.now();
productionData.value = null;
productionDate.value = null;
saleType.value = 2;
quotaType.value = 1;
quotaType.value = 2;
selectedBuyer.value = null;
}
@@ -219,6 +270,11 @@ class SalesOutOfProvinceLogic extends GetxController {
onSuccess: (_) {
res = true;
onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("عملیات با موفقیت انجام شد"),
);
Get.back();
},
);
return res;
@@ -246,4 +302,16 @@ class SalesOutOfProvinceLogic extends GetxController {
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) {},
);
}
}

View File

@@ -324,7 +324,7 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
Widget addOrEditSaleBottomSheet([bool isOnEdit = false]) {
return BaseBottomSheet(
height: 600.h,
height: 670.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
@@ -357,13 +357,12 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
Get.bottomSheet(
modalDatePicker((value) {
controller.saleDate.value = value;
controller.saleDate.refresh();
}),
);
},
borderColor: AppColor.darkGreyLight,
initText: data.value?.formatCompactDate(),
initText: data.value.formatCompactDate(),
);
}, controller.saleDate),
Visibility(visible: isOnEdit == false, child: _buyerWidget()),
@@ -386,24 +385,18 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
child: Column(
spacing: 12,
children: [
ObxValue((data) {
return RTextField(
controller: TextEditingController(),
filledColor: AppColor.bgLight,
filled: true,
Obx(() {
return MonthlyDataCalendar(
label: 'تاریخ تولید گوشت',
onTap: () {
Get.bottomSheet(
modalDatePicker((value) {
controller.productionData.value = value;
controller.productionData.refresh();
}),
);
selectedDate: controller.productionDate.value?.formatCompactDate(),
onDateSelect: (value) {
controller.productionDate.value = value.date;
},
borderColor: AppColor.darkGreyLight,
initText: data.value?.formatCompactDate(),
dayData: controller.quotaType.value == 1
? controller.governmentalProductionDateData
: controller.freeProductionDateData,
);
}, controller.productionData),
}),
Container(
height: 50.h,
@@ -434,13 +427,46 @@ class SalesOutOfProvincePage extends GetView<SalesOutOfProvinceLogic> {
children: [
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 1;
},
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(value: 1),
Text('انبار دولتی', style: AppFonts.yekan14),
Radio(
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(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 2;
},
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(value: 2),
Text('انبار آزاد', style: AppFonts.yekan14),
Radio(
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: [
Expanded(
child: GestureDetector(
onTap: () {
controller.saleType.value = 1;
},
onTap:
(controller.broadcastPrice.value?.active ?? false)
? () {
controller.saleType.value = 1;
}
: null,
child: Row(
children: [
Radio(value: 1),
Text('قیمت دولتی', style: AppFonts.yekan14),
Radio(
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
? () async {
var res = isOnEdit ? await controller.editSale() : await controller.createSale();
if (res) {
Get.back();
}
}
: null,
height: 40,

View File

@@ -23,7 +23,7 @@ class SegmentationLogic extends GetxController {
RxnString searchedValue = RxnString();
RxInt segmentType = 1.obs;
RxInt saleType = 2.obs;
RxInt quotaType = 1.obs;
RxInt quotaType = 2.obs;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
TextEditingController weightController = TextEditingController(text: '0');
RxBool isSubmitButtonEnabled = false.obs;
@@ -35,9 +35,12 @@ class SegmentationLogic extends GetxController {
Resource<PaginationModel<SegmentationModel>>.loading().obs;
RxList<GuildModel> guildsModel = <GuildModel>[].obs;
Rxn<Jalali?> productionData = Rxn();
Rx<Jalali> saleDate = Jalali.now().obs;
Rxn<Jalali?> productionDate = Rxn(null);
Map<String, DayData> freeProductionDateData = {};
Map<String, DayData> governmentalProductionDateData = {};
@override
void onInit() {
super.onInit();
@@ -45,6 +48,46 @@ class SegmentationLogic extends GetxController {
once(rootLogic.rolesProductsModel, (callback) => selectedProduct.value = callback.first);
getAllSegmentation();
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
@@ -55,7 +98,6 @@ class SegmentationLogic extends GetxController {
@override
void onClose() {
// TODO: implement onClose
super.onClose();
}
@@ -69,7 +111,8 @@ class SegmentationLogic extends GetxController {
(callback) => getAllSegmentation(),
time: Duration(milliseconds: timeDebounce),
);
ever(selectedSegment, (_) {
everAll([selectedSegment, quotaType, saleType], (_) {
validateForm();
});
@@ -85,17 +128,26 @@ class SegmentationLogic extends GetxController {
weightController.text = '0';
selectedSegment.value = null;
selectedGuildModel.value = null;
productionData.value = null;
productionDate.value = Jalali.now();
segmentType.value = 1;
saleType.value = 1;
saleType.value = 2;
quotaType.value = 1;
}
void validateForm() {
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 =
selectedProduct.value != null &&
weightController.text.isNotEmpty &&
hasWeight &&
weight! > 0 &&
(segmentType.value == 1 || (segmentType.value == 2 && selectedGuildModel.value != null));
}
@@ -115,7 +167,6 @@ class SegmentationLogic extends GetxController {
await safeCall(
showError: true,
showSuccess: true,
call: () async => await rootLogic.chickenRepository.getSegmentation(
token: rootLogic.tokenService.accessToken.value!,
queryParameters: buildQueryParams(
@@ -171,7 +222,7 @@ class SegmentationLogic extends GetxController {
model: SegmentationModel(
key: selectedSegment.value?.key,
weight: int.tryParse(weightController.text.clearComma) ?? 0,
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
),
),
onSuccess: (result) {
@@ -196,22 +247,24 @@ class SegmentationLogic extends GetxController {
if (segmentType.value == 2) {
segmentationModel = segmentationModel.copyWith(guildKey: selectedGuildModel.value?.key);
}
if (productionData.value != null) {
segmentationModel = segmentationModel.copyWith(
productionDate: productionData.value?.toDateTime().formattedDashedGregorian,
);
}
segmentationModel = segmentationModel.copyWith(
productionDate: productionDate.value?.toDateTime().formattedDashedGregorian,
);
await safeCall(
showError: true,
showSuccess: true,
call: () async => await rootLogic.chickenRepository.createSegmentation(
token: rootLogic.tokenService.accessToken.value!,
model: segmentationModel,
),
onSuccess: (result) {
onSuccess: (result) async {
res = true;
isSubmitButtonEnabled.value = true;
isSubmitButtonEnabled.value = false;
onRefresh();
Future.delayed(
Duration(seconds: 1),
() => defaultShowSuccessMessage("قطعه‌بندی با موفقیت ثبت شد!"),
);
Get.back();
},
onError: (error, stacktrace) {
res = false;
@@ -241,6 +294,8 @@ class SegmentationLogic extends GetxController {
currentPage.value = 1;
await rootLogic.onRefresh();
await getAllSegmentation();
_updateFreeProductionDateData();
_updateGovernmentalProductionDateData();
}
void toggleExpansion({int? index}) {

View File

@@ -10,6 +10,10 @@ import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class SegmentationPage extends GetView<SegmentationLogic> {
final today = Jalali.now();
final oneDayAgo = Jalali.now().addDays(-1);
final twoDaysAgo = Jalali.now().addDays(-2);
@override
Widget build(BuildContext context) {
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(
height: 50.h,
@@ -458,13 +444,46 @@ class SegmentationPage extends GetView<SegmentationLogic> {
children: [
Expanded(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 1;
},
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalGovernmentalRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 1;
}
: null,
child: Row(
children: [
Radio(value: 1),
Text('انبار دولتی', style: AppFonts.yekan14),
Radio(
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(
child: GestureDetector(
onTap: () {
controller.quotaType.value = 2;
},
onTap:
(controller
.rootLogic
.stewardSalesInfoDashboard
.value
?.totalFreeRemainWeight ??
-1) >
0
? () {
controller.quotaType.value = 2;
}
: null,
child: Row(
children: [
Radio(value: 2),
Text('انبار آزاد', style: AppFonts.yekan14),
Radio(
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) {
Jalali currentDate = Jalali.now();
Jalali? tempPickedDate;
return Container(
height: 250,
@@ -652,6 +716,14 @@ class SegmentationPage extends GetView<SegmentationLogic> {
child: PersianCupertinoDatePicker(
initialDateTime: controller.saleDate.value,
mode: PersianCupertinoDatePickerMode.date,
maximumDate: currentDate.addDays(3),
minimumDate: currentDate
.toDateTime()
.subtract(Duration(days: 1))
.toString()
.toJalali,
maximumYear: currentDate.year,
minimumYear: currentDate.year,
onDateTimeChanged: (dateTime) {
tempPickedDate = dateTime;
},

View 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}';
}
}

View File

@@ -37,6 +37,7 @@ export 'loading/loading_widget.dart';
// other
export 'logo_widget.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_logic.dart';
export 'overlay_dropdown_widget/overlay_dropdown.dart';

View File

@@ -67,7 +67,7 @@ Future<T?> gSafeCall<T>({
if (error is DioException && error.response?.statusCode == 401) {
if (showError) {
(onShowErrorMessage ?? _defaultShowErrorMessage)('خطا در احراز هویت');
(onShowErrorMessage ?? defaultShowErrorMessage)('خطا در احراز هویت');
}
onError?.call(error, stackTrace);
return null;
@@ -76,7 +76,7 @@ Future<T?> gSafeCall<T>({
if (retryCount > maxRetries || !_isRetryableError(error)) {
if (showError) {
final message = _getErrorMessage(error);
(onShowErrorMessage ?? _defaultShowErrorMessage)(message);
(onShowErrorMessage ?? defaultShowErrorMessage)(message);
}
onError?.call(error, stackTrace);
return null;
@@ -171,7 +171,7 @@ void defaultShowSuccessMessage(
);
}
void _defaultShowErrorMessage(String message) {
void defaultShowErrorMessage(String message) {
Get.snackbar(
'خطا',
message,

View File

@@ -101,10 +101,10 @@ packages:
dependency: "direct dev"
description:
name: build_runner
sha256: "4e54dbeefdc70691ba80b3bce3976af63b5425c8c07dface348dfee664a0edc1"
sha256: a9461b8e586bf018dd4afd2e13b49b08c6a844a4b226c8d1d10f3a723cdd78c3
url: "https://pub.dev"
source: hosted
version: "2.9.0"
version: "2.10.1"
built_collection:
dependency: transitive
description:
@@ -739,10 +739,10 @@ packages:
dependency: transitive
description:
name: hive_ce
sha256: d678b1b2e315c18cd7ed8fd79eda25d70a1f3852d6988bfe5461cffe260c60aa
sha256: "81d39a03c4c0ba5938260a8c3547d2e71af59defecea21793d57fc3551f0d230"
url: "https://pub.dev"
source: hosted
version: "2.14.0"
version: "2.15.1"
hive_ce_flutter:
dependency: transitive
description:
@@ -755,10 +755,10 @@ packages:
dependency: "direct dev"
description:
name: hive_ce_generator
sha256: "8c677690c8ead43778ddf7ed8ff17e852dd5d22d082c75182b072842c0dc5055"
sha256: b19ac263cb37529513508ba47352c41e6de72ba879952898d9c18c9c8a955921
url: "https://pub.dev"
source: hosted
version: "1.9.5"
version: "1.10.0"
http:
dependency: transitive
description:

View File

@@ -1,7 +1,7 @@
name: rasadyar_app
description: "A new Flutter project."
publish_to: 'none'
version: 1.3.28+25
version: 1.3.29+26
environment:
sdk: ^3.9.2
@@ -38,8 +38,8 @@ dev_dependencies:
sdk: flutter
flutter_lints: ^6.0.0
##code generation
build_runner: ^2.9.0
hive_ce_generator: ^1.9.5
build_runner: ^2.10.1
hive_ce_generator: ^1.10.0
freezed: ^3.2.3
json_serializable: ^6.11.1
flutter_gen_runner: ^5.12.0