Compare commits

7 Commits

114 changed files with 8057 additions and 2521 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

View File

@@ -1,10 +1,6 @@
import 'package:rasadyar_chicken/data/common/dio_error_handler.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/common/data/di/common_di.dart';
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote_impl.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository_impl.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/di/poultry_science_di.dart';
import 'package:rasadyar_chicken/features/steward/data/di/steward_di.dart';
import 'package:rasadyar_chicken/features/province_operator/data/di/province_operator_di.dart';
@@ -86,14 +82,7 @@ Future<void> setupChickenDI() async {
// Setup jahad feature DI
await setupJahadDI(diChicken, dioRemote);
//region kill house module DI
diChicken.registerLazySingleton<KillHouseRemoteDataSource>(
() => KillHouseRemoteDataSourceImpl(diChicken.get<DioRemote>()),
);
diChicken.registerLazySingleton<KillHouseRepository>(
() => KillHouseRepositoryImpl(diChicken.get<KillHouseRemoteDataSource>()),
);
//endregion
}
Future<void> newSetupAuthDI(String newUrl) async {

View File

@@ -1,244 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/common/dio_error_handler.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository.dart';
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/features/steward/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/widget/captcha/logic.dart';
import 'package:rasadyar_core/core.dart';
enum AuthType { useAndPass, otp }
enum AuthStatus { init }
enum OtpStatus { init, sent, verified, reSend }
class AuthLogic extends GetxController with GetTickerProviderStateMixin {
GlobalKey<FormState> formKey = GlobalKey<FormState>();
late AnimationController _textAnimationController;
late Animation<double> textAnimation;
RxBool showCard = false.obs;
RxBool rememberMe = false.obs;
Rx<GlobalKey<FormState>> formKeyOtp = GlobalKey<FormState>().obs;
Rx<GlobalKey<FormState>> formKeySentOtp = GlobalKey<FormState>().obs;
Rx<TextEditingController> usernameController = TextEditingController().obs;
Rx<TextEditingController> passwordController = TextEditingController().obs;
Rx<TextEditingController> phoneOtpNumberController =
TextEditingController().obs;
Rx<TextEditingController> otpCodeController = TextEditingController().obs;
var captchaController = Get.find<CaptchaWidgetLogic>();
RxnString phoneNumber = RxnString(null);
RxBool isLoading = false.obs;
RxBool isDisabled = true.obs;
GService gService = Get.find<GService>();
TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
Rx<AuthType> authType = AuthType.useAndPass.obs;
Rx<AuthStatus> authStatus = AuthStatus.init.obs;
Rx<OtpStatus> otpStatus = OtpStatus.init.obs;
RxnString deviceName = RxnString(null);
RxInt secondsRemaining = 120.obs;
Timer? _timer;
AuthRepository authRepository = diChicken.get<AuthRepository>();
final Module _module = Get.arguments;
@override
void onInit() {
super.onInit();
_textAnimationController =
AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
)
..repeat(reverse: true, count: 2).whenComplete(() {
showCard.value = true;
});
textAnimation = CurvedAnimation(
parent: _textAnimationController,
curve: Curves.easeInOut,
);
initUserPassData();
getDeviceModel();
}
@override
void onClose() {
_textAnimationController.dispose();
_timer?.cancel();
super.onClose();
}
void startTimer() {
_timer?.cancel();
secondsRemaining.value = 120;
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (secondsRemaining.value > 0) {
secondsRemaining.value--;
} else {
timer.cancel();
}
});
}
void stopTimer() {
_timer?.cancel();
}
String get timeFormatted {
final minutes = secondsRemaining.value ~/ 60;
final seconds = secondsRemaining.value % 60;
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}
bool _isFormValid() {
final isCaptchaValid =
captchaController.formKey.currentState?.validate() ?? false;
final isFormValid = formKey.currentState?.validate() ?? false;
return isCaptchaValid && isFormValid;
}
Future<void> submitLoginForm() async {
if (!_isFormValid()) return;
AuthRepository authTmp = diChicken.get<AuthRepository>();
isLoading.value = true;
await safeCall<UserProfileModel?>(
call: () => authTmp.login(
authRequest: {
"username": usernameController.value.text,
"password": passwordController.value.text,
},
),
onSuccess: (result) async {
await gService.saveSelectedModule(_module);
await tokenStorageService.saveModule(_module);
await tokenStorageService.saveAccessToken(
_module,
result?.accessToken ?? '',
);
await tokenStorageService.saveRefreshToken(
_module,
result?.accessToken ?? '',
);
var tmpRoles = result?.role?.where((element) {
final allowedRoles = {
'poultryscience',
'steward',
'killhouse',
'provinceinspector',
'cityjahad',
'jahad',
'vetfarm',
'provincesupervisor',
'superadmin',
};
final lowerElement = element.toString().toLowerCase().trim();
return allowedRoles.contains(lowerElement);
}).toList();
if (tmpRoles?.length==1) {
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
}
await tokenStorageService.saveRoles(_module, tmpRoles ?? []);
if (rememberMe.value) {
await tokenStorageService.saveUserPass(
_module,
usernameController.value.text,
passwordController.value.text,
);
}
authTmp.stewardAppLogin(
token: result?.accessToken ?? '',
queryParameters: {
"mobile": usernameController.value.text,
"device_name": deviceName.value,
},
);
Get.offAndToNamed(CommonRoutes.role);
/* if (tmpRoles!.length > 1) {
Get.offAndToNamed(CommonRoutes.role);
} else {
Get.offAllNamed(StewardRoutes.initSteward);
} */
},
onError: (error, stackTrace) {
if (error is DioException) {
diChicken.get<DioErrorHandler>().handle(error);
if ((error.type == DioExceptionType.unknown) ||
(error.type == DioExceptionType.connectionError)) {
getUserInfo(usernameController.value.text);
}
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
Future<void> getUserInfo(String value) async {
isLoading.value = true;
await safeCall<UserInfoModel?>(
call: () async => await authRepository.getUserInfo(value),
onSuccess: (result) async {
if (result != null) {
await newSetupAuthDI(result.backend ?? '');
await diChicken.allReady();
}
},
onError: (error, stackTrace) {
if (error is DioException) {
diChicken.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
void initUserPassData() {
UserLocalModel? userLocalModel = tokenStorageService.getUserLocal(
Module.chicken,
);
if (userLocalModel?.username != null && userLocalModel?.password != null) {
usernameController.value.text = userLocalModel?.username ?? '';
passwordController.value.text = userLocalModel?.password ?? '';
rememberMe.value = true;
}
}
Future<void> getDeviceModel() async {
final deviceInfo = DeviceInfoPlugin();
if (Platform.isAndroid) {
final info = await deviceInfo.androidInfo;
deviceName.value =
'Device:${info.manufacturer} Model:${info.model} version ${info.version.release}';
} else if (Platform.isIOS) {
final info = await deviceInfo.iosInfo;
deviceName.value =
'Device:${info.utsname.machine} Model:${info.model} version ${info.systemVersion}';
} else {}
}
}

View File

@@ -1,257 +0,0 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/common/data/model/request/change_password/change_password_request_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/iran_province_city/iran_province_city_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/common/common_repository.dart';
import 'package:rasadyar_core/core.dart';
class ProfileLogic extends GetxController {
CommonRepository commonRepository = diChicken.get<CommonRepository>();
GService gService = Get.find<GService>();
TokenStorageService tokenService = Get.find<TokenStorageService>();
RxInt selectedInformationType = 0.obs;
Rxn<Jalali> birthDate = Rxn<Jalali>();
Rx<Resource<UserProfile>> userProfile = Rx<Resource<UserProfile>>(
Resource.loading(),
);
Rx<Resource<UserLocalModel>> userLocal = Rx<Resource<UserLocalModel>>(
Resource.loading(),
);
TextEditingController nameController = TextEditingController();
TextEditingController lastNameController = TextEditingController();
TextEditingController nationalCodeController = TextEditingController();
TextEditingController nationalIdController = TextEditingController();
TextEditingController birthdayController = TextEditingController();
TextEditingController oldPasswordController = TextEditingController();
TextEditingController newPasswordController = TextEditingController();
TextEditingController retryNewPasswordController = TextEditingController();
RxList<IranProvinceCityModel> cites = <IranProvinceCityModel>[].obs;
Rxn<IranProvinceCityModel> selectedProvince = Rxn();
Rxn<IranProvinceCityModel> selectedCity = Rxn();
GlobalKey<FormState> formKey = GlobalKey();
ImagePicker imagePicker = ImagePicker();
Rxn<XFile> selectedImage = Rxn<XFile>();
final RxnString _base64Image = RxnString();
RxBool isOnLoading = false.obs;
RxBool isUserInformationOpen = true.obs;
RxBool isUnitInformationOpen = false.obs;
ScrollController scrollController = ScrollController();
@override
void onInit() {
super.onInit();
ever(selectedImage, (data) async {
if (data?.path != null) {
_base64Image.value = await convertImageToBase64(data!.path);
}
});
}
@override
void onReady() {
super.onReady();
getUserProfile();
getUserRole();
selectedProvince.listen((p0) => getCites());
userProfile.listen((data) {
nameController.text = data.data?.firstName ?? '';
lastNameController.text = data.data?.lastName ?? '';
nationalCodeController.text = data.data?.nationalCode ?? '';
nationalIdController.text = data.data?.nationalId ?? '';
birthdayController.text =
data.data?.birthday?.toJalali.formatCompactDate() ?? '';
birthDate.value = data.data?.birthday?.toJalali;
selectedProvince.value = IranProvinceCityModel(
name: data.data?.province ?? '',
id: data.data?.provinceNumber ?? 0,
);
selectedCity.value = IranProvinceCityModel(
name: data.data?.city ?? '',
id: data.data?.cityNumber ?? 0,
);
});
}
Future<void> getUserProfile() async {
userProfile.value = Resource.loading();
await safeCall<UserProfile?>(
call: () async => await commonRepository.getUserProfile(
token: tokenService.accessToken.value!,
),
onSuccess: (result) {
if (result != null) {
userProfile.value = Resource.success(result);
}
},
onError: (error, stackTrace) {},
);
}
Future<void> getCites() async {
await safeCall(
call: () => commonRepository.getCity(
provinceName: selectedProvince.value?.name ?? '',
),
onSuccess: (result) {
if (result != null && result.isNotEmpty) {
cites.value = result;
}
},
);
}
Future<void> updateUserProfile() async {
UserProfile userProfile = UserProfile(
firstName: nameController.text,
lastName: lastNameController.text,
nationalCode: nationalCodeController.text,
nationalId: nationalIdController.text,
birthday: birthDate.value
?.toDateTime()
.formattedDashedGregorian
.toString(),
image: _base64Image.value,
personType: 'self',
type: 'self_profile',
);
isOnLoading.value = true;
await safeCall(
call: () async => await commonRepository.updateUserProfile(
token: tokenService.accessToken.value!,
userProfile: userProfile,
),
onSuccess: (result) {
isOnLoading.value = false;
},
onError: (error, stackTrace) {
isOnLoading.value = false;
},
);
}
Future<void> updatePassword() async {
if (formKey.currentState?.validate() ?? false) {
ChangePasswordRequestModel model = ChangePasswordRequestModel(
username: userProfile.value.data?.mobile,
password: newPasswordController.text,
);
await safeCall(
call: () async => await commonRepository.updatePassword(
token: tokenService.accessToken.value!,
model: model,
),
);
}
}
Future<void> getUserRole() async {
userLocal.value = Resource.loading();
await safeCall<UserLocalModel?>(
call: () async => tokenService.getUserLocal(Module.chicken),
onSuccess: (result) {
if (result != null) {
userLocal.value = Resource.success(result);
}
},
onError: (error, stackTrace) {},
);
}
void clearPasswordForm() {
oldPasswordController.clear();
newPasswordController.clear();
retryNewPasswordController.clear();
}
Future<void> changeUserRole(String newRole) async {
dLog(newRole);
await gService.saveRoute(Module.chicken, newRole);
Get.offAllNamed(newRole);
}
void scrollToSelectedItem(
int index, {
double chipWidth = 100,
double spacing = 8,
GlobalKey? itemKey,
}) {
if (!scrollController.hasClients) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_performScroll(index, chipWidth, spacing, itemKey);
});
} else {
_performScroll(index, chipWidth, spacing, itemKey);
}
}
void _performScroll(
int index,
double chipWidth,
double spacing,
GlobalKey? itemKey,
) {
if (!scrollController.hasClients) return;
double targetOffset;
// If we have a GlobalKey, use it for precise positioning
if (itemKey?.currentContext != null) {
final RenderBox? renderBox =
itemKey!.currentContext?.findRenderObject() as RenderBox?;
if (renderBox != null) {
final position = renderBox.localToGlobal(Offset.zero);
final scrollPosition = scrollController.position;
final viewportWidth = scrollPosition.viewportDimension;
final chipWidth = renderBox.size.width;
// Get the scroll position of the item
final itemScrollPosition = position.dx - scrollPosition.pixels;
// Center the item
targetOffset =
scrollPosition.pixels +
itemScrollPosition -
(viewportWidth / 2) +
(chipWidth / 2);
} else {
// Fallback to estimated position
targetOffset = _calculateEstimatedPosition(index, chipWidth, spacing);
}
} else {
// Use estimated position
targetOffset = _calculateEstimatedPosition(index, chipWidth, spacing);
}
scrollController.animateTo(
targetOffset.clamp(0.0, scrollController.position.maxScrollExtent),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
);
}
double _calculateEstimatedPosition(
int index,
double chipWidth,
double spacing,
) {
final double itemPosition = (chipWidth + spacing) * index;
final double viewportWidth = scrollController.position.viewportDimension;
return itemPosition - (viewportWidth / 2) + (chipWidth / 2);
}
@override
void onClose() {
scrollController.dispose();
super.onClose();
}
}

View File

@@ -1,902 +0,0 @@
import 'dart:io';
import 'package:flutter/cupertino.dart' hide Image;
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/common/fa_user_role.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile/user_profile.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class ProfilePage extends GetView<ProfileLogic> {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return Column(
spacing: 30,
children: [
Expanded(
child: Container(
color: AppColor.blueNormal,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(),
ObxValue((data) {
final status = data.value.status;
if (status == ResourceStatus.loading) {
return Container(
width: 128.w,
height: 128.h,
child: Center(child: CupertinoActivityIndicator(color: AppColor.greenNormal)),
);
}
if (status == ResourceStatus.error) {
return Container(
width: 128.w,
height: 128.h,
child: Center(child: Text('خطا در دریافت اطلاعات')),
);
}
// Default UI
return Container(
width: 128.w,
height: 128.h,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.blueLightActive,
),
child: Center(
child: data.value.data?.image != null
? CircleAvatar(
radius: 64.w,
backgroundImage: NetworkImage(data.value.data!.image!),
)
: Icon(Icons.person, size: 64.w),
),
);
}, controller.userProfile),
],
),
),
),
Expanded(
flex: 3,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
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 Column(
spacing: 6,
children: [
ObxValue((isOpen) {
return GestureDetector(
onTap: () => isOpen.toggle(),
child: AnimatedContainer(
height: isOpen.value ? 320.h : 47.h,
duration: Duration(milliseconds: 500),
curve: Curves.linear,
child: userProfileInformation(data.value),
),
);
}, controller.isUserInformationOpen),
Visibility(
visible:
data.value.data?.unitName != null ||
data.value.data?.unitAddress != null ||
data.value.data?.unitPostalCode != null ||
data.value.data?.unitRegistrationNumber != null ||
data.value.data?.unitEconomicalNumber != null ||
data.value.data?.unitCity != null ||
data.value.data?.unitProvince != null ||
data.value.data?.unitNationalId != null,
child: ObxValue((isOpen) {
return GestureDetector(
onTap: () => isOpen.toggle(),
child: AnimatedContainer(
height: isOpen.value ? 320.h : 47.h,
duration: Duration(milliseconds: 500),
curve: Curves.linear,
child: unitInformation(data.value),
),
);
}, 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),
),
],
),
),
),
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),
],
),
),
),
],
);
}
Container invoiceIssuanceInformation() => Container();
Widget bankInformationWidget() => Column(
spacing: 16,
children: [
itemList(title: 'نام بانک', content: 'سامان'),
itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'),
itemList(title: 'شماره کارت ', content: '54154545415'),
itemList(title: 'شماره حساب', content: '62565263263652'),
itemList(title: 'شماره شبا', content: '62565263263652'),
],
);
Widget userProfileInformation(Resource<UserProfile> value) {
UserProfile item = value.data!;
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: ObxValue(
(val) => Container(
height: val.value ? 320.h : 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 8 : 0),
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
),
child: val.value
? Column(
spacing: 6,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
Get.bottomSheet(
userInformationBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
);
},
child: Assets.vec.editSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
child: Column(
children: [
itemList(
title: 'نام و نام خانوادگی',
content: item.fullname ?? 'نامشخص',
icon: Assets.vec.userSvg.path,
hasColoredBox: true,
),
itemList(
title: 'کدملی',
content: item.nationalId ?? 'نامشخص',
icon: Assets.vec.tagUserSvg.path,
),
itemList(
title: 'موبایل',
content: item.mobile ?? 'نامشخص',
icon: Assets.vec.callSvg.path,
),
itemList(
title: 'شماره شناسنامه',
content: item.nationalCode ?? 'نامشخص',
icon: Assets.vec.userSquareSvg.path,
),
itemList(
title: 'تاریخ تولد',
content: item.birthday?.toJalali.formatCompactDate() ?? 'نامشخص',
icon: Assets.vec.calendarSvg.path,
),
//todo
itemList(
title: 'استان',
content: item.province ?? 'نامشخص',
icon: Assets.vec.pictureFrameSvg.path,
),
itemList(
title: 'شهر',
content: item.city ?? 'نامشخص',
icon: Assets.vec.mapSvg.path,
),
],
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
),
),
controller.isUserInformationOpen,
),
),
ObxValue(
(isOpen) => AnimatedPositioned(
right: 16,
top: isOpen.value ? -7 : 11,
duration: Duration(milliseconds: 500),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: isOpen.value
? BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
)
: null,
child: Text(
'اطلاعات هویتی',
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
),
),
),
controller.isUserInformationOpen,
),
],
);
}
Widget unitInformation(Resource<UserProfile> value) {
UserProfile item = value.data!;
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: ObxValue(
(val) => Container(
height: val.value ? 320.h : 47.h,
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 12 : 0),
padding: EdgeInsets.symmetric(horizontal: 11.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
),
child: val.value
? Column(
children: [
SizedBox(height: 5.h),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
Get.bottomSheet(
userInformationBottomSheet(),
isScrollControlled: true,
ignoreSafeArea: false,
);
},
child: Assets.vec.editSvg.svg(
width: 24.w,
height: 24.h,
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
child: Column(
spacing: 2,
children: [
itemList(
title: 'نام صنفی',
content: item.unitName ?? 'نامشخص',
hasColoredBox: true,
visible: item.unitName != null,
),
itemList(
title: 'شناسنامه ملی',
content: item.unitNationalId ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'شماره ثبت',
content: item.unitRegistrationNumber ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'کد اقتصادی',
content: item.unitEconomicalNumber ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'کد پستی',
content: item.unitPostalCode ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'استان',
content: item.province ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(
title: 'شهر',
content: item.city ?? 'نامشخص',
visible: item.unitName != null,
),
itemList(title: 'آدرس', content: item.unitAddress ?? 'نامشخص'),
],
),
),
],
)
: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
),
),
controller.isUnitInformationOpen,
),
),
ObxValue(
(isOpen) => AnimatedPositioned(
right: 16,
top: isOpen.value ? -2 : 11,
duration: Duration(milliseconds: 500),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: isOpen.value
? BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
)
: null,
child: Text(
'اطلاعات صنفی',
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
),
),
),
controller.isUnitInformationOpen,
),
],
);
}
Widget itemList({
required String title,
required String content,
String? icon,
bool hasColoredBox = false,
bool? visible,
}) => Visibility(
visible: visible ?? true,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h),
decoration: BoxDecoration(
color: hasColoredBox ? AppColor.greenLight : Colors.transparent,
borderRadius: BorderRadius.circular(8),
border: hasColoredBox
? Border.all(width: 0.25, color: AppColor.bgDark)
: Border.all(width: 0, color: Colors.transparent),
),
child: Row(
spacing: 4,
children: [
if (icon != null)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: SvgGenImage.vec(icon).svg(
width: 20.w,
height: 20.h,
colorFilter: ColorFilter.mode(AppColor.textColor, BlendMode.srcIn),
),
),
Text(title, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
Spacer(),
Text(content, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
],
),
),
);
Widget cardActionWidget({
required String title,
required VoidCallback onPressed,
required String icon,
bool selected = false,
ColorFilter? color,
Color? cardColor,
Color? cardIconColor,
Color? textColor,
}) {
return GestureDetector(
onTap: onPressed,
child: Column(
spacing: 4,
children: [
Container(
width: 52.w,
height: 52.h,
padding: EdgeInsets.all(6),
decoration: ShapeDecoration(
color: cardColor ?? AppColor.blueLight,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: cardIconColor,
borderRadius: BorderRadius.circular(8),
),
child: SvgGenImage.vec(icon).svg(
width: 40.w,
height: 40.h,
colorFilter: color ?? ColorFilter.mode(Colors.white, BlendMode.srcIn),
),
),
),
SizedBox(height: 2),
Text(
title,
style: AppFonts.yekan10.copyWith(color: AppColor.textColor),
textAlign: TextAlign.center,
),
],
),
);
}
Widget userInformationBottomSheet() {
return BaseBottomSheet(
height: 750.h,
child: SingleChildScrollView(
child: Column(
spacing: 8,
children: [
Text(
'ویرایش اطلاعات هویتی',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 12,
children: [
RTextField(
controller: controller.nameController,
label: 'نام',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.lastNameController,
label: 'نام خانوادگی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.nationalCodeController,
label: 'شماره شناسنامه',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
RTextField(
controller: controller.nationalIdController,
label: 'کد ملی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
),
ObxValue((data) {
return RTextField(
controller: controller.birthdayController,
label: 'تاریخ تولد',
initText: data.value?.formatCompactDate() ?? '',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
onTap: () {},
);
}, controller.birthDate),
SizedBox(),
],
),
),
SizedBox(),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.darkGreyLight, width: 1),
),
child: Column(
spacing: 8,
children: [
Text(
'عکس پروفایل',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
),
ObxValue((data) {
return Container(
width: Get.width,
height: 270,
decoration: BoxDecoration(
color: AppColor.lightGreyNormal,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 1, color: AppColor.blackLight),
),
child: Center(
child: data.value == null
? Padding(
padding: const EdgeInsets.fromLTRB(30, 10, 10, 30),
child: Image.network(
controller.userProfile.value.data?.image ?? '',
),
)
: Image.file(File(data.value!.path), fit: BoxFit.cover),
),
);
}, controller.selectedImage),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
text: 'گالری',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
onPressed: () async {
controller.selectedImage.value = await controller.imagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
SizedBox(width: 16),
ROutlinedElevated(
text: 'دوربین',
width: 150.w,
height: 40.h,
textStyle: AppFonts.yekan20.copyWith(color: AppColor.blueNormal),
onPressed: () async {
controller.selectedImage.value = await controller.imagePicker.pickImage(
source: ImageSource.camera,
imageQuality: 60,
maxWidth: 1080,
maxHeight: 720,
);
},
),
],
),
],
),
),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ObxValue((data) {
return RElevated(
height: 40.h,
text: 'ویرایش',
isLoading: data.value,
onPressed: () async {
await controller.updateUserProfile();
controller.getUserProfile();
Get.back();
},
);
}, controller.isOnLoading),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
);
}
Widget changePasswordBottomSheet() {
return BaseBottomSheet(
height: 400.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text(
'تغییر رمز عبور',
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
),
SizedBox(),
RTextField(
controller: controller.oldPasswordController,
hintText: 'رمز عبور قبلی',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (controller.userProfile.value.data?.password != value) {
return 'رمز عبور صحیح نیست';
}
return null;
},
),
RTextField(
controller: controller.newPasswordController,
hintText: 'رمز عبور جدید',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (value.length < 6) {
return 'رمز عبور باید بیش از 6 کارکتر باشد.';
}
return null;
},
),
RTextField(
controller: controller.retryNewPasswordController,
hintText: 'تکرار رمز عبور جدید',
borderColor: AppColor.darkGreyLight,
filledColor: AppColor.bgLight,
filled: true,
validator: (value) {
if (value == null || value.isEmpty) {
return 'رمز عبور را وارد کنید';
} else if (value.length < 6) {
return 'رمز عبور باید بیش از 6 کارکتر باشد.';
} else if (controller.newPasswordController.text != value) {
return 'رمز عبور جدید یکسان نیست';
}
return null;
},
),
SizedBox(),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
height: 40.h,
text: 'ویرایش',
onPressed: () async {
if (controller.formKey.currentState?.validate() != true) {
return;
}
await controller.updatePassword();
controller.getUserProfile();
controller.clearPasswordForm();
Get.back();
},
),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
),
);
}
Widget exitBottomSheet() {
return BaseBottomSheet(
height: 220.h,
child: SingleChildScrollView(
child: Form(
key: controller.formKey,
child: Column(
spacing: 8,
children: [
Text('خروج', style: AppFonts.yekan16Bold.copyWith(color: AppColor.error)),
SizedBox(),
Text(
'آیا مطمئن هستید که می‌خواهید از حساب کاربری خود خارج شوید؟',
textAlign: TextAlign.center,
style: AppFonts.yekan16Bold.copyWith(color: AppColor.textColor),
),
SizedBox(),
Row(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RElevated(
height: 40.h,
text: 'خروج',
backgroundColor: AppColor.error,
onPressed: () async {
await Future.wait([
controller.tokenService.deleteModuleTokens(Module.chicken),
controller.gService.clearSelectedModule(),
]).then((value) async {
await removeChickenDI();
Get.offAllNamed("/moduleList");
});
},
),
ROutlinedElevated(
height: 40.h,
text: 'انصراف',
borderColor: AppColor.blueNormal,
onPressed: () {
Get.back();
},
),
],
),
],
),
),
),
);
}
Widget rolesWidget() {
return ObxValue((data) {
if (data.value.status == ResourceStatus.loading) {
return CupertinoActivityIndicator();
} else if (data.value.status == ResourceStatus.error) {
return ErrorWidget('خطا در دریافت اطلاعات کاربر');
} else if (data.value.status == ResourceStatus.success) {
List<String>? item = data.value.data?.roles;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: 8.w),
physics: BouncingScrollPhysics(),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8.w,
children: List.generate(item?.length ?? 0, (index) {
Map tmpRole = getFaUserRoleWithOnTap(item?[index]);
return CustomChip(
isSelected: controller.gService.getRoute(Module.chicken) == tmpRole.values.first,
title: tmpRole.keys.first,
index: index,
onTap: (int p1) {
controller.changeUserRole(tmpRole.values.first);
},
);
}),
),
);
} else {
return SizedBox.shrink();
}
}, controller.userLocal);
}
}

View File

@@ -1,18 +0,0 @@
import 'package:rasadyar_core/core.dart';
class RoleLogic extends GetxController {
TokenStorageService tokenService = Get.find<TokenStorageService>();
GService gService = Get.find<GService>();
RxList<String> roles = <String>[].obs;
@override
void onInit() {
super.onInit();
List<String> items = tokenService.getUserLocal(Module.chicken)!.roles ?? [];
if (items.isNotEmpty) {
roles.assignAll(items);
}
}
}

View File

@@ -1,79 +0,0 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/common/fa_user_role.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class RolePage extends GetView<RoleLogic> {
const RolePage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
isBase: true,
child: Column(
children: [
Assets.images.selectRole.image(height: 212.h, width: Get.width.w, fit: BoxFit.cover),
ObxValue((data) {
return Expanded(
child: GridView.builder(
physics: BouncingScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 12.h,
crossAxisSpacing: 12.w,
childAspectRatio: 2,
),
itemCount: data.length,
hitTestBehavior: HitTestBehavior.opaque,
itemBuilder: (BuildContext context, int index) {
Map role = getFaUserRoleWithOnTap(data[index]);
return roleCard(
title: role.keys.first,
onTap: () async {
try {
String route = role.values.first;
await controller.gService.saveRoute(Module.chicken, route);
await controller.gService.saveRole(Module.chicken, data[index]);
Get.offAllNamed(route);
} catch (e) {
eLog(
"احتمالا در\n ``getFaUserRoleWithOnTap`` \nروت اش را تعریف نکردی 👻👻 ==>$e ",
);
}
},
);
},
),
);
}, controller.roles),
],
),
);
}
}
Widget roleCard({required String title, Function()? onTap, int? width, int? height}) {
return Container(
width: width?.w ?? 128.w,
height: height?.h ?? 48.h,
margin: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: AppColor.blueNormal, width: 1.w),
),
child: InkWell(
onTap: onTap,
child: Center(
child: Text(
title,
style: AppFonts.yekan12Bold.copyWith(color: AppColor.blueNormal),
textAlign: TextAlign.center,
),
),
),
);
}

View File

@@ -1,9 +1,9 @@
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
abstract class KillHouseRemoteDataSource {

View File

@@ -1,10 +1,10 @@
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {

View File

@@ -1,11 +1,11 @@
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as listModel
show KillRequestList;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/data/model/pagination_model/pagination_model.dart';

View File

@@ -1,11 +1,11 @@
import 'package:rasadyar_chicken/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/data_source/remote/kill_house/kill_house_remote.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as ListModel;
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_core/core.dart';
import 'kill_house_repository.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
import 'package:rasadyar_chicken/features/kill_house/data/repository/kill_house_repository.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/profile/view.dart';
import 'package:rasadyar_chicken/presentation/routes/pages.dart';
import 'package:rasadyar_chicken/presentation/routes/routes.dart';

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/request/kill_request_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/chicken_commission_prices/chicken_commission_prices.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_house/kill_house_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as listModel;
import 'package:rasadyar_chicken/features/kill_house/root/logic.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/register_request/response/kill_request_list/kill_request_list.dart'
import 'package:rasadyar_chicken/features/kill_house/data/model/register_request/response/kill_request_list/kill_request_list.dart'
as listModel
show KillRequestList;
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_core/core.dart';

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_core/core.dart';

View File

@@ -1,7 +1,7 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/root/logic.dart';
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
import 'package:rasadyar_core/core.dart';

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_bars/kill_house_bars_response.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';

View File

@@ -3,9 +3,9 @@ import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:rasadyar_chicken/data/di/chicken_di.dart';
import 'package:rasadyar_chicken/data/models/kill_house_module/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/data/repositories/kill_house/kill_house_repository.dart';
import 'package:rasadyar_chicken/features/common/profile/view.dart';
import 'package:rasadyar_chicken/features/kill_house/data/model/warehouse_and_distribution/response/kill_house_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
import 'package:rasadyar_chicken/features/kill_house/data/repository/kill_house_repository.dart';
import 'package:rasadyar_chicken/features/common/presentation/page/profile/view.dart';
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/buy/view.dart';
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/home/view.dart';
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/view.dart';

View File

@@ -4,7 +4,7 @@ import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/s
import 'package:rasadyar_core/core.dart';
Widget farmInfoWidget({
required CreateInspectionBottomSheetLogic controller,
CreateInspectionBottomSheetLogic? controller,
required String title,
required Widget child,
EdgeInsets? padding,

View File

@@ -1,4 +1,3 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.dart';

View File

@@ -12,4 +12,6 @@ abstract class VetFarmRemoteDataSource {
required String token,
required SubmitInspectionResponse request,
});
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({String? token});
}

View File

@@ -36,4 +36,20 @@ class VetFarmRemoteDataSourceImpl implements VetFarmRemoteDataSource {
data: request.toJson(),
);
}
@override
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({String? token}) async {
DioRemote dio = DioRemote(baseUrl: "http://testbackend.rasadyaar.ir/");
await dio.init();
var res = await dio.get(
'inspection_form_sd_ui/',
fromJson: (json) {
return json;
},
);
return res;
}
}

View File

@@ -12,4 +12,7 @@ abstract class VetFarmRepository {
required String token,
required SubmitInspectionResponse request,
});
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({String? token});
}

View File

@@ -27,4 +27,8 @@ class VetFarmRepositoryImpl implements VetFarmRepository {
}) async {
return await _remote.submitInspection(token: token, request: request);
}
@override
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({String? token}) async {
return await _remote.getSDUIForm(token: token);
}
}

View File

@@ -21,5 +21,10 @@ class VetFarmHomeLogic extends GetxController {
route: VetFarmRoutes.newInspectionVetFarm,
icon: Assets.vec.activeFramSvg.path,
),
VetFarmHomeItem(
title: "صفحه جدید",
route: VetFarmRoutes.newPageVetFarm,
icon: Assets.vec.activeFramSvg.path,
),
].obs;
}

View File

@@ -0,0 +1,131 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/root/logic.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget_model.dart';
import 'package:rasadyar_core/core.dart';
class NewPageLogic extends GetxController {
VetFarmRootLogic rootLogic = Get.find<VetFarmRootLogic>();
Rxn<SDUIWidgetModel> sduiModel = Rxn<SDUIWidgetModel>();
Map<String, TextEditingController> controllers = {};
RxMap<String, dynamic> formState = <String, dynamic>{}.obs;
Map<String, RxList<XFile>> images = {};
@override
void onInit() {
super.onInit();
getSDUIForm();
}
@override
void onReady() {
super.onReady();
// Ready logic here
}
@override
void onClose() {
// Dispose all controllers
for (var controller in controllers.values) {
controller.dispose();
}
controllers.clear();
super.onClose();
}
Future<void> getSDUIForm() async {
await safeCall(
call: () async => await rootLogic.vetFarmRepository.getSDUIForm(),
onSuccess: (result) {
if (result.data != null) {
try {
iLog('SDUI JSON received: ${result.data}');
// Extract SDUI data from info structure
// JSON structure: { "info": { "type": "column", "visible": true, "data": {...}, "children": [...] } }
Map<String, dynamic>? sduiData;
if (result.data!['info'] != null && result.data!['info'] is Map) {
final infoMap = result.data!['info'] as Map<String, dynamic>;
// Check if info has type field (meaning it's the SDUI structure itself)
if (infoMap.containsKey('type')) {
sduiData = infoMap;
iLog(
'SDUI data extracted from info (info contains type field)',
);
} else if (infoMap['data'] != null) {
// Fallback: if info.data exists, use it
sduiData = infoMap['data'] as Map<String, dynamic>;
iLog('SDUI data extracted from info.data');
} else {
iLog('info exists but has no type or data field');
}
} else {
// Fallback: try direct data structure
sduiData = result.data;
iLog('Using direct data structure (no info field)');
}
if (sduiData != null) {
iLog('SDUI data to parse: $sduiData');
sduiModel.value = SDUIWidgetModel.fromJson(sduiData);
iLog(
'SDUI Model parsed successfully. Type: ${sduiModel.value?.type}, Visible: ${sduiModel.value?.visible}, Children count: ${sduiModel.value?.children?.length ?? 0}',
);
_initializeControllers(sduiModel.value!);
} else {
iLog('SDUI data is null after extraction');
}
} catch (e, stackTrace) {
eLog('Error parsing SDUI model: $e');
eLog('Stack trace: $stackTrace');
eLog('JSON data: ${result.data}');
}
} else {
iLog('SDUI result.data is null');
}
},
onError: (error, stackTrace) {
eLog('Error fetching SDUI form: $error');
eLog('Stack trace: $stackTrace');
},
);
}
void _initializeControllers(SDUIWidgetModel model) {
// Extract all text form field keys from the model and create controllers
_extractTextFields(model);
}
void _extractTextFields(SDUIWidgetModel model) {
if (model.type == 'text_form_field' && model.data != null) {
final key = model.data!['key'] as String?;
final value = model.data!['value'] as String?;
if (key != null && !controllers.containsKey(key)) {
controllers[key] = TextEditingController(text: value ?? '');
}
}
if (model.child != null) {
_extractTextFields(SDUIWidgetModel.fromJson(model.child!));
}
if (model.children != null) {
for (var child in model.children!) {
_extractTextFields(SDUIWidgetModel.fromJson(child));
}
}
}
void onButtonPressed() {
// Example: Get all form values
controllers.forEach((key, controller) {
iLog('Field $key: ${controller.text}');
});
// Example: Get all chip selection values
formState.forEach((key, value) {
iLog('State $key: $value');
});
}
}

View File

@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/view.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/form/sdui_form_widget.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class NewPage extends GetView<NewPageLogic> {
const NewPage({super.key});
@override
Widget build(BuildContext context) {
return ChickenBasePage(
hasBack: true,
backId: vetFarmActionKey,
child: contentWidget(),
);
}
Widget contentWidget() {
return SingleChildScrollView(
physics: BouncingScrollPhysics(),
padding: EdgeInsets.all(16.w),
child: Column(
children: [
SizedBox(height: 24.h),
Row(children: []),
SizedBox(height: 24.h),
RElevated(
text: 'دکمه نمونه',
onPressed: () {
Get.bottomSheet(
isScrollControlled: true,
enableDrag: true,
BaseBottomSheet(
height: Get.height * 0.8,
child: ObxValue((data) {
if (data.value == null) {
return Center(child: CircularProgressIndicator());
}
return Obx(
() => SDUIFormWidget(
model: data.value!,
controllers: controller.controllers,
state: controller.formState,
onStateChanged: (key, value) {
controller.formState[key] = value;
},
images: controller.images,
onImagesChanged: (key, imageList) {
controller.images[key] = imageList;
},
),
);
}, controller.sduiModel),
),
);
},
),
SizedBox(height: 24.h),
],
),
);
}
}

View File

@@ -7,6 +7,8 @@ import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/active_hat
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/active_hatching/view.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/new_inspection/logic.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/new_inspection/view.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/new_page/logic.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/new_page/view.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/routes/routes.dart';
import 'package:rasadyar_chicken/presentation/routes/global_binding.dart';
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
@@ -72,5 +74,18 @@ class VetFarmPages {
}),
],
),
GetPage(
name: VetFarmRoutes.newPageVetFarm,
page: () => NewPage(),
middlewares: [AuthMiddleware()],
bindings: [
GlobalBinding(),
BindingsBuilder(() {
Get.lazyPut(() => NewPageLogic());
}),
],
),
];
}

View File

@@ -7,4 +7,5 @@ sealed class VetFarmRoutes {
static const actionVetFarm = '$_base/action';
static const activeHatchingVetFarm = '$_base/activeHatching';
static const newInspectionVetFarm = '$_base/newInspection';
static const newPageVetFarm = '$_base/newPage';
}

View File

@@ -0,0 +1,27 @@
{
"type": "chip_selection",
"visible": true,
"data": {
"key": "grain_quality",
"label": "کیفیت دانه",
"selectedIndex": -1,
"options": [
{
"index": 0,
"label": "خوب",
"value": "خوب"
},
{
"index": 1,
"label": "متوسط",
"value": "متوسط"
},
{
"index": 2,
"label": "ضعیف",
"value": "ضعیف"
}
]
}
}

View File

@@ -0,0 +1,15 @@
{
"type": "dropdown",
"visible": true,
"data": {
"key": "training_status",
"label": "آموزش‌دیده در حوزه بهداشت و امنیت زیستی",
"placeholder": "آموزش‌دیده در حوزه بهداشت و امنیت زیستی",
"items": [
"بله",
"خیر"
],
"selectedValue": null,
"enabled": true
}
}

View File

@@ -0,0 +1,157 @@
{
"type": "column",
"visible": true,
"data": {
"spacing": 10.0,
"crossAxisAlignment": "start"
},
"children": [
{
"type": "card_label_item",
"visible": true,
"data": {
"title": "اطلاعات پایه واحد",
"padding_horizontal": 12.0,
"padding_vertical": 11.0
},
"child": {
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "unit_name",
"label": "نام واحد مرغداری",
"keyboardType": "text",
"enabled": true,
"readonly": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "breeding_unique_id",
"label": "کد یکتا / شناسه واحد",
"keyboardType": "text",
"enabled": true,
"readonly": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "health_license",
"label": "پروانه بهداشتی",
"keyboardType": "text",
"enabled": true,
"readonly": false
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "total_capacity",
"label": "ظرفیت اسمی سالن‌ها",
"keyboardType": "number",
"enabled": true,
"readonly": false,
"commaSperator": true
}
}
]
}
},
{
"type": "sized_box",
"visible": true,
"data": {
"height": 30.0
}
},
{
"type": "card_label_item",
"visible": true,
"data": {
"title": "اطلاعات جوجه ریزی",
"padding_horizontal": 12.0,
"padding_vertical": 11.0
},
"child": {
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "hatching_date",
"label": "تاریخ جوجه ریزی",
"keyboardType": "text",
"enabled": true,
"readonly": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "visit_date",
"label": "تاریخ بازدید",
"keyboardType": "text",
"enabled": true,
"readonly": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "hatching_count",
"label": "تعداد جوجه‌ریزی اولیه",
"keyboardType": "number",
"enabled": true,
"readonly": true,
"commaSperator": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "hatching_breed",
"label": "نوع نژاد",
"keyboardType": "text",
"enabled": true,
"readonly": false
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "hatching_average_weight",
"label": "میانگین وزن جوجه",
"keyboardType": "number",
"enabled": true,
"readonly": false,
"commaSperator": true,
"decimal": true
}
}
]
}
}
]
}

View File

@@ -0,0 +1,11 @@
{
"type": "image_picker",
"visible": true,
"data": {
"key": "hall_images",
"label": "ثبت عکس سالن (حداقل ۳ زاویه)",
"required": true,
"maxImages": null
}
}

View File

@@ -0,0 +1,9 @@
{
"type": "stepper",
"visible": true,
"data": {
"key": "activeStepperIndex",
"totalSteps": 5,
"activeStep": 0
}
}

View File

@@ -0,0 +1,620 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/card_label_item/card_label_item_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/card_label_item/model/card_label_item_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/chip_selection/chip_selection_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/chip_selection/model/chip_selection_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/dropdown/dropdown_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/dropdown/model/dropdown_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/image_picker/image_picker_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/image_picker/model/image_picker_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/text_form_filed/model/text_form_field_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/text_form_filed/text_form_filed_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/stepper/stepper_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/stepper/model/stepper_sdui_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/page_view_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/model/page_view_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class SDUIFormWidget extends StatelessWidget {
final SDUIWidgetModel model;
final Map<String, TextEditingController>? controllers;
final RxMap<String, dynamic>? state;
final Function(String key, dynamic value)? onStateChanged;
final Map<String, RxList<XFile>>? images;
final Function(String key, RxList<XFile> images)? onImagesChanged;
final Map<String, PageController>? pageControllers;
const SDUIFormWidget({
super.key,
required this.model,
this.controllers,
this.state,
this.onStateChanged,
this.images,
this.onImagesChanged,
this.pageControllers,
});
@override
Widget build(BuildContext context) {
if (model.visible == false) {
return const SizedBox.shrink();
}
try {
return _buildWidget(model);
} catch (e, stackTrace) {
iLog('Error in SDUIFormWidget.build: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.red.withOpacity(0.1),
child: Text('Error: $e'),
);
}
}
Widget _buildWidget(SDUIWidgetModel widgetModel) {
final type = widgetModel.type;
if (type == null || type.isEmpty) {
iLog('SDUIWidgetModel type is null or empty');
return const SizedBox.shrink();
}
switch (type) {
case 'text_form_field':
return _buildTextFormField(widgetModel);
case 'card_label_item':
return _buildCardLabelItem(widgetModel);
case 'chip_selection':
return _buildChipSelection(widgetModel);
case 'dropdown':
return _buildDropdown(widgetModel);
case 'image_picker':
return _buildImagePicker(widgetModel);
case 'column':
return _buildColumn(widgetModel);
case 'row':
return _buildRow(widgetModel);
case 'sized_box':
return _buildSizedBox(widgetModel);
case 'stepper':
return _buildStepper(widgetModel);
case 'page_view':
return _buildPageView(widgetModel);
default:
iLog('Unknown SDUI widget type: $type');
return const SizedBox.shrink();
}
}
Widget _buildTextFormField(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final textFieldModel = TextFormFieldSDUIModel.fromJson(widgetModel.data!);
// Use provided controller or create a new one
final key = textFieldModel.key ?? '';
TextEditingController controller;
if (controllers != null &&
key.isNotEmpty &&
controllers!.containsKey(key)) {
controller = controllers![key]!;
} else {
controller = TextEditingController(text: textFieldModel.value ?? '');
// Store the controller in the map if controllers map is provided
if (controllers != null && key.isNotEmpty) {
controllers![key] = controller;
}
}
return textFormFiledSDUI(model: textFieldModel, controller: controller);
} catch (e) {
iLog('Error building text_form_field: $e');
return const SizedBox.shrink();
}
}
Widget _buildCardLabelItem(SDUIWidgetModel widgetModel) {
try {
// Check visible_condition if present in data
if (widgetModel.data != null) {
final visibleCondition =
widgetModel.data!['visible_condition'] as String?;
if (visibleCondition != null && visibleCondition.isNotEmpty) {
if (state != null) {
return Obx(() {
if (!_evaluateVisibleCondition(visibleCondition)) {
return const SizedBox.shrink();
}
return _buildCardLabelItemInternal(widgetModel);
});
} else {
// If state is null, only show first step (0) by default
// This allows the form to work even without state initialization
if (visibleCondition.contains('activeStepperIndex == 0')) {
return _buildCardLabelItemInternal(widgetModel);
}
return const SizedBox.shrink();
}
}
}
return _buildCardLabelItemInternal(widgetModel);
} catch (e, stackTrace) {
iLog('Error building card_label_item: $e');
iLog('Stack trace: $stackTrace');
iLog('WidgetModel data: ${widgetModel.data}');
return Container(
padding: EdgeInsets.all(16),
color: Colors.orange.withOpacity(0.1),
child: Text('Card Error: $e'),
);
}
}
Widget _buildCardLabelItemInternal(SDUIWidgetModel widgetModel) {
try {
// Remove visible_condition from data before creating CardLabelItemData
// because it's not part of the model
final dataWithoutCondition = widgetModel.data != null
? Map<String, dynamic>.from(widgetModel.data!)
: null;
if (dataWithoutCondition != null) {
dataWithoutCondition.remove('visible_condition');
}
final cardModel = CardLabelItemSDUI.fromJson({
'type': widgetModel.type,
'visible': widgetModel.visible,
'data': dataWithoutCondition,
'child': widgetModel.child,
});
// If there's a child, build it recursively
Widget? childWidget;
if (widgetModel.child != null) {
try {
childWidget = SDUIFormWidget(
model: SDUIWidgetModel.fromJson(widgetModel.child!),
controllers: controllers,
state: state,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
);
} catch (e) {
iLog('Error building card_label_item child: $e');
iLog('Child data: ${widgetModel.child}');
}
} else if (widgetModel.children != null &&
widgetModel.children!.isNotEmpty) {
// If there are children, build them as a column
try {
childWidget = Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: widgetModel.children!
.map(
(child) => SDUIFormWidget(
model: SDUIWidgetModel.fromJson(child),
controllers: controllers,
state: state,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
),
)
.toList(),
);
} catch (e) {
iLog('Error building card_label_item children: $e');
}
}
// Create a modified card model with the child widget
return cardLabelItemSDUI(model: cardModel, child: childWidget);
} catch (e, stackTrace) {
iLog('Error building card_label_item: $e');
iLog('Stack trace: $stackTrace');
iLog('WidgetModel data: ${widgetModel.data}');
return Container(
padding: EdgeInsets.all(16),
color: Colors.orange.withOpacity(0.1),
child: Text('Card Error: $e'),
);
}
}
Widget _buildColumn(SDUIWidgetModel widgetModel) {
if (widgetModel.children == null || widgetModel.children!.isEmpty) {
iLog('Column has no children');
return const SizedBox.shrink();
}
try {
final spacing = widgetModel.data?['spacing'];
final spacingValue = spacing is int
? spacing.toDouble()
: (spacing as double?) ?? 0.0;
final mainAxisSize = widgetModel.data?['mainAxisSize'] == 'min'
? MainAxisSize.min
: MainAxisSize.max;
final crossAxisAlignment = _parseCrossAxisAlignment(
widgetModel.data?['crossAxisAlignment'],
);
final children = widgetModel.children!.map((child) {
try {
return SDUIFormWidget(
model: SDUIWidgetModel.fromJson(child),
controllers: controllers,
state: state,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
pageControllers: pageControllers,
);
} catch (e) {
iLog('Error building column child: $e');
iLog('Child data: $child');
return Container(
padding: EdgeInsets.all(8),
color: Colors.yellow.withOpacity(0.1),
child: Text('Child Error'),
);
}
}).toList();
// Add spacing between children
if (spacingValue > 0 && children.length > 1) {
final spacedChildren = <Widget>[];
for (int i = 0; i < children.length; i++) {
spacedChildren.add(children[i]);
if (i < children.length - 1) {
spacedChildren.add(SizedBox(height: spacingValue));
}
}
return Column(
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
children: spacedChildren,
);
}
return Column(
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
children: children,
);
} catch (e, stackTrace) {
iLog('Error building column: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.blue.withOpacity(0.1),
child: Text('Column Error: $e'),
);
}
}
Widget _buildRow(SDUIWidgetModel widgetModel) {
if (widgetModel.children == null || widgetModel.children!.isEmpty) {
return const SizedBox.shrink();
}
final spacing = widgetModel.data?['spacing'] as double? ?? 0.0;
final mainAxisAlignment = _parseMainAxisAlignment(
widgetModel.data?['mainAxisAlignment'],
);
final children = widgetModel.children!
.map(
(child) => SDUIFormWidget(
model: SDUIWidgetModel.fromJson(child),
controllers: controllers,
state: state,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
),
)
.toList();
// Add spacing between children
if (spacing > 0 && children.length > 1) {
final spacedChildren = <Widget>[];
for (int i = 0; i < children.length; i++) {
spacedChildren.add(children[i]);
if (i < children.length - 1) {
spacedChildren.add(SizedBox(width: spacing));
}
}
return Row(
mainAxisAlignment: mainAxisAlignment,
children: spacedChildren,
);
}
return Row(mainAxisAlignment: mainAxisAlignment, children: children);
}
Widget _buildSizedBox(SDUIWidgetModel widgetModel) {
final data = widgetModel.data ?? {};
final width = data['width'] as double?;
final height = data['height'] as double?;
return SizedBox(width: width, height: height);
}
Widget _buildChipSelection(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final chipModel = ChipSelectionSDUIModel.fromJson(widgetModel.data!);
return ChipSelectionSDUI(
model: chipModel,
state: state,
onChanged: (key, index, value) {
if (onStateChanged != null) {
onStateChanged!(key, index);
}
},
);
} catch (e, stackTrace) {
iLog('Error building chip_selection: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.purple.withOpacity(0.1),
child: Text('Chip Selection Error: $e'),
);
}
}
Widget _buildDropdown(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final dropdownModel = DropdownSDUIModel.fromJson(widgetModel.data!);
return DropdownSDUI(
model: dropdownModel,
state: state,
onChanged: (key, value) {
if (onStateChanged != null) {
onStateChanged!(key, value);
}
},
);
} catch (e, stackTrace) {
iLog('Error building dropdown: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.blue.withOpacity(0.1),
child: Text('Dropdown Error: $e'),
);
}
}
Widget _buildImagePicker(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final imagePickerModel = ImagePickerSDUIModel.fromJson(widgetModel.data!);
return ImagePickerSDUI(
model: imagePickerModel,
images: images,
onImagesChanged: (key, imageList) {
if (onImagesChanged != null) {
onImagesChanged!(key, imageList);
}
},
);
} catch (e, stackTrace) {
iLog('Error building image_picker: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.green.withOpacity(0.1),
child: Text('Image Picker Error: $e'),
);
}
}
CrossAxisAlignment _parseCrossAxisAlignment(dynamic value) {
if (value == null) return CrossAxisAlignment.center;
switch (value.toString()) {
case 'start':
return CrossAxisAlignment.start;
case 'end':
return CrossAxisAlignment.end;
case 'center':
return CrossAxisAlignment.center;
case 'stretch':
return CrossAxisAlignment.stretch;
default:
return CrossAxisAlignment.center;
}
}
MainAxisAlignment _parseMainAxisAlignment(dynamic value) {
if (value == null) return MainAxisAlignment.start;
switch (value.toString()) {
case 'start':
return MainAxisAlignment.start;
case 'end':
return MainAxisAlignment.end;
case 'center':
return MainAxisAlignment.center;
case 'spaceBetween':
return MainAxisAlignment.spaceBetween;
case 'spaceAround':
return MainAxisAlignment.spaceAround;
case 'spaceEvenly':
return MainAxisAlignment.spaceEvenly;
default:
return MainAxisAlignment.start;
}
}
Widget _buildStepper(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final stepperModel = StepperSDUIModel.fromJson(widgetModel.data!);
return StepperSDUI(model: stepperModel, state: state);
} catch (e, stackTrace) {
iLog('Error building stepper: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.orange.withOpacity(0.1),
child: Text('Stepper Error: $e'),
);
}
}
Widget _buildPageView(SDUIWidgetModel widgetModel) {
if (widgetModel.data == null) {
return const SizedBox.shrink();
}
try {
final pageViewModel = PageViewSDUIModel.fromJson(widgetModel.data!);
// Get PageController from map if key is provided
PageController? pageController;
if (pageViewModel.key != null &&
pageViewModel.key!.isNotEmpty &&
pageControllers != null &&
pageControllers!.containsKey(pageViewModel.key!)) {
pageController = pageControllers![pageViewModel.key!];
}
// Build children if they exist
List<Widget> pageChildren = [];
if (widgetModel.children != null && widgetModel.children!.isNotEmpty) {
pageChildren = widgetModel.children!.map((child) {
try {
return SDUIFormWidget(
model: SDUIWidgetModel.fromJson(child),
controllers: controllers,
state: state,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
pageControllers: pageControllers,
);
} catch (e) {
iLog('Error building page_view child: $e');
iLog('Child data: $child');
return Container(
padding: EdgeInsets.all(8),
color: Colors.yellow.withOpacity(0.1),
child: Text('Child Error'),
);
}
}).toList();
}
return PageViewSDUI(
model: pageViewModel,
controller: pageController,
children: pageChildren,
state: state,
controllers: controllers,
onStateChanged: onStateChanged,
images: images,
onImagesChanged: onImagesChanged,
);
} catch (e, stackTrace) {
iLog('Error building page_view: $e');
iLog('Stack trace: $stackTrace');
return Container(
padding: EdgeInsets.all(16),
color: Colors.blue.withOpacity(0.1),
child: Text('PageView Error: $e'),
);
}
}
bool _evaluateVisibleCondition(String condition) {
if (state == null) {
// If state is null, return true for first step (0) by default
// This allows the form to work even without state initialization
if (condition.contains('activeStepperIndex == 0')) {
return true;
}
return false;
}
try {
// Simple condition evaluation
// Supports: variable == value
if (condition.contains(' == ')) {
final parts = condition.split(' == ');
if (parts.length == 2) {
final variable = parts[0].trim();
var value = parts[1].trim();
// Remove quotes if present
if ((value.startsWith("'") && value.endsWith("'")) ||
(value.startsWith('"') && value.endsWith('"'))) {
value = value.substring(1, value.length - 1);
}
final stateValue = state![variable];
if (stateValue == null) {
// If variable doesn't exist in state, default to showing first step (0)
if (variable == 'activeStepperIndex' && value == '0') {
return true;
}
return false;
}
// Handle int comparison
final intValue = int.tryParse(value);
if (intValue != null) {
if (stateValue is int) {
return stateValue == intValue;
}
if (stateValue is num) {
return stateValue.toInt() == intValue;
}
}
// Handle string comparison
return stateValue.toString() == value;
}
}
// If condition format is not recognized, return false
iLog('Unsupported visible_condition format: $condition');
return false;
} catch (e) {
iLog('Error evaluating visible_condition: $e');
return false;
}
}
}

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'sdui_widget_model.freezed.dart';
part 'sdui_widget_model.g.dart';
@freezed
abstract class SDUIWidgetModel with _$SDUIWidgetModel {
const factory SDUIWidgetModel({
String? type,
bool? visible,
Map<String, dynamic>? data,
Map<String, dynamic>? child,
List<Map<String, dynamic>>? children,
}) = _SDUIWidgetModel;
factory SDUIWidgetModel.fromJson(Map<String, dynamic> json) =>
_$SDUIWidgetModelFromJson(json);
}

View File

@@ -0,0 +1,313 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'sdui_widget_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$SDUIWidgetModel {
String? get type; bool? get visible; Map<String, dynamic>? get data; Map<String, dynamic>? get child; List<Map<String, dynamic>>? get children;
/// Create a copy of SDUIWidgetModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$SDUIWidgetModelCopyWith<SDUIWidgetModel> get copyWith => _$SDUIWidgetModelCopyWithImpl<SDUIWidgetModel>(this as SDUIWidgetModel, _$identity);
/// Serializes this SDUIWidgetModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is SDUIWidgetModel&&(identical(other.type, type) || other.type == type)&&(identical(other.visible, visible) || other.visible == visible)&&const DeepCollectionEquality().equals(other.data, data)&&const DeepCollectionEquality().equals(other.child, child)&&const DeepCollectionEquality().equals(other.children, children));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,visible,const DeepCollectionEquality().hash(data),const DeepCollectionEquality().hash(child),const DeepCollectionEquality().hash(children));
@override
String toString() {
return 'SDUIWidgetModel(type: $type, visible: $visible, data: $data, child: $child, children: $children)';
}
}
/// @nodoc
abstract mixin class $SDUIWidgetModelCopyWith<$Res> {
factory $SDUIWidgetModelCopyWith(SDUIWidgetModel value, $Res Function(SDUIWidgetModel) _then) = _$SDUIWidgetModelCopyWithImpl;
@useResult
$Res call({
String? type, bool? visible, Map<String, dynamic>? data, Map<String, dynamic>? child, List<Map<String, dynamic>>? children
});
}
/// @nodoc
class _$SDUIWidgetModelCopyWithImpl<$Res>
implements $SDUIWidgetModelCopyWith<$Res> {
_$SDUIWidgetModelCopyWithImpl(this._self, this._then);
final SDUIWidgetModel _self;
final $Res Function(SDUIWidgetModel) _then;
/// Create a copy of SDUIWidgetModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? type = freezed,Object? visible = freezed,Object? data = freezed,Object? child = freezed,Object? children = freezed,}) {
return _then(_self.copyWith(
type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,visible: freezed == visible ? _self.visible : visible // ignore: cast_nullable_to_non_nullable
as bool?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,child: freezed == child ? _self.child : child // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,children: freezed == children ? _self.children : children // ignore: cast_nullable_to_non_nullable
as List<Map<String, dynamic>>?,
));
}
}
/// Adds pattern-matching-related methods to [SDUIWidgetModel].
extension SDUIWidgetModelPatterns on SDUIWidgetModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SDUIWidgetModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _SDUIWidgetModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SDUIWidgetModel value) $default,){
final _that = this;
switch (_that) {
case _SDUIWidgetModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SDUIWidgetModel value)? $default,){
final _that = this;
switch (_that) {
case _SDUIWidgetModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? type, bool? visible, Map<String, dynamic>? data, Map<String, dynamic>? child, List<Map<String, dynamic>>? children)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _SDUIWidgetModel() when $default != null:
return $default(_that.type,_that.visible,_that.data,_that.child,_that.children);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? type, bool? visible, Map<String, dynamic>? data, Map<String, dynamic>? child, List<Map<String, dynamic>>? children) $default,) {final _that = this;
switch (_that) {
case _SDUIWidgetModel():
return $default(_that.type,_that.visible,_that.data,_that.child,_that.children);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? type, bool? visible, Map<String, dynamic>? data, Map<String, dynamic>? child, List<Map<String, dynamic>>? children)? $default,) {final _that = this;
switch (_that) {
case _SDUIWidgetModel() when $default != null:
return $default(_that.type,_that.visible,_that.data,_that.child,_that.children);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _SDUIWidgetModel implements SDUIWidgetModel {
const _SDUIWidgetModel({this.type, this.visible, final Map<String, dynamic>? data, final Map<String, dynamic>? child, final List<Map<String, dynamic>>? children}): _data = data,_child = child,_children = children;
factory _SDUIWidgetModel.fromJson(Map<String, dynamic> json) => _$SDUIWidgetModelFromJson(json);
@override final String? type;
@override final bool? visible;
final Map<String, dynamic>? _data;
@override Map<String, dynamic>? get data {
final value = _data;
if (value == null) return null;
if (_data is EqualUnmodifiableMapView) return _data;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
final Map<String, dynamic>? _child;
@override Map<String, dynamic>? get child {
final value = _child;
if (value == null) return null;
if (_child is EqualUnmodifiableMapView) return _child;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
final List<Map<String, dynamic>>? _children;
@override List<Map<String, dynamic>>? get children {
final value = _children;
if (value == null) return null;
if (_children is EqualUnmodifiableListView) return _children;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
/// Create a copy of SDUIWidgetModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SDUIWidgetModelCopyWith<_SDUIWidgetModel> get copyWith => __$SDUIWidgetModelCopyWithImpl<_SDUIWidgetModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$SDUIWidgetModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SDUIWidgetModel&&(identical(other.type, type) || other.type == type)&&(identical(other.visible, visible) || other.visible == visible)&&const DeepCollectionEquality().equals(other._data, _data)&&const DeepCollectionEquality().equals(other._child, _child)&&const DeepCollectionEquality().equals(other._children, _children));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,visible,const DeepCollectionEquality().hash(_data),const DeepCollectionEquality().hash(_child),const DeepCollectionEquality().hash(_children));
@override
String toString() {
return 'SDUIWidgetModel(type: $type, visible: $visible, data: $data, child: $child, children: $children)';
}
}
/// @nodoc
abstract mixin class _$SDUIWidgetModelCopyWith<$Res> implements $SDUIWidgetModelCopyWith<$Res> {
factory _$SDUIWidgetModelCopyWith(_SDUIWidgetModel value, $Res Function(_SDUIWidgetModel) _then) = __$SDUIWidgetModelCopyWithImpl;
@override @useResult
$Res call({
String? type, bool? visible, Map<String, dynamic>? data, Map<String, dynamic>? child, List<Map<String, dynamic>>? children
});
}
/// @nodoc
class __$SDUIWidgetModelCopyWithImpl<$Res>
implements _$SDUIWidgetModelCopyWith<$Res> {
__$SDUIWidgetModelCopyWithImpl(this._self, this._then);
final _SDUIWidgetModel _self;
final $Res Function(_SDUIWidgetModel) _then;
/// Create a copy of SDUIWidgetModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? type = freezed,Object? visible = freezed,Object? data = freezed,Object? child = freezed,Object? children = freezed,}) {
return _then(_SDUIWidgetModel(
type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,visible: freezed == visible ? _self.visible : visible // ignore: cast_nullable_to_non_nullable
as bool?,data: freezed == data ? _self._data : data // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,child: freezed == child ? _self._child : child // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,children: freezed == children ? _self._children : children // ignore: cast_nullable_to_non_nullable
as List<Map<String, dynamic>>?,
));
}
}
// dart format on

View File

@@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'sdui_widget_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_SDUIWidgetModel _$SDUIWidgetModelFromJson(Map<String, dynamic> json) =>
_SDUIWidgetModel(
type: json['type'] as String?,
visible: json['visible'] as bool?,
data: json['data'] as Map<String, dynamic>?,
child: json['child'] as Map<String, dynamic>?,
children: (json['children'] as List<dynamic>?)
?.map((e) => e as Map<String, dynamic>)
.toList(),
);
Map<String, dynamic> _$SDUIWidgetModelToJson(_SDUIWidgetModel instance) =>
<String, dynamic>{
'type': instance.type,
'visible': instance.visible,
'data': instance.data,
'child': instance.child,
'children': instance.children,
};

View File

@@ -0,0 +1,8 @@
// SDUI Export file
export 'form/sdui_form_widget.dart';
export 'model/sdui_widget_model.dart';
export 'widgets/card_label_item/card_label_item_sdui.dart';
export 'widgets/card_label_item/model/card_label_item_sdui_model.dart';
export 'widgets/text_form_filed/text_form_filed_sdui.dart';
export 'widgets/text_form_filed/model/text_form_field_sdui_model.dart';

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,79 @@
{
"info": {
"type": "column",
"visible": true,
"data": {
"spacing": 10.0,
"crossAxisAlignment": "start"
},
"children": [
{
"type": "card_label_item",
"visible": true,
"data": {
"title": "اطلاعات پایه واحد",
"padding_horizontal": 12.0,
"padding_vertical": 11.0
},
"child": {
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "unit_name",
"label": "نام واحد مرغداری",
"keyboard_type": "text"
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "breeding_unique_id",
"label": "(عدد معمولی)کد یکتا / شناسه واحد",
"keyboard_type": "number"
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "health_a",
"label": "(سه تایی جداشه)پروانه بهداشتی",
"keyboard_type": "number",
"comma_sperator": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "health_license",
"label": "عدد اعشاری ",
"keyboard_type": "number",
"decimal": true
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "health_q",
"label": "عدد اعشاری با 2 رقم اعشار",
"keyboard_type": "number",
"decimal": true,
"decimal_places": 2
}
}
]
}
}
]
}
}

View File

@@ -0,0 +1,77 @@
{
"id": 1,
"key": "simple-test-form",
"create_date": "2025-01-15T10:00:00.000000",
"modify_date": "2025-01-15T10:00:00.000000",
"trash": false,
"info": {
"data": {
"type": "column",
"visible": true,
"data": {
"spacing": 20.0,
"crossAxisAlignment": "start"
},
"children": [
{
"type": "card_label_item",
"visible": true,
"data": {
"title": "فرم تست",
"padding_horizontal": 12.0,
"padding_vertical": 11.0
},
"child": {
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "name",
"label": "نام",
"keyboardType": "text",
"enabled": true,
"readonly": false,
"value": ""
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "phone",
"label": "شماره تماس",
"keyboardType": "text",
"enabled": true,
"readonly": false,
"value": ""
}
},
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "age",
"label": "سن",
"keyboardType": "number",
"enabled": true,
"readonly": false,
"commaSperator": true,
"value": ""
}
}
]
}
}
]
}
},
"created_by": null,
"modified_by": null
}

View File

@@ -0,0 +1,54 @@
import 'package:rasadyar_core/core.dart';
import 'model/card_label_item_sdui_model.dart';
import 'package:flutter/material.dart';
Widget cardLabelItemSDUI({required CardLabelItemSDUI model, Widget? child}) {
return farmInfoWidget(
title: model.data?.title ?? '',
child: child ?? Container(),
);
}
Widget farmInfoWidget({
required String title,
required Widget child,
EdgeInsets? padding,
}) {
return Stack(
clipBehavior: Clip.none,
children: [
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.50, color: AppColor.mediumGrey),
),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 11.h),
child: Column(
children: [
SizedBox(height: 8.h),
child,
],
),
),
Positioned(
top: -17,
right: 7,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 5.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.50, color: AppColor.mediumGrey),
),
child: Text(
title,
style: AppFonts.yekan14.copyWith(color: AppColor.iconColor),
),
),
),
],
);
}

View File

@@ -0,0 +1,29 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'card_label_item_sdui_model.freezed.dart';
part 'card_label_item_sdui_model.g.dart';
@freezed
abstract class CardLabelItemSDUI with _$CardLabelItemSDUI {
const factory CardLabelItemSDUI({
String? type,
bool? visible,
CardLabelItemData? data,
Map<String, dynamic>? child,
}) = _CardLabelItemSDUI;
factory CardLabelItemSDUI.fromJson(Map<String, dynamic> json) =>
_$CardLabelItemSDUIFromJson(json);
}
@freezed
abstract class CardLabelItemData with _$CardLabelItemData {
const factory CardLabelItemData({
String? title,
double? paddingHorizontal,
double? paddingVertical,
}) = _CardLabelItemData;
factory CardLabelItemData.fromJson(Map<String, dynamic> json) =>
_$CardLabelItemDataFromJson(json);
}

View File

@@ -0,0 +1,587 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'card_label_item_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$CardLabelItemSDUI {
String? get type; bool? get visible; CardLabelItemData? get data; Map<String, dynamic>? get child;
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CardLabelItemSDUICopyWith<CardLabelItemSDUI> get copyWith => _$CardLabelItemSDUICopyWithImpl<CardLabelItemSDUI>(this as CardLabelItemSDUI, _$identity);
/// Serializes this CardLabelItemSDUI to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CardLabelItemSDUI&&(identical(other.type, type) || other.type == type)&&(identical(other.visible, visible) || other.visible == visible)&&(identical(other.data, data) || other.data == data)&&const DeepCollectionEquality().equals(other.child, child));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,visible,data,const DeepCollectionEquality().hash(child));
@override
String toString() {
return 'CardLabelItemSDUI(type: $type, visible: $visible, data: $data, child: $child)';
}
}
/// @nodoc
abstract mixin class $CardLabelItemSDUICopyWith<$Res> {
factory $CardLabelItemSDUICopyWith(CardLabelItemSDUI value, $Res Function(CardLabelItemSDUI) _then) = _$CardLabelItemSDUICopyWithImpl;
@useResult
$Res call({
String? type, bool? visible, CardLabelItemData? data, Map<String, dynamic>? child
});
$CardLabelItemDataCopyWith<$Res>? get data;
}
/// @nodoc
class _$CardLabelItemSDUICopyWithImpl<$Res>
implements $CardLabelItemSDUICopyWith<$Res> {
_$CardLabelItemSDUICopyWithImpl(this._self, this._then);
final CardLabelItemSDUI _self;
final $Res Function(CardLabelItemSDUI) _then;
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? type = freezed,Object? visible = freezed,Object? data = freezed,Object? child = freezed,}) {
return _then(_self.copyWith(
type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,visible: freezed == visible ? _self.visible : visible // ignore: cast_nullable_to_non_nullable
as bool?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
as CardLabelItemData?,child: freezed == child ? _self.child : child // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
));
}
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CardLabelItemDataCopyWith<$Res>? get data {
if (_self.data == null) {
return null;
}
return $CardLabelItemDataCopyWith<$Res>(_self.data!, (value) {
return _then(_self.copyWith(data: value));
});
}
}
/// Adds pattern-matching-related methods to [CardLabelItemSDUI].
extension CardLabelItemSDUIPatterns on CardLabelItemSDUI {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CardLabelItemSDUI value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CardLabelItemSDUI() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CardLabelItemSDUI value) $default,){
final _that = this;
switch (_that) {
case _CardLabelItemSDUI():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CardLabelItemSDUI value)? $default,){
final _that = this;
switch (_that) {
case _CardLabelItemSDUI() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? type, bool? visible, CardLabelItemData? data, Map<String, dynamic>? child)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CardLabelItemSDUI() when $default != null:
return $default(_that.type,_that.visible,_that.data,_that.child);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? type, bool? visible, CardLabelItemData? data, Map<String, dynamic>? child) $default,) {final _that = this;
switch (_that) {
case _CardLabelItemSDUI():
return $default(_that.type,_that.visible,_that.data,_that.child);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? type, bool? visible, CardLabelItemData? data, Map<String, dynamic>? child)? $default,) {final _that = this;
switch (_that) {
case _CardLabelItemSDUI() when $default != null:
return $default(_that.type,_that.visible,_that.data,_that.child);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CardLabelItemSDUI implements CardLabelItemSDUI {
const _CardLabelItemSDUI({this.type, this.visible, this.data, final Map<String, dynamic>? child}): _child = child;
factory _CardLabelItemSDUI.fromJson(Map<String, dynamic> json) => _$CardLabelItemSDUIFromJson(json);
@override final String? type;
@override final bool? visible;
@override final CardLabelItemData? data;
final Map<String, dynamic>? _child;
@override Map<String, dynamic>? get child {
final value = _child;
if (value == null) return null;
if (_child is EqualUnmodifiableMapView) return _child;
// ignore: implicit_dynamic_type
return EqualUnmodifiableMapView(value);
}
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CardLabelItemSDUICopyWith<_CardLabelItemSDUI> get copyWith => __$CardLabelItemSDUICopyWithImpl<_CardLabelItemSDUI>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CardLabelItemSDUIToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CardLabelItemSDUI&&(identical(other.type, type) || other.type == type)&&(identical(other.visible, visible) || other.visible == visible)&&(identical(other.data, data) || other.data == data)&&const DeepCollectionEquality().equals(other._child, _child));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,type,visible,data,const DeepCollectionEquality().hash(_child));
@override
String toString() {
return 'CardLabelItemSDUI(type: $type, visible: $visible, data: $data, child: $child)';
}
}
/// @nodoc
abstract mixin class _$CardLabelItemSDUICopyWith<$Res> implements $CardLabelItemSDUICopyWith<$Res> {
factory _$CardLabelItemSDUICopyWith(_CardLabelItemSDUI value, $Res Function(_CardLabelItemSDUI) _then) = __$CardLabelItemSDUICopyWithImpl;
@override @useResult
$Res call({
String? type, bool? visible, CardLabelItemData? data, Map<String, dynamic>? child
});
@override $CardLabelItemDataCopyWith<$Res>? get data;
}
/// @nodoc
class __$CardLabelItemSDUICopyWithImpl<$Res>
implements _$CardLabelItemSDUICopyWith<$Res> {
__$CardLabelItemSDUICopyWithImpl(this._self, this._then);
final _CardLabelItemSDUI _self;
final $Res Function(_CardLabelItemSDUI) _then;
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? type = freezed,Object? visible = freezed,Object? data = freezed,Object? child = freezed,}) {
return _then(_CardLabelItemSDUI(
type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,visible: freezed == visible ? _self.visible : visible // ignore: cast_nullable_to_non_nullable
as bool?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
as CardLabelItemData?,child: freezed == child ? _self._child : child // ignore: cast_nullable_to_non_nullable
as Map<String, dynamic>?,
));
}
/// Create a copy of CardLabelItemSDUI
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CardLabelItemDataCopyWith<$Res>? get data {
if (_self.data == null) {
return null;
}
return $CardLabelItemDataCopyWith<$Res>(_self.data!, (value) {
return _then(_self.copyWith(data: value));
});
}
}
/// @nodoc
mixin _$CardLabelItemData {
String? get title; double? get paddingHorizontal; double? get paddingVertical;
/// Create a copy of CardLabelItemData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CardLabelItemDataCopyWith<CardLabelItemData> get copyWith => _$CardLabelItemDataCopyWithImpl<CardLabelItemData>(this as CardLabelItemData, _$identity);
/// Serializes this CardLabelItemData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CardLabelItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.paddingHorizontal, paddingHorizontal) || other.paddingHorizontal == paddingHorizontal)&&(identical(other.paddingVertical, paddingVertical) || other.paddingVertical == paddingVertical));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,paddingHorizontal,paddingVertical);
@override
String toString() {
return 'CardLabelItemData(title: $title, paddingHorizontal: $paddingHorizontal, paddingVertical: $paddingVertical)';
}
}
/// @nodoc
abstract mixin class $CardLabelItemDataCopyWith<$Res> {
factory $CardLabelItemDataCopyWith(CardLabelItemData value, $Res Function(CardLabelItemData) _then) = _$CardLabelItemDataCopyWithImpl;
@useResult
$Res call({
String? title, double? paddingHorizontal, double? paddingVertical
});
}
/// @nodoc
class _$CardLabelItemDataCopyWithImpl<$Res>
implements $CardLabelItemDataCopyWith<$Res> {
_$CardLabelItemDataCopyWithImpl(this._self, this._then);
final CardLabelItemData _self;
final $Res Function(CardLabelItemData) _then;
/// Create a copy of CardLabelItemData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? title = freezed,Object? paddingHorizontal = freezed,Object? paddingVertical = freezed,}) {
return _then(_self.copyWith(
title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String?,paddingHorizontal: freezed == paddingHorizontal ? _self.paddingHorizontal : paddingHorizontal // ignore: cast_nullable_to_non_nullable
as double?,paddingVertical: freezed == paddingVertical ? _self.paddingVertical : paddingVertical // ignore: cast_nullable_to_non_nullable
as double?,
));
}
}
/// Adds pattern-matching-related methods to [CardLabelItemData].
extension CardLabelItemDataPatterns on CardLabelItemData {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _CardLabelItemData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CardLabelItemData() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _CardLabelItemData value) $default,){
final _that = this;
switch (_that) {
case _CardLabelItemData():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _CardLabelItemData value)? $default,){
final _that = this;
switch (_that) {
case _CardLabelItemData() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? title, double? paddingHorizontal, double? paddingVertical)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CardLabelItemData() when $default != null:
return $default(_that.title,_that.paddingHorizontal,_that.paddingVertical);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? title, double? paddingHorizontal, double? paddingVertical) $default,) {final _that = this;
switch (_that) {
case _CardLabelItemData():
return $default(_that.title,_that.paddingHorizontal,_that.paddingVertical);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? title, double? paddingHorizontal, double? paddingVertical)? $default,) {final _that = this;
switch (_that) {
case _CardLabelItemData() when $default != null:
return $default(_that.title,_that.paddingHorizontal,_that.paddingVertical);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CardLabelItemData implements CardLabelItemData {
const _CardLabelItemData({this.title, this.paddingHorizontal, this.paddingVertical});
factory _CardLabelItemData.fromJson(Map<String, dynamic> json) => _$CardLabelItemDataFromJson(json);
@override final String? title;
@override final double? paddingHorizontal;
@override final double? paddingVertical;
/// Create a copy of CardLabelItemData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CardLabelItemDataCopyWith<_CardLabelItemData> get copyWith => __$CardLabelItemDataCopyWithImpl<_CardLabelItemData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CardLabelItemDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CardLabelItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.paddingHorizontal, paddingHorizontal) || other.paddingHorizontal == paddingHorizontal)&&(identical(other.paddingVertical, paddingVertical) || other.paddingVertical == paddingVertical));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,paddingHorizontal,paddingVertical);
@override
String toString() {
return 'CardLabelItemData(title: $title, paddingHorizontal: $paddingHorizontal, paddingVertical: $paddingVertical)';
}
}
/// @nodoc
abstract mixin class _$CardLabelItemDataCopyWith<$Res> implements $CardLabelItemDataCopyWith<$Res> {
factory _$CardLabelItemDataCopyWith(_CardLabelItemData value, $Res Function(_CardLabelItemData) _then) = __$CardLabelItemDataCopyWithImpl;
@override @useResult
$Res call({
String? title, double? paddingHorizontal, double? paddingVertical
});
}
/// @nodoc
class __$CardLabelItemDataCopyWithImpl<$Res>
implements _$CardLabelItemDataCopyWith<$Res> {
__$CardLabelItemDataCopyWithImpl(this._self, this._then);
final _CardLabelItemData _self;
final $Res Function(_CardLabelItemData) _then;
/// Create a copy of CardLabelItemData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? title = freezed,Object? paddingHorizontal = freezed,Object? paddingVertical = freezed,}) {
return _then(_CardLabelItemData(
title: freezed == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String?,paddingHorizontal: freezed == paddingHorizontal ? _self.paddingHorizontal : paddingHorizontal // ignore: cast_nullable_to_non_nullable
as double?,paddingVertical: freezed == paddingVertical ? _self.paddingVertical : paddingVertical // ignore: cast_nullable_to_non_nullable
as double?,
));
}
}
// dart format on

View File

@@ -0,0 +1,39 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'card_label_item_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_CardLabelItemSDUI _$CardLabelItemSDUIFromJson(Map<String, dynamic> json) =>
_CardLabelItemSDUI(
type: json['type'] as String?,
visible: json['visible'] as bool?,
data: json['data'] == null
? null
: CardLabelItemData.fromJson(json['data'] as Map<String, dynamic>),
child: json['child'] as Map<String, dynamic>?,
);
Map<String, dynamic> _$CardLabelItemSDUIToJson(_CardLabelItemSDUI instance) =>
<String, dynamic>{
'type': instance.type,
'visible': instance.visible,
'data': instance.data,
'child': instance.child,
};
_CardLabelItemData _$CardLabelItemDataFromJson(Map<String, dynamic> json) =>
_CardLabelItemData(
title: json['title'] as String?,
paddingHorizontal: (json['padding_horizontal'] as num?)?.toDouble(),
paddingVertical: (json['padding_vertical'] as num?)?.toDouble(),
);
Map<String, dynamic> _$CardLabelItemDataToJson(_CardLabelItemData instance) =>
<String, dynamic>{
'title': instance.title,
'padding_horizontal': instance.paddingHorizontal,
'padding_vertical': instance.paddingVertical,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/chip_selection/model/chip_selection_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class ChipSelectionSDUI extends StatelessWidget {
final ChipSelectionSDUIModel model;
final RxMap<String, dynamic>? state;
final Function(String key, int index, String? value)? onChanged;
const ChipSelectionSDUI({
super.key,
required this.model,
this.state,
this.onChanged,
});
@override
Widget build(BuildContext context) {
final options = model.options ?? [];
final spacing = 10.0;
if (options.isEmpty) {
return const SizedBox.shrink();
}
return Obx(() {
final selectedIndex =
state?[model.key] as int? ?? model.selectedIndex ?? -1;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (model.label != null && model.label!.isNotEmpty) ...[
Text(
model.label!,
style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2),
),
SizedBox(height: 9.h),
],
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: spacing,
children: options.asMap().entries.map((entry) {
final option = entry.value;
final optionIndex = option.index ?? entry.key;
return Expanded(
child: containerChips(
selectedIndex: selectedIndex,
index: optionIndex,
label: option.label ?? '',
onTap: (index) {
if (onChanged != null && model.key != null) {
onChanged!(model.key!, index, option.value);
}
},
),
);
}).toList(),
),
],
);
});
}
}

View File

@@ -0,0 +1,30 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chip_selection_sdui_model.freezed.dart';
part 'chip_selection_sdui_model.g.dart';
@freezed
abstract class ChipSelectionSDUIModel with _$ChipSelectionSDUIModel {
const factory ChipSelectionSDUIModel({
String? key,
String? label,
List<ChipOption>? options,
int? selectedIndex,
}) = _ChipSelectionSDUIModel;
factory ChipSelectionSDUIModel.fromJson(Map<String, dynamic> json) =>
_$ChipSelectionSDUIModelFromJson(json);
}
@freezed
abstract class ChipOption with _$ChipOption {
const factory ChipOption({
int? index,
String? label,
String? value,
}) = _ChipOption;
factory ChipOption.fromJson(Map<String, dynamic> json) =>
_$ChipOptionFromJson(json);
}

View File

@@ -0,0 +1,563 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'chip_selection_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ChipSelectionSDUIModel {
String? get key; String? get label; List<ChipOption>? get options; int? get selectedIndex;
/// Create a copy of ChipSelectionSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ChipSelectionSDUIModelCopyWith<ChipSelectionSDUIModel> get copyWith => _$ChipSelectionSDUIModelCopyWithImpl<ChipSelectionSDUIModel>(this as ChipSelectionSDUIModel, _$identity);
/// Serializes this ChipSelectionSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ChipSelectionSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&const DeepCollectionEquality().equals(other.options, options)&&(identical(other.selectedIndex, selectedIndex) || other.selectedIndex == selectedIndex));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,const DeepCollectionEquality().hash(options),selectedIndex);
@override
String toString() {
return 'ChipSelectionSDUIModel(key: $key, label: $label, options: $options, selectedIndex: $selectedIndex)';
}
}
/// @nodoc
abstract mixin class $ChipSelectionSDUIModelCopyWith<$Res> {
factory $ChipSelectionSDUIModelCopyWith(ChipSelectionSDUIModel value, $Res Function(ChipSelectionSDUIModel) _then) = _$ChipSelectionSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, List<ChipOption>? options, int? selectedIndex
});
}
/// @nodoc
class _$ChipSelectionSDUIModelCopyWithImpl<$Res>
implements $ChipSelectionSDUIModelCopyWith<$Res> {
_$ChipSelectionSDUIModelCopyWithImpl(this._self, this._then);
final ChipSelectionSDUIModel _self;
final $Res Function(ChipSelectionSDUIModel) _then;
/// Create a copy of ChipSelectionSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? options = freezed,Object? selectedIndex = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,options: freezed == options ? _self.options : options // ignore: cast_nullable_to_non_nullable
as List<ChipOption>?,selectedIndex: freezed == selectedIndex ? _self.selectedIndex : selectedIndex // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// Adds pattern-matching-related methods to [ChipSelectionSDUIModel].
extension ChipSelectionSDUIModelPatterns on ChipSelectionSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ChipSelectionSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ChipSelectionSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ChipSelectionSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, List<ChipOption>? options, int? selectedIndex)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.options,_that.selectedIndex);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, List<ChipOption>? options, int? selectedIndex) $default,) {final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel():
return $default(_that.key,_that.label,_that.options,_that.selectedIndex);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, List<ChipOption>? options, int? selectedIndex)? $default,) {final _that = this;
switch (_that) {
case _ChipSelectionSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.options,_that.selectedIndex);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ChipSelectionSDUIModel implements ChipSelectionSDUIModel {
const _ChipSelectionSDUIModel({this.key, this.label, final List<ChipOption>? options, this.selectedIndex}): _options = options;
factory _ChipSelectionSDUIModel.fromJson(Map<String, dynamic> json) => _$ChipSelectionSDUIModelFromJson(json);
@override final String? key;
@override final String? label;
final List<ChipOption>? _options;
@override List<ChipOption>? get options {
final value = _options;
if (value == null) return null;
if (_options is EqualUnmodifiableListView) return _options;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override final int? selectedIndex;
/// Create a copy of ChipSelectionSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ChipSelectionSDUIModelCopyWith<_ChipSelectionSDUIModel> get copyWith => __$ChipSelectionSDUIModelCopyWithImpl<_ChipSelectionSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ChipSelectionSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChipSelectionSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&const DeepCollectionEquality().equals(other._options, _options)&&(identical(other.selectedIndex, selectedIndex) || other.selectedIndex == selectedIndex));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,const DeepCollectionEquality().hash(_options),selectedIndex);
@override
String toString() {
return 'ChipSelectionSDUIModel(key: $key, label: $label, options: $options, selectedIndex: $selectedIndex)';
}
}
/// @nodoc
abstract mixin class _$ChipSelectionSDUIModelCopyWith<$Res> implements $ChipSelectionSDUIModelCopyWith<$Res> {
factory _$ChipSelectionSDUIModelCopyWith(_ChipSelectionSDUIModel value, $Res Function(_ChipSelectionSDUIModel) _then) = __$ChipSelectionSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, List<ChipOption>? options, int? selectedIndex
});
}
/// @nodoc
class __$ChipSelectionSDUIModelCopyWithImpl<$Res>
implements _$ChipSelectionSDUIModelCopyWith<$Res> {
__$ChipSelectionSDUIModelCopyWithImpl(this._self, this._then);
final _ChipSelectionSDUIModel _self;
final $Res Function(_ChipSelectionSDUIModel) _then;
/// Create a copy of ChipSelectionSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? options = freezed,Object? selectedIndex = freezed,}) {
return _then(_ChipSelectionSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,options: freezed == options ? _self._options : options // ignore: cast_nullable_to_non_nullable
as List<ChipOption>?,selectedIndex: freezed == selectedIndex ? _self.selectedIndex : selectedIndex // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// @nodoc
mixin _$ChipOption {
int? get index; String? get label; String? get value;
/// Create a copy of ChipOption
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ChipOptionCopyWith<ChipOption> get copyWith => _$ChipOptionCopyWithImpl<ChipOption>(this as ChipOption, _$identity);
/// Serializes this ChipOption to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ChipOption&&(identical(other.index, index) || other.index == index)&&(identical(other.label, label) || other.label == label)&&(identical(other.value, value) || other.value == value));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,index,label,value);
@override
String toString() {
return 'ChipOption(index: $index, label: $label, value: $value)';
}
}
/// @nodoc
abstract mixin class $ChipOptionCopyWith<$Res> {
factory $ChipOptionCopyWith(ChipOption value, $Res Function(ChipOption) _then) = _$ChipOptionCopyWithImpl;
@useResult
$Res call({
int? index, String? label, String? value
});
}
/// @nodoc
class _$ChipOptionCopyWithImpl<$Res>
implements $ChipOptionCopyWith<$Res> {
_$ChipOptionCopyWithImpl(this._self, this._then);
final ChipOption _self;
final $Res Function(ChipOption) _then;
/// Create a copy of ChipOption
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? index = freezed,Object? label = freezed,Object? value = freezed,}) {
return _then(_self.copyWith(
index: freezed == index ? _self.index : index // ignore: cast_nullable_to_non_nullable
as int?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
/// Adds pattern-matching-related methods to [ChipOption].
extension ChipOptionPatterns on ChipOption {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ChipOption value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ChipOption() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ChipOption value) $default,){
final _that = this;
switch (_that) {
case _ChipOption():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ChipOption value)? $default,){
final _that = this;
switch (_that) {
case _ChipOption() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( int? index, String? label, String? value)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ChipOption() when $default != null:
return $default(_that.index,_that.label,_that.value);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( int? index, String? label, String? value) $default,) {final _that = this;
switch (_that) {
case _ChipOption():
return $default(_that.index,_that.label,_that.value);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( int? index, String? label, String? value)? $default,) {final _that = this;
switch (_that) {
case _ChipOption() when $default != null:
return $default(_that.index,_that.label,_that.value);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ChipOption implements ChipOption {
const _ChipOption({this.index, this.label, this.value});
factory _ChipOption.fromJson(Map<String, dynamic> json) => _$ChipOptionFromJson(json);
@override final int? index;
@override final String? label;
@override final String? value;
/// Create a copy of ChipOption
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ChipOptionCopyWith<_ChipOption> get copyWith => __$ChipOptionCopyWithImpl<_ChipOption>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ChipOptionToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ChipOption&&(identical(other.index, index) || other.index == index)&&(identical(other.label, label) || other.label == label)&&(identical(other.value, value) || other.value == value));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,index,label,value);
@override
String toString() {
return 'ChipOption(index: $index, label: $label, value: $value)';
}
}
/// @nodoc
abstract mixin class _$ChipOptionCopyWith<$Res> implements $ChipOptionCopyWith<$Res> {
factory _$ChipOptionCopyWith(_ChipOption value, $Res Function(_ChipOption) _then) = __$ChipOptionCopyWithImpl;
@override @useResult
$Res call({
int? index, String? label, String? value
});
}
/// @nodoc
class __$ChipOptionCopyWithImpl<$Res>
implements _$ChipOptionCopyWith<$Res> {
__$ChipOptionCopyWithImpl(this._self, this._then);
final _ChipOption _self;
final $Res Function(_ChipOption) _then;
/// Create a copy of ChipOption
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? index = freezed,Object? label = freezed,Object? value = freezed,}) {
return _then(_ChipOption(
index: freezed == index ? _self.index : index // ignore: cast_nullable_to_non_nullable
as int?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
// dart format on

View File

@@ -0,0 +1,40 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'chip_selection_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_ChipSelectionSDUIModel _$ChipSelectionSDUIModelFromJson(
Map<String, dynamic> json,
) => _ChipSelectionSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
options: (json['options'] as List<dynamic>?)
?.map((e) => ChipOption.fromJson(e as Map<String, dynamic>))
.toList(),
selectedIndex: (json['selected_index'] as num?)?.toInt(),
);
Map<String, dynamic> _$ChipSelectionSDUIModelToJson(
_ChipSelectionSDUIModel instance,
) => <String, dynamic>{
'key': instance.key,
'label': instance.label,
'options': instance.options,
'selected_index': instance.selectedIndex,
};
_ChipOption _$ChipOptionFromJson(Map<String, dynamic> json) => _ChipOption(
index: (json['index'] as num?)?.toInt(),
label: json['label'] as String?,
value: json['value'] as String?,
);
Map<String, dynamic> _$ChipOptionToJson(_ChipOption instance) =>
<String, dynamic>{
'index': instance.index,
'label': instance.label,
'value': instance.value,
};

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/dropdown/model/dropdown_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class DropdownSDUI extends StatelessWidget {
final DropdownSDUIModel model;
final RxMap<String, dynamic>? state;
final Function(String key, String value)? onChanged;
const DropdownSDUI({
super.key,
required this.model,
this.state,
this.onChanged,
});
@override
Widget build(BuildContext context) {
final items = model.items ?? [];
if (items.isEmpty) {
return const SizedBox.shrink();
}
return Obx(() {
final selectedValue = state?[model.key] as String? ?? model.selectedValue;
return ResourceOverlayDropdown<String>(
items: Resource.success(items),
selectedItem: selectedValue,
onChanged: (item) {
if (onChanged != null && model.key != null) {
onChanged!(model.key!, item);
}
},
itemBuilder: (item) => Text(item),
labelBuilder: (selected) =>
Text(selected ?? (model.placeholder ?? model.label ?? '')),
isDisabled: model.enabled == false,
);
});
}
}

View File

@@ -0,0 +1,20 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'dropdown_sdui_model.freezed.dart';
part 'dropdown_sdui_model.g.dart';
@freezed
abstract class DropdownSDUIModel with _$DropdownSDUIModel {
const factory DropdownSDUIModel({
String? key,
String? label,
String? placeholder,
List<String>? items,
String? selectedValue,
bool? enabled,
}) = _DropdownSDUIModel;
factory DropdownSDUIModel.fromJson(Map<String, dynamic> json) =>
_$DropdownSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,300 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'dropdown_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$DropdownSDUIModel {
String? get key; String? get label; String? get placeholder; List<String>? get items; String? get selectedValue; bool? get enabled;
/// Create a copy of DropdownSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$DropdownSDUIModelCopyWith<DropdownSDUIModel> get copyWith => _$DropdownSDUIModelCopyWithImpl<DropdownSDUIModel>(this as DropdownSDUIModel, _$identity);
/// Serializes this DropdownSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is DropdownSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.placeholder, placeholder) || other.placeholder == placeholder)&&const DeepCollectionEquality().equals(other.items, items)&&(identical(other.selectedValue, selectedValue) || other.selectedValue == selectedValue)&&(identical(other.enabled, enabled) || other.enabled == enabled));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,placeholder,const DeepCollectionEquality().hash(items),selectedValue,enabled);
@override
String toString() {
return 'DropdownSDUIModel(key: $key, label: $label, placeholder: $placeholder, items: $items, selectedValue: $selectedValue, enabled: $enabled)';
}
}
/// @nodoc
abstract mixin class $DropdownSDUIModelCopyWith<$Res> {
factory $DropdownSDUIModelCopyWith(DropdownSDUIModel value, $Res Function(DropdownSDUIModel) _then) = _$DropdownSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, String? placeholder, List<String>? items, String? selectedValue, bool? enabled
});
}
/// @nodoc
class _$DropdownSDUIModelCopyWithImpl<$Res>
implements $DropdownSDUIModelCopyWith<$Res> {
_$DropdownSDUIModelCopyWithImpl(this._self, this._then);
final DropdownSDUIModel _self;
final $Res Function(DropdownSDUIModel) _then;
/// Create a copy of DropdownSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? placeholder = freezed,Object? items = freezed,Object? selectedValue = freezed,Object? enabled = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,placeholder: freezed == placeholder ? _self.placeholder : placeholder // ignore: cast_nullable_to_non_nullable
as String?,items: freezed == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
as List<String>?,selectedValue: freezed == selectedValue ? _self.selectedValue : selectedValue // ignore: cast_nullable_to_non_nullable
as String?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
/// Adds pattern-matching-related methods to [DropdownSDUIModel].
extension DropdownSDUIModelPatterns on DropdownSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _DropdownSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _DropdownSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _DropdownSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _DropdownSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _DropdownSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _DropdownSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, String? placeholder, List<String>? items, String? selectedValue, bool? enabled)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _DropdownSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.placeholder,_that.items,_that.selectedValue,_that.enabled);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, String? placeholder, List<String>? items, String? selectedValue, bool? enabled) $default,) {final _that = this;
switch (_that) {
case _DropdownSDUIModel():
return $default(_that.key,_that.label,_that.placeholder,_that.items,_that.selectedValue,_that.enabled);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, String? placeholder, List<String>? items, String? selectedValue, bool? enabled)? $default,) {final _that = this;
switch (_that) {
case _DropdownSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.placeholder,_that.items,_that.selectedValue,_that.enabled);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _DropdownSDUIModel implements DropdownSDUIModel {
const _DropdownSDUIModel({this.key, this.label, this.placeholder, final List<String>? items, this.selectedValue, this.enabled}): _items = items;
factory _DropdownSDUIModel.fromJson(Map<String, dynamic> json) => _$DropdownSDUIModelFromJson(json);
@override final String? key;
@override final String? label;
@override final String? placeholder;
final List<String>? _items;
@override List<String>? get items {
final value = _items;
if (value == null) return null;
if (_items is EqualUnmodifiableListView) return _items;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override final String? selectedValue;
@override final bool? enabled;
/// Create a copy of DropdownSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$DropdownSDUIModelCopyWith<_DropdownSDUIModel> get copyWith => __$DropdownSDUIModelCopyWithImpl<_DropdownSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$DropdownSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _DropdownSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.placeholder, placeholder) || other.placeholder == placeholder)&&const DeepCollectionEquality().equals(other._items, _items)&&(identical(other.selectedValue, selectedValue) || other.selectedValue == selectedValue)&&(identical(other.enabled, enabled) || other.enabled == enabled));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,placeholder,const DeepCollectionEquality().hash(_items),selectedValue,enabled);
@override
String toString() {
return 'DropdownSDUIModel(key: $key, label: $label, placeholder: $placeholder, items: $items, selectedValue: $selectedValue, enabled: $enabled)';
}
}
/// @nodoc
abstract mixin class _$DropdownSDUIModelCopyWith<$Res> implements $DropdownSDUIModelCopyWith<$Res> {
factory _$DropdownSDUIModelCopyWith(_DropdownSDUIModel value, $Res Function(_DropdownSDUIModel) _then) = __$DropdownSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, String? placeholder, List<String>? items, String? selectedValue, bool? enabled
});
}
/// @nodoc
class __$DropdownSDUIModelCopyWithImpl<$Res>
implements _$DropdownSDUIModelCopyWith<$Res> {
__$DropdownSDUIModelCopyWithImpl(this._self, this._then);
final _DropdownSDUIModel _self;
final $Res Function(_DropdownSDUIModel) _then;
/// Create a copy of DropdownSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? placeholder = freezed,Object? items = freezed,Object? selectedValue = freezed,Object? enabled = freezed,}) {
return _then(_DropdownSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,placeholder: freezed == placeholder ? _self.placeholder : placeholder // ignore: cast_nullable_to_non_nullable
as String?,items: freezed == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
as List<String>?,selectedValue: freezed == selectedValue ? _self.selectedValue : selectedValue // ignore: cast_nullable_to_non_nullable
as String?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
// dart format on

View File

@@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'dropdown_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_DropdownSDUIModel _$DropdownSDUIModelFromJson(Map<String, dynamic> json) =>
_DropdownSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
placeholder: json['placeholder'] as String?,
items: (json['items'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
selectedValue: json['selected_value'] as String?,
enabled: json['enabled'] as bool?,
);
Map<String, dynamic> _$DropdownSDUIModelToJson(_DropdownSDUIModel instance) =>
<String, dynamic>{
'key': instance.key,
'label': instance.label,
'placeholder': instance.placeholder,
'items': instance.items,
'selected_value': instance.selectedValue,
'enabled': instance.enabled,
};

View File

@@ -0,0 +1,251 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/image_picker/model/image_picker_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class ImagePickerSDUI extends StatefulWidget {
final ImagePickerSDUIModel model;
final Map<String, RxList<XFile>>? images;
final Function(String key, RxList<XFile> images)? onImagesChanged;
const ImagePickerSDUI({
super.key,
required this.model,
this.images,
this.onImagesChanged,
});
@override
State<ImagePickerSDUI> createState() => _ImagePickerSDUIState();
}
class _ImagePickerSDUIState extends State<ImagePickerSDUI> {
late RImagePickerController imagePickerController;
RxList<XFile>? imageList;
Set<String> _addedImagePaths = {}; // برای track کردن عکس‌های اضافه شده
@override
void initState() {
super.initState();
imagePickerController = RImagePickerController();
final key = widget.model.key ?? '';
if (key.isNotEmpty) {
// Get or create the images list for this key
if (widget.images != null && widget.images!.containsKey(key)) {
imageList = widget.images![key]!;
// اضافه کردن path های عکس‌های موجود به set
_addedImagePaths = imageList!.map((img) => img.path).toSet();
} else {
imageList = RxList<XFile>();
if (widget.images != null) {
widget.images![key] = imageList!;
}
_addedImagePaths = {};
}
imagePickerController.capturedImages.clear();
// Listen to controller changes
imagePickerController.addListener(() {
if (imagePickerController.capturedImages.isNotEmpty &&
imageList != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final maxImages = widget.model.maxImages;
final allCapturedImages = imagePickerController.capturedImages;
// فقط عکس‌های جدید را پیدا می‌کنیم (عکس‌هایی که قبلاً اضافه نشده‌اند)
final newImages = allCapturedImages
.where((img) => !_addedImagePaths.contains(img.path))
.toList();
if (newImages.isNotEmpty) {
if (maxImages != null) {
// اگر محدودیت وجود دارد، فقط تا maxImages عکس اضافه می‌کنیم
final currentCount = imageList!.length;
final remainingSlots = maxImages - currentCount;
if (remainingSlots > 0) {
final imagesToAdd = newImages.take(remainingSlots).toList();
imageList!.addAll(imagesToAdd);
// اضافه کردن path های عکس‌های جدید به set
_addedImagePaths.addAll(imagesToAdd.map((img) => img.path));
}
} else {
// اگر محدودیت وجود ندارد، همه عکس‌های جدید را اضافه می‌کنیم
imageList!.addAll(newImages);
// اضافه کردن path های عکس‌های جدید به set
_addedImagePaths.addAll(newImages.map((img) => img.path));
}
}
if (widget.onImagesChanged != null) {
widget.onImagesChanged!(key, imageList!);
}
});
}
});
}
}
@override
void dispose() {
imagePickerController.disposeCameraController();
super.dispose();
}
@override
Widget build(BuildContext context) {
final key = widget.model.key ?? '';
if (key.isEmpty || imageList == null) {
return const SizedBox.shrink();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 10.h),
Row(
children: [
Expanded(
child: Obx(() {
final maxImages = widget.model.maxImages;
final currentImageCount = imageList!.length;
final canAddMore =
maxImages == null || currentImageCount < maxImages;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: BouncingScrollPhysics(),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8,
children: [
...imageList!.map(
(entry) => Stack(
children: [
Container(
height: 80.h,
width: 80.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.path),
fit: BoxFit.cover,
),
),
),
// Delete button
Positioned(
top: 4,
left: 4,
child: GestureDetector(
onTap: () {
imageList!.removeWhere(
(element) => element.path == entry.path,
);
// حذف path از set
_addedImagePaths.remove(entry.path);
if (widget.onImagesChanged != null) {
widget.onImagesChanged!(key, imageList!);
}
},
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 16,
),
),
),
),
],
),
),
// Add image button - only show if we can add more
if (canAddMore)
GestureDetector(
onTap: () {
imagePickerController.capturedImages.clear();
final existingPaths = imageList!
.map((img) => img.path)
.toSet();
_addedImagePaths = existingPaths;
Get.to(
() => RImagePicker(
controller: imagePickerController,
maxImages: maxImages != null
? maxImages - currentImageCount
: null,
),
fullscreenDialog: true,
transition: Transition.fade,
duration: Duration(milliseconds: 300),
);
},
child: Container(
height: 80.h,
width: 80.w,
padding: EdgeInsets.all(22),
decoration: BoxDecoration(
color: Color(0xFFE9E9E9),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
borderRadius: BorderRadius.circular(8),
),
child: Assets.vec.galleryAddSvg.svg(
width: 36,
height: 36,
),
),
),
],
),
);
}),
),
],
),
if (widget.model.label != null && widget.model.label!.isNotEmpty) ...[
SizedBox(height: 9.h),
RichText(
text: TextSpan(
children: [
TextSpan(
text: widget.model.label!,
style: AppFonts.yekan14.copyWith(
color: AppColor.textColorLight,
),
),
if (widget.model.required == true)
TextSpan(
text: ' *',
style: AppFonts.yekan14.copyWith(color: Colors.red),
),
],
),
),
],
],
);
}
}

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'image_picker_sdui_model.freezed.dart';
part 'image_picker_sdui_model.g.dart';
@freezed
abstract class ImagePickerSDUIModel with _$ImagePickerSDUIModel {
const factory ImagePickerSDUIModel({
String? key,
String? label,
bool? required,
int? maxImages,
}) = _ImagePickerSDUIModel;
factory ImagePickerSDUIModel.fromJson(Map<String, dynamic> json) =>
_$ImagePickerSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,286 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'image_picker_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ImagePickerSDUIModel {
String? get key; String? get label; bool? get required; int? get maxImages;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ImagePickerSDUIModelCopyWith<ImagePickerSDUIModel> get copyWith => _$ImagePickerSDUIModelCopyWithImpl<ImagePickerSDUIModel>(this as ImagePickerSDUIModel, _$identity);
/// Serializes this ImagePickerSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ImagePickerSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.required, required) || other.required == required)&&(identical(other.maxImages, maxImages) || other.maxImages == maxImages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,required,maxImages);
@override
String toString() {
return 'ImagePickerSDUIModel(key: $key, label: $label, required: $required, maxImages: $maxImages)';
}
}
/// @nodoc
abstract mixin class $ImagePickerSDUIModelCopyWith<$Res> {
factory $ImagePickerSDUIModelCopyWith(ImagePickerSDUIModel value, $Res Function(ImagePickerSDUIModel) _then) = _$ImagePickerSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, bool? required, int? maxImages
});
}
/// @nodoc
class _$ImagePickerSDUIModelCopyWithImpl<$Res>
implements $ImagePickerSDUIModelCopyWith<$Res> {
_$ImagePickerSDUIModelCopyWithImpl(this._self, this._then);
final ImagePickerSDUIModel _self;
final $Res Function(ImagePickerSDUIModel) _then;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? required = freezed,Object? maxImages = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,maxImages: freezed == maxImages ? _self.maxImages : maxImages // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// Adds pattern-matching-related methods to [ImagePickerSDUIModel].
extension ImagePickerSDUIModelPatterns on ImagePickerSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _ImagePickerSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _ImagePickerSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _ImagePickerSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, bool? required, int? maxImages)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, bool? required, int? maxImages) $default,) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel():
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, bool? required, int? maxImages)? $default,) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ImagePickerSDUIModel implements ImagePickerSDUIModel {
const _ImagePickerSDUIModel({this.key, this.label, this.required, this.maxImages});
factory _ImagePickerSDUIModel.fromJson(Map<String, dynamic> json) => _$ImagePickerSDUIModelFromJson(json);
@override final String? key;
@override final String? label;
@override final bool? required;
@override final int? maxImages;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ImagePickerSDUIModelCopyWith<_ImagePickerSDUIModel> get copyWith => __$ImagePickerSDUIModelCopyWithImpl<_ImagePickerSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ImagePickerSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ImagePickerSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.required, required) || other.required == required)&&(identical(other.maxImages, maxImages) || other.maxImages == maxImages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,required,maxImages);
@override
String toString() {
return 'ImagePickerSDUIModel(key: $key, label: $label, required: $required, maxImages: $maxImages)';
}
}
/// @nodoc
abstract mixin class _$ImagePickerSDUIModelCopyWith<$Res> implements $ImagePickerSDUIModelCopyWith<$Res> {
factory _$ImagePickerSDUIModelCopyWith(_ImagePickerSDUIModel value, $Res Function(_ImagePickerSDUIModel) _then) = __$ImagePickerSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, bool? required, int? maxImages
});
}
/// @nodoc
class __$ImagePickerSDUIModelCopyWithImpl<$Res>
implements _$ImagePickerSDUIModelCopyWith<$Res> {
__$ImagePickerSDUIModelCopyWithImpl(this._self, this._then);
final _ImagePickerSDUIModel _self;
final $Res Function(_ImagePickerSDUIModel) _then;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? required = freezed,Object? maxImages = freezed,}) {
return _then(_ImagePickerSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,maxImages: freezed == maxImages ? _self.maxImages : maxImages // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
// dart format on

View File

@@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'image_picker_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_ImagePickerSDUIModel _$ImagePickerSDUIModelFromJson(
Map<String, dynamic> json,
) => _ImagePickerSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
required: json['required'] as bool?,
maxImages: (json['max_images'] as num?)?.toInt(),
);
Map<String, dynamic> _$ImagePickerSDUIModelToJson(
_ImagePickerSDUIModel instance,
) => <String, dynamic>{
'key': instance.key,
'label': instance.label,
'required': instance.required,
'max_images': instance.maxImages,
};

View File

@@ -0,0 +1,76 @@
# PageView SDUI Widget
این ویجت برای استفاده از PageView در ساختار SDUI طراحی شده است.
## استفاده در کد
```dart
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/page_view_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/model/page_view_sdui_model.dart';
// ایجاد مدل
final pageViewModel = PageViewSDUIModel(
key: 'pageController', // کلید برای دسترسی به PageController
reverse: true,
physics: 'neverScrollable', // 'neverScrollable', 'bouncing', 'clamping', 'alwaysScrollable'
itemCount: 5,
);
// استفاده از ویجت
PageViewSDUI(
model: pageViewModel,
controller: controller.pageController, // PageController از logic
children: pages, // لیست صفحات
)
```
## استفاده در JSON
```json
{
"type": "page_view",
"visible": true,
"data": {
"key": "pageController",
"reverse": true,
"physics": "neverScrollable",
"itemCount": 5
},
"children": [
{
"type": "column",
"visible": true,
"children": [...]
}
]
}
```
## پارامترها
- `key`: کلید برای دسترسی به PageController از map
- `reverse`: جهت معکوس (پیش‌فرض: true)
- `physics`: نوع فیزیک اسکرول ('neverScrollable', 'bouncing', 'clamping', 'alwaysScrollable')
- `itemCount`: تعداد آیتم‌ها (پیش‌فرض: تعداد children)
## مثال استفاده در create_inspection_bottom_sheet.dart
```dart
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/page_view_sdui.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/model/page_view_sdui_model.dart';
// در build method:
Expanded(
child: PageViewSDUI(
model: PageViewSDUIModel(
key: 'pageController',
reverse: true,
physics: 'neverScrollable',
itemCount: pages.length,
),
controller: controller.pageController,
children: pages,
),
),
```

View File

@@ -0,0 +1,46 @@
{
"type": "page_view",
"visible": true,
"data": {
"key": "pageController",
"reverse": true,
"physics": "neverScrollable",
"itemCount": 5
},
"children": [
{
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "field1",
"label": "Field 1"
}
}
]
},
{
"type": "column",
"visible": true,
"data": {
"spacing": 10.0
},
"children": [
{
"type": "text_form_field",
"visible": true,
"data": {
"key": "field2",
"label": "Field 2"
}
}
]
}
]
}

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'page_view_sdui_model.freezed.dart';
part 'page_view_sdui_model.g.dart';
@freezed
abstract class PageViewSDUIModel with _$PageViewSDUIModel {
const factory PageViewSDUIModel({
String? key,
bool? reverse,
String? physics, // 'neverScrollable', 'bouncing', 'clamping', 'alwaysScrollable'
int? itemCount,
}) = _PageViewSDUIModel;
factory PageViewSDUIModel.fromJson(Map<String, dynamic> json) =>
_$PageViewSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,288 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'page_view_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$PageViewSDUIModel {
String? get key; bool? get reverse; String? get physics;// 'neverScrollable', 'bouncing', 'clamping', 'alwaysScrollable'
int? get itemCount;
/// Create a copy of PageViewSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$PageViewSDUIModelCopyWith<PageViewSDUIModel> get copyWith => _$PageViewSDUIModelCopyWithImpl<PageViewSDUIModel>(this as PageViewSDUIModel, _$identity);
/// Serializes this PageViewSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is PageViewSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.reverse, reverse) || other.reverse == reverse)&&(identical(other.physics, physics) || other.physics == physics)&&(identical(other.itemCount, itemCount) || other.itemCount == itemCount));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,reverse,physics,itemCount);
@override
String toString() {
return 'PageViewSDUIModel(key: $key, reverse: $reverse, physics: $physics, itemCount: $itemCount)';
}
}
/// @nodoc
abstract mixin class $PageViewSDUIModelCopyWith<$Res> {
factory $PageViewSDUIModelCopyWith(PageViewSDUIModel value, $Res Function(PageViewSDUIModel) _then) = _$PageViewSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, bool? reverse, String? physics, int? itemCount
});
}
/// @nodoc
class _$PageViewSDUIModelCopyWithImpl<$Res>
implements $PageViewSDUIModelCopyWith<$Res> {
_$PageViewSDUIModelCopyWithImpl(this._self, this._then);
final PageViewSDUIModel _self;
final $Res Function(PageViewSDUIModel) _then;
/// Create a copy of PageViewSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? reverse = freezed,Object? physics = freezed,Object? itemCount = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,reverse: freezed == reverse ? _self.reverse : reverse // ignore: cast_nullable_to_non_nullable
as bool?,physics: freezed == physics ? _self.physics : physics // ignore: cast_nullable_to_non_nullable
as String?,itemCount: freezed == itemCount ? _self.itemCount : itemCount // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// Adds pattern-matching-related methods to [PageViewSDUIModel].
extension PageViewSDUIModelPatterns on PageViewSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _PageViewSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _PageViewSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _PageViewSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _PageViewSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _PageViewSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _PageViewSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, bool? reverse, String? physics, int? itemCount)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _PageViewSDUIModel() when $default != null:
return $default(_that.key,_that.reverse,_that.physics,_that.itemCount);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, bool? reverse, String? physics, int? itemCount) $default,) {final _that = this;
switch (_that) {
case _PageViewSDUIModel():
return $default(_that.key,_that.reverse,_that.physics,_that.itemCount);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, bool? reverse, String? physics, int? itemCount)? $default,) {final _that = this;
switch (_that) {
case _PageViewSDUIModel() when $default != null:
return $default(_that.key,_that.reverse,_that.physics,_that.itemCount);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _PageViewSDUIModel implements PageViewSDUIModel {
const _PageViewSDUIModel({this.key, this.reverse, this.physics, this.itemCount});
factory _PageViewSDUIModel.fromJson(Map<String, dynamic> json) => _$PageViewSDUIModelFromJson(json);
@override final String? key;
@override final bool? reverse;
@override final String? physics;
// 'neverScrollable', 'bouncing', 'clamping', 'alwaysScrollable'
@override final int? itemCount;
/// Create a copy of PageViewSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$PageViewSDUIModelCopyWith<_PageViewSDUIModel> get copyWith => __$PageViewSDUIModelCopyWithImpl<_PageViewSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$PageViewSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PageViewSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.reverse, reverse) || other.reverse == reverse)&&(identical(other.physics, physics) || other.physics == physics)&&(identical(other.itemCount, itemCount) || other.itemCount == itemCount));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,reverse,physics,itemCount);
@override
String toString() {
return 'PageViewSDUIModel(key: $key, reverse: $reverse, physics: $physics, itemCount: $itemCount)';
}
}
/// @nodoc
abstract mixin class _$PageViewSDUIModelCopyWith<$Res> implements $PageViewSDUIModelCopyWith<$Res> {
factory _$PageViewSDUIModelCopyWith(_PageViewSDUIModel value, $Res Function(_PageViewSDUIModel) _then) = __$PageViewSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, bool? reverse, String? physics, int? itemCount
});
}
/// @nodoc
class __$PageViewSDUIModelCopyWithImpl<$Res>
implements _$PageViewSDUIModelCopyWith<$Res> {
__$PageViewSDUIModelCopyWithImpl(this._self, this._then);
final _PageViewSDUIModel _self;
final $Res Function(_PageViewSDUIModel) _then;
/// Create a copy of PageViewSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? reverse = freezed,Object? physics = freezed,Object? itemCount = freezed,}) {
return _then(_PageViewSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,reverse: freezed == reverse ? _self.reverse : reverse // ignore: cast_nullable_to_non_nullable
as bool?,physics: freezed == physics ? _self.physics : physics // ignore: cast_nullable_to_non_nullable
as String?,itemCount: freezed == itemCount ? _self.itemCount : itemCount // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
// dart format on

View File

@@ -0,0 +1,23 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'page_view_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_PageViewSDUIModel _$PageViewSDUIModelFromJson(Map<String, dynamic> json) =>
_PageViewSDUIModel(
key: json['key'] as String?,
reverse: json['reverse'] as bool?,
physics: json['physics'] as String?,
itemCount: (json['item_count'] as num?)?.toInt(),
);
Map<String, dynamic> _$PageViewSDUIModelToJson(_PageViewSDUIModel instance) =>
<String, dynamic>{
'key': instance.key,
'reverse': instance.reverse,
'physics': instance.physics,
'item_count': instance.itemCount,
};

View File

@@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/model/page_view_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class PageViewSDUI extends StatelessWidget {
final PageViewSDUIModel model;
final PageController? controller;
final List<Widget> children;
final RxMap<String, dynamic>? state;
final Map<String, TextEditingController>? controllers;
final Function(String key, dynamic value)? onStateChanged;
final Map<String, RxList<XFile>>? images;
final Function(String key, RxList<XFile> images)? onImagesChanged;
const PageViewSDUI({
super.key,
required this.model,
required this.children,
this.controller,
this.state,
this.controllers,
this.onStateChanged,
this.images,
this.onImagesChanged,
});
ScrollPhysics? _parsePhysics(String? physics) {
switch (physics) {
case 'neverScrollable':
return const NeverScrollableScrollPhysics();
case 'bouncing':
return const BouncingScrollPhysics();
case 'clamping':
return const ClampingScrollPhysics();
case 'alwaysScrollable':
return const AlwaysScrollableScrollPhysics();
default:
return const NeverScrollableScrollPhysics();
}
}
@override
Widget build(BuildContext context) {
final physics = _parsePhysics(model.physics);
final reverse = model.reverse ?? true;
final itemCount = model.itemCount ?? children.length;
return PageView.builder(
physics: physics,
reverse: reverse,
controller: controller,
itemCount: itemCount,
itemBuilder: (context, index) {
if (index < children.length) {
return children[index];
}
return const SizedBox.shrink();
},
);
}
}

View File

@@ -0,0 +1,9 @@
{
"type": "stepper",
"visible": true,
"data": {
"key": "activeStepperIndex",
"totalSteps": 5,
"activeStep": 0
}
}

View File

@@ -0,0 +1,16 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'stepper_sdui_model.freezed.dart';
part 'stepper_sdui_model.g.dart';
@freezed
abstract class StepperSDUIModel with _$StepperSDUIModel {
const factory StepperSDUIModel({
String? key,
int? totalSteps,
int? activeStep,
}) = _StepperSDUIModel;
factory StepperSDUIModel.fromJson(Map<String, dynamic> json) =>
_$StepperSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,283 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'stepper_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$StepperSDUIModel {
String? get key; int? get totalSteps; int? get activeStep;
/// Create a copy of StepperSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$StepperSDUIModelCopyWith<StepperSDUIModel> get copyWith => _$StepperSDUIModelCopyWithImpl<StepperSDUIModel>(this as StepperSDUIModel, _$identity);
/// Serializes this StepperSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is StepperSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.totalSteps, totalSteps) || other.totalSteps == totalSteps)&&(identical(other.activeStep, activeStep) || other.activeStep == activeStep));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,totalSteps,activeStep);
@override
String toString() {
return 'StepperSDUIModel(key: $key, totalSteps: $totalSteps, activeStep: $activeStep)';
}
}
/// @nodoc
abstract mixin class $StepperSDUIModelCopyWith<$Res> {
factory $StepperSDUIModelCopyWith(StepperSDUIModel value, $Res Function(StepperSDUIModel) _then) = _$StepperSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, int? totalSteps, int? activeStep
});
}
/// @nodoc
class _$StepperSDUIModelCopyWithImpl<$Res>
implements $StepperSDUIModelCopyWith<$Res> {
_$StepperSDUIModelCopyWithImpl(this._self, this._then);
final StepperSDUIModel _self;
final $Res Function(StepperSDUIModel) _then;
/// Create a copy of StepperSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? totalSteps = freezed,Object? activeStep = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,totalSteps: freezed == totalSteps ? _self.totalSteps : totalSteps // ignore: cast_nullable_to_non_nullable
as int?,activeStep: freezed == activeStep ? _self.activeStep : activeStep // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// Adds pattern-matching-related methods to [StepperSDUIModel].
extension StepperSDUIModelPatterns on StepperSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _StepperSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _StepperSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _StepperSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _StepperSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _StepperSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _StepperSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, int? totalSteps, int? activeStep)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _StepperSDUIModel() when $default != null:
return $default(_that.key,_that.totalSteps,_that.activeStep);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, int? totalSteps, int? activeStep) $default,) {final _that = this;
switch (_that) {
case _StepperSDUIModel():
return $default(_that.key,_that.totalSteps,_that.activeStep);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, int? totalSteps, int? activeStep)? $default,) {final _that = this;
switch (_that) {
case _StepperSDUIModel() when $default != null:
return $default(_that.key,_that.totalSteps,_that.activeStep);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _StepperSDUIModel implements StepperSDUIModel {
const _StepperSDUIModel({this.key, this.totalSteps, this.activeStep});
factory _StepperSDUIModel.fromJson(Map<String, dynamic> json) => _$StepperSDUIModelFromJson(json);
@override final String? key;
@override final int? totalSteps;
@override final int? activeStep;
/// Create a copy of StepperSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$StepperSDUIModelCopyWith<_StepperSDUIModel> get copyWith => __$StepperSDUIModelCopyWithImpl<_StepperSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$StepperSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _StepperSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.totalSteps, totalSteps) || other.totalSteps == totalSteps)&&(identical(other.activeStep, activeStep) || other.activeStep == activeStep));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,totalSteps,activeStep);
@override
String toString() {
return 'StepperSDUIModel(key: $key, totalSteps: $totalSteps, activeStep: $activeStep)';
}
}
/// @nodoc
abstract mixin class _$StepperSDUIModelCopyWith<$Res> implements $StepperSDUIModelCopyWith<$Res> {
factory _$StepperSDUIModelCopyWith(_StepperSDUIModel value, $Res Function(_StepperSDUIModel) _then) = __$StepperSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, int? totalSteps, int? activeStep
});
}
/// @nodoc
class __$StepperSDUIModelCopyWithImpl<$Res>
implements _$StepperSDUIModelCopyWith<$Res> {
__$StepperSDUIModelCopyWithImpl(this._self, this._then);
final _StepperSDUIModel _self;
final $Res Function(_StepperSDUIModel) _then;
/// Create a copy of StepperSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? totalSteps = freezed,Object? activeStep = freezed,}) {
return _then(_StepperSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,totalSteps: freezed == totalSteps ? _self.totalSteps : totalSteps // ignore: cast_nullable_to_non_nullable
as int?,activeStep: freezed == activeStep ? _self.activeStep : activeStep // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
// dart format on

View File

@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'stepper_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_StepperSDUIModel _$StepperSDUIModelFromJson(Map<String, dynamic> json) =>
_StepperSDUIModel(
key: json['key'] as String?,
totalSteps: (json['total_steps'] as num?)?.toInt(),
activeStep: (json['active_step'] as num?)?.toInt(),
);
Map<String, dynamic> _$StepperSDUIModelToJson(_StepperSDUIModel instance) =>
<String, dynamic>{
'key': instance.key,
'total_steps': instance.totalSteps,
'active_step': instance.activeStep,
};

View File

@@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/stepper/model/stepper_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class StepperSDUI extends StatelessWidget {
final StepperSDUIModel model;
final RxMap<String, dynamic>? state;
const StepperSDUI({super.key, required this.model, this.state});
@override
Widget build(BuildContext context) {
final totalSteps = model.totalSteps ?? 5;
return Obx(() {
final activeStep = state?[model.key] as int? ?? model.activeStep ?? 0;
return Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
height: 24,
width: Get.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildSteps(totalSteps, activeStep),
),
),
);
});
}
List<Widget> _buildSteps(int totalSteps, int activeStep) {
final List<Widget> widgets = [];
for (int i = 0; i < totalSteps; i++) {
// Add step circle
widgets.add(
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
color: activeStep >= i
? AppColor.greenNormalHover
: AppColor.whiteNormalActive,
shape: BoxShape.circle,
),
width: 24.w,
height: 24.h,
child: Text(
'${i + 1}',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(
color: activeStep >= i ? Colors.white : AppColor.iconColor,
),
),
),
);
// Add divider between steps (except after last step)
if (i < totalSteps - 1) {
widgets.add(
Expanded(
child: Divider(
color: activeStep >= i + 1
? AppColor.greenNormalHover
: AppColor.whiteNormalActive,
thickness: 8,
),
),
);
}
}
return widgets;
}
}

View File

@@ -0,0 +1,29 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'text_form_field_sdui_model.freezed.dart';
part 'text_form_field_sdui_model.g.dart';
@freezed
abstract class TextFormFieldSDUIModel with _$TextFormFieldSDUIModel {
const factory TextFormFieldSDUIModel({
String? key,
String? label,
String? hintText,
String? variant,
String? keyboardType,
String? value,
int? maxLength,
int? minLine,
int? maxLine,
bool? required,
bool? enabled,
bool? readonly,
bool? commaSperator,
bool? decimal,
int? decimalPlaces,
String? type,
}) = _TextFormFieldSDUIModel;
factory TextFormFieldSDUIModel.fromJson(Map<String, dynamic> json) =>
_$TextFormFieldSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,322 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'text_form_field_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$TextFormFieldSDUIModel {
String? get key; String? get label; String? get hintText; String? get variant; String? get keyboardType; String? get value; int? get maxLength; int? get minLine; int? get maxLine; bool? get required; bool? get enabled; bool? get readonly; bool? get commaSperator; bool? get decimal; int? get decimalPlaces; String? get type;
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$TextFormFieldSDUIModelCopyWith<TextFormFieldSDUIModel> get copyWith => _$TextFormFieldSDUIModelCopyWithImpl<TextFormFieldSDUIModel>(this as TextFormFieldSDUIModel, _$identity);
/// Serializes this TextFormFieldSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&(identical(other.value, value) || other.value == value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSperator, commaSperator) || other.commaSperator == commaSperator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,value,maxLength,minLine,maxLine,required,enabled,readonly,commaSperator,decimal,decimalPlaces,type);
@override
String toString() {
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSperator: $commaSperator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
}
}
/// @nodoc
abstract mixin class $TextFormFieldSDUIModelCopyWith<$Res> {
factory $TextFormFieldSDUIModelCopyWith(TextFormFieldSDUIModel value, $Res Function(TextFormFieldSDUIModel) _then) = _$TextFormFieldSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type
});
}
/// @nodoc
class _$TextFormFieldSDUIModelCopyWithImpl<$Res>
implements $TextFormFieldSDUIModelCopyWith<$Res> {
_$TextFormFieldSDUIModelCopyWithImpl(this._self, this._then);
final TextFormFieldSDUIModel _self;
final $Res Function(TextFormFieldSDUIModel) _then;
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSperator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,hintText: freezed == hintText ? _self.hintText : hintText // ignore: cast_nullable_to_non_nullable
as String?,variant: freezed == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable
as String?,keyboardType: freezed == keyboardType ? _self.keyboardType : keyboardType // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as int?,minLine: freezed == minLine ? _self.minLine : minLine // ignore: cast_nullable_to_non_nullable
as int?,maxLine: freezed == maxLine ? _self.maxLine : maxLine // ignore: cast_nullable_to_non_nullable
as int?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,readonly: freezed == readonly ? _self.readonly : readonly // ignore: cast_nullable_to_non_nullable
as bool?,commaSperator: freezed == commaSperator ? _self.commaSperator : commaSperator // ignore: cast_nullable_to_non_nullable
as bool?,decimal: freezed == decimal ? _self.decimal : decimal // ignore: cast_nullable_to_non_nullable
as bool?,decimalPlaces: freezed == decimalPlaces ? _self.decimalPlaces : decimalPlaces // ignore: cast_nullable_to_non_nullable
as int?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
/// Adds pattern-matching-related methods to [TextFormFieldSDUIModel].
extension TextFormFieldSDUIModelPatterns on TextFormFieldSDUIModel {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _TextFormFieldSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _TextFormFieldSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _TextFormFieldSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type) $default,) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel():
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type)? $default,) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _TextFormFieldSDUIModel implements TextFormFieldSDUIModel {
const _TextFormFieldSDUIModel({this.key, this.label, this.hintText, this.variant, this.keyboardType, this.value, this.maxLength, this.minLine, this.maxLine, this.required, this.enabled, this.readonly, this.commaSperator, this.decimal, this.decimalPlaces, this.type});
factory _TextFormFieldSDUIModel.fromJson(Map<String, dynamic> json) => _$TextFormFieldSDUIModelFromJson(json);
@override final String? key;
@override final String? label;
@override final String? hintText;
@override final String? variant;
@override final String? keyboardType;
@override final String? value;
@override final int? maxLength;
@override final int? minLine;
@override final int? maxLine;
@override final bool? required;
@override final bool? enabled;
@override final bool? readonly;
@override final bool? commaSperator;
@override final bool? decimal;
@override final int? decimalPlaces;
@override final String? type;
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$TextFormFieldSDUIModelCopyWith<_TextFormFieldSDUIModel> get copyWith => __$TextFormFieldSDUIModelCopyWithImpl<_TextFormFieldSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$TextFormFieldSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&(identical(other.value, value) || other.value == value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSperator, commaSperator) || other.commaSperator == commaSperator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,value,maxLength,minLine,maxLine,required,enabled,readonly,commaSperator,decimal,decimalPlaces,type);
@override
String toString() {
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSperator: $commaSperator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
}
}
/// @nodoc
abstract mixin class _$TextFormFieldSDUIModelCopyWith<$Res> implements $TextFormFieldSDUIModelCopyWith<$Res> {
factory _$TextFormFieldSDUIModelCopyWith(_TextFormFieldSDUIModel value, $Res Function(_TextFormFieldSDUIModel) _then) = __$TextFormFieldSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type
});
}
/// @nodoc
class __$TextFormFieldSDUIModelCopyWithImpl<$Res>
implements _$TextFormFieldSDUIModelCopyWith<$Res> {
__$TextFormFieldSDUIModelCopyWithImpl(this._self, this._then);
final _TextFormFieldSDUIModel _self;
final $Res Function(_TextFormFieldSDUIModel) _then;
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSperator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
return _then(_TextFormFieldSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,hintText: freezed == hintText ? _self.hintText : hintText // ignore: cast_nullable_to_non_nullable
as String?,variant: freezed == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable
as String?,keyboardType: freezed == keyboardType ? _self.keyboardType : keyboardType // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as int?,minLine: freezed == minLine ? _self.minLine : minLine // ignore: cast_nullable_to_non_nullable
as int?,maxLine: freezed == maxLine ? _self.maxLine : maxLine // ignore: cast_nullable_to_non_nullable
as int?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,readonly: freezed == readonly ? _self.readonly : readonly // ignore: cast_nullable_to_non_nullable
as bool?,commaSperator: freezed == commaSperator ? _self.commaSperator : commaSperator // ignore: cast_nullable_to_non_nullable
as bool?,decimal: freezed == decimal ? _self.decimal : decimal // ignore: cast_nullable_to_non_nullable
as bool?,decimalPlaces: freezed == decimalPlaces ? _self.decimalPlaces : decimalPlaces // ignore: cast_nullable_to_non_nullable
as int?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
as String?,
));
}
}
// dart format on

View File

@@ -0,0 +1,49 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'text_form_field_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_TextFormFieldSDUIModel _$TextFormFieldSDUIModelFromJson(
Map<String, dynamic> json,
) => _TextFormFieldSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
hintText: json['hint_text'] as String?,
variant: json['variant'] as String?,
keyboardType: json['keyboard_type'] as String?,
value: json['value'] as String?,
maxLength: (json['max_length'] as num?)?.toInt(),
minLine: (json['min_line'] as num?)?.toInt(),
maxLine: (json['max_line'] as num?)?.toInt(),
required: json['required'] as bool?,
enabled: json['enabled'] as bool?,
readonly: json['readonly'] as bool?,
commaSperator: json['comma_sperator'] as bool?,
decimal: json['decimal'] as bool?,
decimalPlaces: (json['decimal_places'] as num?)?.toInt(),
type: json['type'] as String?,
);
Map<String, dynamic> _$TextFormFieldSDUIModelToJson(
_TextFormFieldSDUIModel instance,
) => <String, dynamic>{
'key': instance.key,
'label': instance.label,
'hint_text': instance.hintText,
'variant': instance.variant,
'keyboard_type': instance.keyboardType,
'value': instance.value,
'max_length': instance.maxLength,
'min_line': instance.minLine,
'max_line': instance.maxLine,
'required': instance.required,
'enabled': instance.enabled,
'readonly': instance.readonly,
'comma_sperator': instance.commaSperator,
'decimal': instance.decimal,
'decimal_places': instance.decimalPlaces,
'type': instance.type,
};

View File

@@ -0,0 +1,28 @@
{
"type": "text_form_field",
"data": {
"key": "user_full_name",
"label": "نام و نام خانوادگی",
"hintText": "لطفاً نام خود را وارد کنید",
"variant": "normal",
"keyboardType": "text",
"maxLength": 100,
"minLine":1,
"maxLine":1,
"required": true,
"enabled": true,
"readonly": true,
"commaSperator":true,
"decimal":true,
"decimalPlaces":2,
"type": "normal"
}
}
// type => normal / date_picker /
// keyboardType => text / number

View File

@@ -0,0 +1,94 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_core/core.dart';
import 'model/text_form_field_sdui_model.dart';
Widget textFormFiledSDUI({
required TextFormFieldSDUIModel model,
TextEditingController? controller,
}) {
List<TextInputFormatter>? inputFormatters = [];
TextInputType? keyboardType;
VoidCallback? onTap;
bool isReadonly = model.readonly ?? false;
final textController = controller ?? TextEditingController(text: model.value);
if (model.type == 'date_picker') {
// برای date picker، readonly می‌کنیم و onTap اضافه می‌کنیم
isReadonly = true;
onTap = () {
// پارس کردن تاریخ فعلی اگر وجود دارد
Jalali? initialDate;
if (textController.text.isNotEmpty) {
try {
// فرض می‌کنیم تاریخ به فرمت '1404/01/01' یا '1404-01-01' است
final dateStr = textController.text.replaceAll('-', '/');
final parts = dateStr.split('/');
if (parts.length == 3) {
final year = int.tryParse(parts[0]);
final month = int.tryParse(parts[1]);
final day = int.tryParse(parts[2]);
if (year != null && month != null && day != null) {
initialDate = Jalali(year, month, day);
}
}
} catch (e) {
iLog('Error parsing date: $e');
}
}
// اگر نتوانستیم parse کنیم، از تاریخ امروز استفاده می‌کنیم
initialDate ??= Jalali.now();
// نمایش date picker
Get.bottomSheet(
modalDatePicker(
initialDate: initialDate,
onDateSelected: (selectedDate) {
// فرمت کردن تاریخ و قرار دادن در controller
textController.text = selectedDate.formatCompactDate();
},
),
isScrollControlled: true,
);
};
} else {
if (model.keyboardType == 'text') {
keyboardType = TextInputType.text;
} else if (model.keyboardType == 'number') {
final isDecimal = model.decimal ?? false;
keyboardType = TextInputType.numberWithOptions(decimal: isDecimal);
if (!isDecimal) {
inputFormatters.add(FilteringTextInputFormatter.digitsOnly);
}
}
if ((model.commaSperator ?? false) &&
(model.decimal == null || model.decimal == false)) {
inputFormatters.add(SeparatorInputFormatter());
}
}
return RTextField(
controller: textController,
onChanged: (data) {
iLog(data);
},
onTap: onTap,
label: model.label,
filled: true,
filledColor: AppColor.bgLight,
hintText: model.hintText,
keyboardType: keyboardType,
maxLength: model.maxLength,
minLines: model.minLine,
maxLines: model.maxLine,
enabled: model.enabled ?? true,
inputFormatters: inputFormatters,
readonly: isReadonly,
);
}

View File

@@ -3,6 +3,7 @@ import 'package:mocktail/mocktail.dart';
import 'package:rasadyar_chicken/features/common/data/datasources/remote/auth/auth_remote.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_info/user_info_model.dart';
import 'package:rasadyar_chicken/features/common/data/model/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_chicken/features/common/data/repositories/auth/auth_repository_imp.dart';
class MockAuthRemoteDataSource extends Mock implements AuthRemoteDataSource {}

View File

@@ -16,7 +16,6 @@ export 'package:flutter_map_animations/flutter_map_animations.dart';
export 'package:flutter_map_marker_cluster/flutter_map_marker_cluster.dart';
export 'package:flutter_map_tile_caching/flutter_map_tile_caching.dart' hide DownloadProgress;
export 'package:flutter_rating_bar/flutter_rating_bar.dart';
export 'package:device_preview_plus/device_preview_plus.dart';
export 'package:flutter_screenutil/flutter_screenutil.dart' hide DeviceType;
export 'package:flutter_secure_storage/flutter_secure_storage.dart';
export 'package:flutter_slidable/flutter_slidable.dart';
@@ -36,8 +35,7 @@ export 'package:image_cropper/image_cropper.dart';
///image picker
export 'package:image_picker/image_picker.dart';
//encryption
//export 'package:encrypt/encrypt.dart' show Encrypted;
//Map and location
export 'package:latlong2/latlong.dart';

View File

@@ -268,6 +268,9 @@ class $AssetsIconsGen {
/// File path: assets/icons/outside.svg
SvgGenImage get outside => const SvgGenImage('assets/icons/outside.svg');
/// File path: assets/icons/pattern_dam.svg
SvgGenImage get patternDam => const SvgGenImage('assets/icons/pattern_dam.svg');
/// File path: assets/icons/pdf_download.svg
SvgGenImage get pdfDownload => const SvgGenImage('assets/icons/pdf_download.svg');
@@ -469,6 +472,7 @@ class $AssetsIconsGen {
noteRemove,
ordersReceived,
outside,
patternDam,
pdfDownload,
people,
pictureFrame,
@@ -787,6 +791,9 @@ class $AssetsVecGen {
/// File path: assets/vec/outside.svg.vec
SvgGenImage get outsideSvg => const SvgGenImage.vec('assets/vec/outside.svg.vec');
/// File path: assets/vec/pattern_dam.svg.vec
SvgGenImage get patternDamSvg => const SvgGenImage.vec('assets/vec/pattern_dam.svg.vec');
/// File path: assets/vec/pdf_download.svg.vec
SvgGenImage get pdfDownloadSvg => const SvgGenImage.vec('assets/vec/pdf_download.svg.vec');
@@ -988,6 +995,7 @@ class $AssetsVecGen {
noteRemoveSvg,
ordersReceivedSvg,
outsideSvg,
patternDamSvg,
pdfDownloadSvg,
peopleSvg,
pictureFrameSvg,

Some files were not shown because too many files have changed in this diff Show More