Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f842940bef | |||
| f25b8514cd | |||
| 17f8a2d79b | |||
| 0f0fa8da09 | |||
| 6a65aa2883 | |||
| a6cf440840 | |||
| 4dcc574e19 | |||
| 26f94345f6 | |||
| fb0b817cf9 | |||
| 8c25e2c65c | |||
| dcfe9f6dcf | |||
| fc0161e261 | |||
| 71952bef5a | |||
| 0b49302434 | |||
| 60c58ef17e | |||
| 3eccf492ff | |||
| 12c6b51aac |
@@ -2,6 +2,7 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url = uri("https://archive.ito.gov.ir/gradle/maven_central/") }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
sdk.dir=C:\\Users\\Housh11\\AppData\\Local\\Android\\sdk
|
||||
flutter.sdk=C:\\src\\flutter
|
||||
flutter.buildMode=debug
|
||||
flutter.versionName=1.3.41
|
||||
flutter.versionCode=37
|
||||
flutter.versionName=1.3.42
|
||||
flutter.versionCode=38
|
||||
@@ -10,9 +10,10 @@ pluginManagement {
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url = uri("https://archive.ito.gov.ir/gradle/maven_central/") }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
assets/icons/pattern_dam.svg
Normal file
1
assets/icons/pattern_dam.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 65 KiB |
BIN
assets/vec/pattern_dam.svg.vec
Normal file
BIN
assets/vec/pattern_dam.svg.vec
Normal file
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:rasadyar_app/data/model/app_info_model.dart';
|
||||
@@ -35,9 +36,15 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
duration: const Duration(milliseconds: 8000),
|
||||
);
|
||||
|
||||
scaleAnimation.value = Tween<double>(begin: 0.8, end: 1.2).animate(scaleController);
|
||||
scaleAnimation.value = Tween<double>(
|
||||
begin: 0.8,
|
||||
end: 1.2,
|
||||
).animate(scaleController);
|
||||
|
||||
rotationAnimation.value = Tween<double>(begin: 0.0, end: 1).animate(rotateController);
|
||||
rotationAnimation.value = Tween<double>(
|
||||
begin: 0.0,
|
||||
end: 1,
|
||||
).animate(rotateController);
|
||||
|
||||
rotateController.forward();
|
||||
rotateController.addStatusListener((status) {
|
||||
@@ -152,8 +159,10 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
|
||||
Future.delayed(const Duration(milliseconds: 250), () async {
|
||||
try {
|
||||
final isUpdateNeeded = await checkVersion();
|
||||
if (isUpdateNeeded) return;
|
||||
if (!kDebugMode) {
|
||||
final isUpdateNeeded = await checkVersion();
|
||||
if (isUpdateNeeded) return;
|
||||
}
|
||||
|
||||
final module = gService.getSelectedModule();
|
||||
final target = gService.getTargetPage(module);
|
||||
@@ -164,8 +173,6 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
if (target != null) {
|
||||
var mFuns = getFunctionsList(target.functions);
|
||||
await Future.wait(mFuns ?? []);
|
||||
|
||||
iLog("target.route ===>${target.route!}");
|
||||
Get.offAndToNamed(target.route!);
|
||||
}
|
||||
} catch (e, st) {
|
||||
@@ -185,7 +192,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
try {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
int version = info.version.versionNumber;
|
||||
var res = await _dio.get("https://rsibackend.rasadyar.com/app/rasadyar-app-info/");
|
||||
var res = await _dio.get(
|
||||
"https://rsibackend.rasadyar.com/app/rasadyar-app-info/",
|
||||
);
|
||||
|
||||
appInfoModel = AppInfoModel.fromJson(res.data);
|
||||
|
||||
@@ -244,7 +253,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
||||
Future<void> installApk() async {
|
||||
try {
|
||||
eLog(_updateFilePath.value);
|
||||
await platform.invokeMethod('apk_installer', {'appPath': _updateFilePath.value});
|
||||
await platform.invokeMethod('apk_installer', {
|
||||
'appPath': _updateFilePath.value,
|
||||
});
|
||||
} catch (e) {
|
||||
eLog(e);
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"format-version":[1,0,0],"native-assets":{}}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"]}
|
||||
@@ -1 +0,0 @@
|
||||
[{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}]
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
{"format-version":[1,0,0],"native-assets":{}}
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
@@ -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 {
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -431,3 +431,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -619,6 +619,7 @@ GestureDetector containerChips({
|
||||
onTap: () => onTap(index),
|
||||
child: Container(
|
||||
height: 24.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
||||
decoration: BoxDecoration(
|
||||
color: index == selectedIndex
|
||||
? AppColor.green1Normal
|
||||
|
||||
@@ -12,4 +12,8 @@ abstract class VetFarmRemoteDataSource {
|
||||
required String token,
|
||||
required SubmitInspectionResponse request,
|
||||
});
|
||||
|
||||
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({
|
||||
required String token,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
|
||||
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
|
||||
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
|
||||
import 'package:rasadyar_chicken/features/vet_farm/data/datasources/remote/vet_farm_remote_data_source.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
@@ -36,4 +36,16 @@ class VetFarmRemoteDataSourceImpl implements VetFarmRemoteDataSource {
|
||||
data: request.toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({required String token}) async {
|
||||
var res = await _httpClient.get(
|
||||
'/form-information/?hatching=232&form=b1',
|
||||
headers: {'Authorization': 'Bearer $token'},
|
||||
fromJson: (json) {
|
||||
return json;
|
||||
},
|
||||
);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,9 @@ abstract class VetFarmRepository {
|
||||
required String token,
|
||||
required SubmitInspectionResponse request,
|
||||
});
|
||||
|
||||
|
||||
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({
|
||||
required String token,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,4 +27,8 @@ class VetFarmRepositoryImpl implements VetFarmRepository {
|
||||
}) async {
|
||||
return await _remote.submitInspection(token: token, request: request);
|
||||
}
|
||||
@override
|
||||
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({required String token,}) async {
|
||||
return await _remote.getSDUIForm(token: token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
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.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 onClose() {
|
||||
for (var controller in controllers.values) {
|
||||
controller.dispose();
|
||||
}
|
||||
controllers.clear();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> getSDUIForm() async {
|
||||
await safeCall(
|
||||
call: () async => await rootLogic.vetFarmRepository.getSDUIForm(
|
||||
token: rootLogic.tokenService.accessToken.value ?? '',
|
||||
),
|
||||
onSuccess: (result) {
|
||||
if (result.data != null) {
|
||||
try {
|
||||
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);
|
||||
|
||||
// Log model info using pattern matching
|
||||
final modelType =
|
||||
sduiModel.value?.maybeWhen(
|
||||
textFormField: (data, visible, visibleCondition) => 'text_form_field',
|
||||
cardLabelItem: (data, child, children, visible, visibleCondition) =>
|
||||
'card_label_item',
|
||||
chipSelection: (data, visible, visibleCondition) => 'chip_selection',
|
||||
dropdown: (data, visible, visibleCondition) => 'dropdown',
|
||||
imagePicker: (data, visible, visibleCondition) => 'image_picker',
|
||||
column:
|
||||
(
|
||||
children,
|
||||
spacing,
|
||||
mainAxisSize,
|
||||
crossAxisAlignment,
|
||||
visible,
|
||||
paddingHorizontal,
|
||||
paddingVertical,
|
||||
visibleCondition,
|
||||
) => 'column',
|
||||
row: (children, spacing, mainAxisAlignment, visible, visibleCondition) => 'row',
|
||||
sizedBox: (width, height, visible, visibleCondition) => 'sized_box',
|
||||
stepper: (data, children, visible, visibleCondition) => 'stepper',
|
||||
pageView: (data, children, visible, visibleCondition) => 'page_view',
|
||||
orElse: () => 'unknown',
|
||||
) ??
|
||||
'null';
|
||||
|
||||
final childrenCount =
|
||||
sduiModel.value?.maybeWhen(
|
||||
column:
|
||||
(
|
||||
children,
|
||||
spacing,
|
||||
mainAxisSize,
|
||||
crossAxisAlignment,
|
||||
visible,
|
||||
paddingHorizontal,
|
||||
paddingVertical,
|
||||
visibleCondition,
|
||||
) => children.length,
|
||||
row: (children, spacing, mainAxisAlignment, visible, visibleCondition) =>
|
||||
children.length,
|
||||
cardLabelItem: (data, child, children, visible, visibleCondition) =>
|
||||
(child != null ? 1 : 0) + (children?.length ?? 0),
|
||||
stepper: (data, children, visible, visibleCondition) => children?.length ?? 0,
|
||||
pageView: (data, children, visible, visibleCondition) => children.length,
|
||||
orElse: () => 0,
|
||||
) ??
|
||||
0;
|
||||
|
||||
iLog(
|
||||
'SDUI Model parsed successfully. Type: $modelType, Visible: ${sduiModel.value?.visible}, Children count: $childrenCount',
|
||||
);
|
||||
_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) {
|
||||
// Extract text form field using pattern matching
|
||||
model.maybeWhen(
|
||||
textFormField: (data, visible, visibleCondition) {
|
||||
final key = data.key;
|
||||
final value = data.value;
|
||||
if (key != null && !controllers.containsKey(key)) {
|
||||
controllers[key] = TextEditingController(text: value.toString() ?? '');
|
||||
}
|
||||
},
|
||||
orElse: () {},
|
||||
);
|
||||
|
||||
// Recursively extract from children using pattern matching
|
||||
model.maybeWhen(
|
||||
column:
|
||||
(
|
||||
children,
|
||||
spacing,
|
||||
mainAxisSize,
|
||||
crossAxisAlignment,
|
||||
visible,
|
||||
paddingHorizontal,
|
||||
paddingVertical,
|
||||
visibleCondition,
|
||||
) {
|
||||
for (var child in children) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
},
|
||||
row: (children, spacing, mainAxisAlignment, visible, visibleCondition) {
|
||||
for (var child in children) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
},
|
||||
cardLabelItem: (data, child, children, visible, visibleCondition) {
|
||||
if (child != null) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
if (children != null) {
|
||||
for (var child in children) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
}
|
||||
},
|
||||
stepper: (data, children, visible, visibleCondition) {
|
||||
if (children != null) {
|
||||
for (var child in children) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
}
|
||||
},
|
||||
pageView: (data, children, visible, visibleCondition) {
|
||||
for (var child in children) {
|
||||
_extractTextFields(child);
|
||||
}
|
||||
},
|
||||
orElse: () {},
|
||||
);
|
||||
}
|
||||
|
||||
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');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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: () async {
|
||||
await controller.getSDUIForm();
|
||||
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
|
||||
BaseBottomSheet(
|
||||
height: Get.height * 0.8,
|
||||
rootChild: 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),
|
||||
|
||||
RElevated(
|
||||
text: '222222222222دکمه نمونه',
|
||||
onPressed: () {
|
||||
Get.bottomSheet(
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
|
||||
BaseBottomSheet(
|
||||
height: Get.height * 0.8,
|
||||
rootChild: Column(
|
||||
children: [
|
||||
Container(height: 100, width: 100, color: Colors.red),
|
||||
Expanded(child: Container(color: Colors.blue)),
|
||||
Container(height: 100, width: 100, color: Colors.green),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}),
|
||||
|
||||
],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class ConditionEvaluator {
|
||||
static bool check(String? condition, RxMap<String, dynamic>? state) {
|
||||
if (condition == null || condition.isEmpty) return true;
|
||||
if (state == null) {
|
||||
return condition.contains('activeStepperIndex == 0');
|
||||
}
|
||||
|
||||
try {
|
||||
if (condition.contains(' == ')) {
|
||||
final parts = condition.split(' == ');
|
||||
if (parts.length != 2) return true;
|
||||
|
||||
final key = parts[0].trim();
|
||||
var expectedValue = parts[1].trim();
|
||||
|
||||
// Remove quotes
|
||||
if ((expectedValue.startsWith("'") && expectedValue.endsWith("'")) ||
|
||||
(expectedValue.startsWith('"') && expectedValue.endsWith('"'))) {
|
||||
expectedValue = expectedValue.substring(1, expectedValue.length - 1);
|
||||
}
|
||||
|
||||
final actualValue = state[key];
|
||||
|
||||
if (actualValue == null) {
|
||||
if (key == 'activeStepperIndex' && expectedValue == '0') return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle numeric comparison if possible
|
||||
final expectedInt = int.tryParse(expectedValue);
|
||||
if (expectedInt != null) {
|
||||
if (actualValue is int) return actualValue == expectedInt;
|
||||
if (actualValue is String) return int.tryParse(actualValue) == expectedInt;
|
||||
}
|
||||
|
||||
return actualValue.toString() == expectedValue;
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
debugPrint('Error parsing condition: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts step index without using expensive RegExp in a loop if possible,
|
||||
/// or at least centralizes the logic.
|
||||
static int? extractStepIndex(String? condition) {
|
||||
if (condition == null || !condition.contains('activeStepperIndex')) return null;
|
||||
|
||||
try {
|
||||
final parts = condition.split(' == ');
|
||||
if (parts.length == 2 && parts[0].trim() == 'activeStepperIndex') {
|
||||
return int.tryParse(parts[1].trim());
|
||||
}
|
||||
} catch (_) {}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
11
packages/chicken/lib/presentation/utils/sdui_extension.dart
Normal file
11
packages/chicken/lib/presentation/utils/sdui_extension.dart
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/stepper/model/stepper_sdui_model.dart';
|
||||
|
||||
extension SDUIModelExtensions on SDUIWidgetModel {
|
||||
// چک میکند آیا این ویجت استپر است؟
|
||||
bool get isStepper => this.maybeWhen(stepper: (_, _, _, _) => true, orElse: () => false);
|
||||
|
||||
// دیتای استپر را برمیگرداند (اگر استپر باشد)
|
||||
StepperSDUIModel? get stepperData =>
|
||||
maybeWhen(stepper: (data, _, _, _) => data, orElse: () => null);
|
||||
}
|
||||
@@ -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": "ضعیف"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"type": "dropdown",
|
||||
"visible": true,
|
||||
"data": {
|
||||
"key": "training_status",
|
||||
"label": "آموزشدیده در حوزه بهداشت و امنیت زیستی",
|
||||
"placeholder": "آموزشدیده در حوزه بهداشت و امنیت زیستی",
|
||||
"items": [
|
||||
"بله",
|
||||
"خیر"
|
||||
],
|
||||
"selectedValue": null,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
157
packages/chicken/lib/presentation/widget/sdui/example_form.json
Normal file
157
packages/chicken/lib/presentation/widget/sdui/example_form.json
Normal 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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "image_picker",
|
||||
"visible": true,
|
||||
"data": {
|
||||
"key": "hall_images",
|
||||
"label": "ثبت عکس سالن (حداقل ۳ زاویه)",
|
||||
"required": true,
|
||||
"maxImages": null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "stepper",
|
||||
"visible": true,
|
||||
"data": {
|
||||
"key": "activeStepperIndex",
|
||||
"totalSteps": 5,
|
||||
"activeStep": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rasadyar_chicken/presentation/utils/condition_evaluator.dart';
|
||||
import 'package:rasadyar_chicken/presentation/utils/sdui_extension.dart';
|
||||
// ایمپورتهای پروژه شما (اینها را طبق پروژه خودتان تنظیم کنید)
|
||||
import 'package:rasadyar_chicken/presentation/widget/sdui/form/sdui_form_widget_controller.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget.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/page_view/model/page_view_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/stepper/stepper_sdui.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_core/core.dart';
|
||||
|
||||
import '../widgets/image_picker/image_picker_sdui.dart' show ImagePickerSDUI;
|
||||
import '../widgets/image_picker/model/image_picker_sdui_model.dart' show ImagePickerSDUIModel;
|
||||
import '../widgets/stepper/model/stepper_sdui_model.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) {
|
||||
// اگر ویجت اصلی مخفی است، هیچ چیز نساز
|
||||
final isVisible = model.maybeWhen(
|
||||
textFormField: (_, v, __) => v,
|
||||
cardLabelItem: (_, __, ___, v, ____) => v,
|
||||
chipSelection: (_, v, __) => v,
|
||||
dropdown: (_, v, __) => v,
|
||||
imagePicker: (_, v, __) => v,
|
||||
column: (_, __, ___, ____, _____, ______, v, _______) => v,
|
||||
row: (_, __, ___, v, ____) => v,
|
||||
stepper: (_, __, v, ___) => v,
|
||||
pageView: (_, __, v, ___) => v,
|
||||
sizedBox: (_, __, v, ___) => v,
|
||||
orElse: () => false,
|
||||
);
|
||||
|
||||
if (!isVisible) return const SizedBox.shrink();
|
||||
|
||||
// ۱. جستجو برای استپر (فقط در فرزندان مستقیم ستون اصلی)
|
||||
StepperSDUIModel? foundStepperData;
|
||||
|
||||
model.maybeWhen(
|
||||
column: (children, _, _, _, _, _, _, _) {
|
||||
final stepperWidget = children.firstWhereOrNull((c) => c.isStepper);
|
||||
foundStepperData = stepperWidget?.stepperData;
|
||||
},
|
||||
orElse: () {},
|
||||
);
|
||||
|
||||
// ۲. اگر استپر پیدا شد، لایوت مخصوص استپر را بساز
|
||||
if (foundStepperData != null) {
|
||||
return _buildStepperLayout(model, foundStepperData!);
|
||||
}
|
||||
|
||||
// ۳. در غیر این صورت، رندر استاندارد و بازگشتی
|
||||
return _buildStandardWidget(model);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// LAYOUT BUILDERS (STEPPER & STANDARD)
|
||||
// ===========================================================================
|
||||
|
||||
Widget _buildStepperLayout(SDUIWidgetModel rootModel, StepperSDUIModel stepperData) {
|
||||
final stepperKey = stepperData.key ?? 'activeStepperIndex';
|
||||
final controllerTag = 'stepper_$stepperKey';
|
||||
|
||||
// مدیریت کنترلر GetX برای دکمههای بعدی/قبلی
|
||||
SDUIFormWidgetController formController;
|
||||
try {
|
||||
formController = Get.find<SDUIFormWidgetController>(tag: controllerTag);
|
||||
} catch (_) {
|
||||
formController = Get.put(SDUIFormWidgetController(), tag: controllerTag);
|
||||
}
|
||||
|
||||
formController.initializeStepper(stepperData.totalSteps ?? 10, stepperKey);
|
||||
|
||||
// مقداردهی اولیه استیت اگر وجود نداشته باشد
|
||||
if (state != null && !state!.containsKey(stepperKey)) {
|
||||
state![stepperKey] = 0;
|
||||
}
|
||||
|
||||
final scrollController = ScrollController();
|
||||
|
||||
// استخراج فرزندان Column اصلی برای جدا کردن محتوا از خودِ نوار استپر
|
||||
final List<SDUIWidgetModel> rawChildren = rootModel.maybeWhen(
|
||||
column: (children, _, __, ___, ____, _____, ______, _______) => children,
|
||||
orElse: () => [],
|
||||
);
|
||||
|
||||
return Obx(() {
|
||||
// فقط برای تریگر شدن بیلد هنگام تغییر استپ
|
||||
// ignore: unused_local_variable
|
||||
final currentStep = formController.currentStep.value;
|
||||
|
||||
// اسکرول به بالا هنگام تغییر صفحه
|
||||
if (scrollController.hasClients) {
|
||||
scrollController.animateTo(
|
||||
0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
// A. نوار استپر (Header)
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
|
||||
child: StepperSDUI(model: stepperData, state: state),
|
||||
),
|
||||
|
||||
// B. بدنه فرم (Scrollable Content)
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
padding: EdgeInsets.all(16.w),
|
||||
physics: const BouncingScrollPhysics(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
for (final child in rawChildren)
|
||||
// خود ویجت استپر را دوباره در بدنه رندر نکن
|
||||
if (!child.isStepper) _buildConditionAwareChild(child),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// C. دکمههای نویگیشن (Footer)
|
||||
_buildNavigationButtons(formController, stepperKey),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// این متد قبل از رندر هر ویجت، شرط `visibleCondition` را چک میکند
|
||||
Widget _buildConditionAwareChild(SDUIWidgetModel widgetModel) {
|
||||
// استخراج visibleCondition از مدل با استفاده از pattern matching
|
||||
final String? condition = widgetModel.maybeWhen(
|
||||
textFormField: (_, __, c) => c,
|
||||
cardLabelItem: (_, __, ___, ____, c) => c,
|
||||
chipSelection: (_, __, c) => c,
|
||||
dropdown: (_, __, c) => c,
|
||||
imagePicker: (_, __, c) => c,
|
||||
column: (_, _, _, _, _, _, _, c) => c,
|
||||
row: (_, __, ___, ____, c) => c,
|
||||
stepper: (_, __, ___, c) => c,
|
||||
pageView: (_, __, ___, c) => c,
|
||||
sizedBox: (_, __, ___, c) => c,
|
||||
orElse: () => null, // Should not happen given the union is exhaustive
|
||||
);
|
||||
|
||||
// بررسی شرط
|
||||
final isVisible = ConditionEvaluator.check(condition, state);
|
||||
|
||||
if (!isVisible) return const SizedBox.shrink();
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h), // فاصله پیشفرض بین آیتمها
|
||||
child: _buildStandardWidget(widgetModel),
|
||||
);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// WIDGET FACTORY (RECURSIVE MAPPER)
|
||||
// ===========================================================================
|
||||
|
||||
Widget _buildStandardWidget(SDUIWidgetModel widget) {
|
||||
// ۱. استخراج دادهها (بدون نیاز به Obx)
|
||||
final String? condition = widget.maybeWhen(
|
||||
textFormField: (_, __, c) => c,
|
||||
cardLabelItem: (_, __, ___, ____, c) => c,
|
||||
chipSelection: (_, __, c) => c,
|
||||
dropdown: (_, __, c) => c,
|
||||
imagePicker: (_, __, c) => c,
|
||||
column: (_, _, _, _, _, _, _, c) => c,
|
||||
row: (_, __, ___, ____, c) => c,
|
||||
stepper: (_, __, ___, c) => c,
|
||||
pageView: (_, __, ___, c) => c,
|
||||
sizedBox: (_, __, ___, c) => c,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
final bool isVisibleProp = widget.maybeWhen(
|
||||
textFormField: (_, v, __) => v,
|
||||
cardLabelItem: (_, __, ___, v, ____) => v,
|
||||
chipSelection: (_, v, __) => v,
|
||||
dropdown: (_, v, __) => v,
|
||||
imagePicker: (_, v, __) => v,
|
||||
column: (_, __, ___, ____, _____, ______, v, _______) => v,
|
||||
row: (_, __, ___, v, ____) => v,
|
||||
stepper: (_, __, v, ___) => v,
|
||||
pageView: (_, __, v, ___) => v,
|
||||
sizedBox: (_, __, v, ___) => v,
|
||||
orElse: () => true,
|
||||
);
|
||||
|
||||
// ۲. اگر ویجت کلاً غیرفعال است، همان اول برگرد (پرفورمنس)
|
||||
if (!isVisibleProp) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
// ۳. تابع سازنده ویجت (برای جلوگیری از تکرار کد)
|
||||
Widget buildTheWidget() {
|
||||
return widget.map(
|
||||
textFormField: (m) => _buildTextField(m.data),
|
||||
chipSelection: (m) => _buildChipSelection(m.data),
|
||||
dropdown: (m) => _buildDropdown(m.data),
|
||||
imagePicker: (m) => _buildImagePicker(m.data),
|
||||
cardLabelItem: (m) => _buildCard(m.data, m.child, m.children),
|
||||
column: (m) => _buildColumn(m.children, m.spacing, m.mainAxisSize, m.crossAxisAlignment),
|
||||
row: (m) => _buildRow(m.children, m.spacing, m.mainAxisAlignment),
|
||||
sizedBox: (m) => SizedBox(width: m.width?.w, height: m.height?.h),
|
||||
stepper: (m) => const SizedBox.shrink(),
|
||||
pageView: (m) => _buildPageView(m.data, m.children),
|
||||
);
|
||||
}
|
||||
|
||||
// ۴. تصمیمگیری هوشمند برای استفاده از Obx
|
||||
|
||||
// اگر شرطی وجود ندارد یا state نال است، نیازی به Obx نیست!
|
||||
// (چون چیزی برای تغییر کردن وجود ندارد)
|
||||
if (condition == null || condition.isEmpty || state == null) {
|
||||
return buildTheWidget();
|
||||
}
|
||||
|
||||
// ۵. فقط اگر شرط وجود داشت، Obx را فعال کن
|
||||
return Obx(() {
|
||||
// اینجا مطمئن هستیم که ConditionEvaluator وضعیت state را میخواند
|
||||
if (!ConditionEvaluator.check(condition, state)) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return buildTheWidget();
|
||||
});
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// INDIVIDUAL WIDGET BUILDERS
|
||||
// ===========================================================================
|
||||
|
||||
Widget _buildTextField(TextFormFieldSDUIModel data) {
|
||||
final key = data.key ?? 'unknown_${UniqueKey()}';
|
||||
|
||||
TextEditingController controller;
|
||||
if (controllers != null) {
|
||||
controller = controllers!.putIfAbsent(key, () => TextEditingController(text: data.value));
|
||||
} else {
|
||||
controller = TextEditingController(text: data.value);
|
||||
}
|
||||
|
||||
return textFormFiledSDUI(
|
||||
model: data,
|
||||
controller: controller,
|
||||
onChanged: (val) => onStateChanged?.call(key, val),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDropdown(DropdownSDUIModel data) {
|
||||
return DropdownSDUI(
|
||||
model: data,
|
||||
state: state,
|
||||
onChanged: (key, value) => onStateChanged?.call(key, value),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChipSelection(ChipSelectionSDUIModel data) {
|
||||
return ChipSelectionSDUI(
|
||||
model: data,
|
||||
state: state,
|
||||
onChanged: (key, index, value) => onStateChanged?.call(key, index),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImagePicker(ImagePickerSDUIModel data) {
|
||||
return ImagePickerSDUI(
|
||||
model: data,
|
||||
images: images,
|
||||
onImagesChanged: (key, imageList) => onImagesChanged?.call(key, imageList),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCard(
|
||||
CardLabelItemData data,
|
||||
SDUIWidgetModel? child,
|
||||
List<SDUIWidgetModel>? children,
|
||||
) {
|
||||
Widget? content;
|
||||
|
||||
if (child != null) {
|
||||
content = _buildStandardWidget(child);
|
||||
} else if (children != null && children.isNotEmpty) {
|
||||
content = Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: children
|
||||
.map(
|
||||
(c) => Padding(
|
||||
padding: EdgeInsets.only(bottom: 10.h),
|
||||
child: _buildStandardWidget(c),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
// ساختن مدل داخلی کارت (اگر ویجت شما مدل داخلی متفاوتی میگیرد)
|
||||
final cardWidgetModel = CardLabelItemSDUI(
|
||||
type: 'card_label_item',
|
||||
visible: true,
|
||||
data: data,
|
||||
child: null,
|
||||
);
|
||||
|
||||
return cardLabelItemSDUI(model: cardWidgetModel, child: content);
|
||||
}
|
||||
|
||||
Widget _buildColumn(
|
||||
List<SDUIWidgetModel> children, // لیست خام (همه فرزندان)
|
||||
double spacing,
|
||||
String mainAxisSizeStr,
|
||||
String crossAlignStr,
|
||||
) {
|
||||
// ۲. فیلتر کردن لیست دقیقاً همینجا (داخل Obx) انجام میشود
|
||||
// چون ConditionEvaluator.check مقدار state را میخواند، Obx خوشحال میشود!
|
||||
final visibleChildren = children.where((child) {
|
||||
// لاجیک ساده برای استخراج شرط (یا استفاده از getter اکستنشن)
|
||||
final condition = child.maybeWhen(
|
||||
textFormField: (_, __, c) => c,
|
||||
cardLabelItem: (_, __, ___, ____, c) => c,
|
||||
chipSelection: (_, __, c) => c,
|
||||
dropdown: (_, __, c) => c,
|
||||
imagePicker: (_, __, c) => c,
|
||||
column: (_, _, _, _, _, _, _, c) => c,
|
||||
row: (_, __, ___, ____, c) => c,
|
||||
stepper: (_, __, ___, c) => c,
|
||||
pageView: (_, __, ___, c) => c,
|
||||
sizedBox: (_, __, ___, c) => c,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
final isVisibleProp = child.maybeWhen(
|
||||
textFormField: (_, v, __) => v,
|
||||
cardLabelItem: (_, __, ___, v, ____) => v,
|
||||
chipSelection: (_, v, __) => v,
|
||||
dropdown: (_, v, __) => v,
|
||||
imagePicker: (_, v, __) => v,
|
||||
column: (_, __, ___, ____, _____, ______, v, _______) => v,
|
||||
row: (_, __, ___, v, ____) => v,
|
||||
stepper: (_, __, v, ___) => v,
|
||||
pageView: (_, __, v, ___) => v,
|
||||
sizedBox: (_, __, v, ___) => v,
|
||||
orElse: () => true,
|
||||
);
|
||||
|
||||
return isVisibleProp && ConditionEvaluator.check(condition, state);
|
||||
}).toList();
|
||||
|
||||
// ۳. اگر لیست خالی شد، هیچی نشون نده
|
||||
if (visibleChildren.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
// ۴. ساختن ستون با لیست فیلتر شده
|
||||
return Column(
|
||||
mainAxisSize: mainAxisSizeStr == 'min' ? MainAxisSize.min : MainAxisSize.max,
|
||||
crossAxisAlignment: _parseCrossAxis(crossAlignStr),
|
||||
children: [
|
||||
for (int i = 0; i < visibleChildren.length; i++) ...[
|
||||
_buildStandardWidget(visibleChildren[i]),
|
||||
|
||||
if (i < visibleChildren.length - 1 && spacing > 0) SizedBox(height: spacing.h),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRow(List<SDUIWidgetModel> children, double spacing, String mainAlignStr) {
|
||||
final visibleChildren = children.where((child) {
|
||||
// (همان لاجیک استخراج شرط که در Column بود)
|
||||
// برای جلوگیری از تکرار کد، میتوانید getter visibleCondition را به extension اضافه کنید
|
||||
return true; // اینجا فرض را بر سادگی میگذاریم، لاجیک مشابه Column است
|
||||
}).toList();
|
||||
|
||||
if (visibleChildren.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return Obx(() {
|
||||
return Row(
|
||||
mainAxisAlignment: _parseMainAxis(mainAlignStr),
|
||||
children: [
|
||||
for (int i = 0; i < visibleChildren.length; i++) ...[
|
||||
Expanded(child: _buildStandardWidget(visibleChildren[i])),
|
||||
if (i < visibleChildren.length - 1 && spacing > 0) SizedBox(width: spacing.w),
|
||||
],
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildPageView(PageViewSDUIModel data, List<SDUIWidgetModel> children) {
|
||||
PageController? controller;
|
||||
if (data.key != null && pageControllers != null) {
|
||||
controller = pageControllers![data.key];
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: 200.h, // ارتفاع باید مدیریت شود
|
||||
child: PageViewSDUI(
|
||||
model: data,
|
||||
controller: controller,
|
||||
state: state,
|
||||
children: children.map(_buildStandardWidget).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildNavigationButtons(SDUIFormWidgetController formController, String stepperKey) {
|
||||
return Obx(() {
|
||||
final isLastStep = formController.isLastStep;
|
||||
final canGoPrevious = formController.canGoPrevious;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.all(16.w),
|
||||
decoration: BoxDecoration(color: Colors.white),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: OutlinedButton(
|
||||
onPressed: canGoPrevious
|
||||
? () {
|
||||
formController.previousStep(state);
|
||||
onStateChanged?.call(stepperKey, formController.currentStep.value);
|
||||
}
|
||||
: null,
|
||||
style: OutlinedButton.styleFrom(
|
||||
side: const BorderSide(color: Colors.blue),
|
||||
minimumSize: Size(0, 40.h),
|
||||
),
|
||||
child: const Text('قبلی'),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10.w),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
if (isLastStep) {
|
||||
debugPrint('Form Submitted');
|
||||
} else {
|
||||
formController.nextStep(state);
|
||||
onStateChanged?.call(stepperKey, formController.currentStep.value);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.blue,
|
||||
minimumSize: Size(0, 40.h),
|
||||
),
|
||||
child: Text(isLastStep ? 'ثبت' : 'بعدی'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// HELPERS
|
||||
// ===========================================================================
|
||||
|
||||
CrossAxisAlignment _parseCrossAxis(String? val) {
|
||||
switch (val) {
|
||||
case 'start':
|
||||
return CrossAxisAlignment.start;
|
||||
case 'end':
|
||||
return CrossAxisAlignment.end;
|
||||
case 'stretch':
|
||||
return CrossAxisAlignment.stretch;
|
||||
default:
|
||||
return CrossAxisAlignment.center;
|
||||
}
|
||||
}
|
||||
|
||||
MainAxisAlignment _parseMainAxis(String? val) {
|
||||
switch (val) {
|
||||
case 'start':
|
||||
return MainAxisAlignment.start;
|
||||
case 'end':
|
||||
return MainAxisAlignment.end;
|
||||
case 'spaceBetween':
|
||||
return MainAxisAlignment.spaceBetween;
|
||||
case 'spaceAround':
|
||||
return MainAxisAlignment.spaceAround;
|
||||
default:
|
||||
return MainAxisAlignment.center;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:rasadyar_core/core.dart';
|
||||
|
||||
class SDUIFormWidgetController extends GetxController {
|
||||
RxInt currentStep = 0.obs;
|
||||
int totalSteps = 0;
|
||||
String? stepperKey;
|
||||
|
||||
void initializeStepper(int totalSteps, String? key) {
|
||||
this.totalSteps = totalSteps;
|
||||
this.stepperKey = key;
|
||||
currentStep.value = 0;
|
||||
}
|
||||
|
||||
void nextStep(RxMap<String, dynamic>? state) {
|
||||
if (currentStep.value < totalSteps - 1) {
|
||||
currentStep.value++;
|
||||
if (state != null && stepperKey != null) {
|
||||
state[stepperKey!] = currentStep.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void previousStep(RxMap<String, dynamic>? state) {
|
||||
if (currentStep.value > 0) {
|
||||
currentStep.value--;
|
||||
if (state != null && stepperKey != null) {
|
||||
state[stepperKey!] = currentStep.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool get canGoNext => currentStep.value < totalSteps - 1;
|
||||
bool get canGoPrevious => currentStep.value > 0;
|
||||
bool get isLastStep => currentStep.value == totalSteps - 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
1055
packages/chicken/lib/presentation/widget/sdui/form/ts1 copy.json
Normal file
1055
packages/chicken/lib/presentation/widget/sdui/form/ts1 copy.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.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/card_label_item/model/card_label_item_sdui_model.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/model/dropdown_sdui_model.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/stepper/model/stepper_sdui_model.dart';
|
||||
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/page_view/model/page_view_sdui_model.dart';
|
||||
|
||||
part 'sdui_widget.freezed.dart';
|
||||
part 'sdui_widget.g.dart';
|
||||
|
||||
// استفاده از snake_case برای تبدیل خودکار نامها (مثلاً text_form_field به textFormField)
|
||||
@Freezed(unionKey: 'type', unionValueCase: FreezedUnionCase.snake)
|
||||
sealed class SDUIWidgetModel with _$SDUIWidgetModel {
|
||||
// ۱. فیلد متنی
|
||||
const factory SDUIWidgetModel.textFormField({
|
||||
required TextFormFieldSDUIModel data,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _TextFormField;
|
||||
|
||||
// ۲. کارت لیبلدار
|
||||
const factory SDUIWidgetModel.cardLabelItem({
|
||||
required CardLabelItemData data,
|
||||
SDUIWidgetModel? child,
|
||||
List<SDUIWidgetModel>? children,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _CardLabelItem;
|
||||
|
||||
// ۳. انتخاب گزینهای
|
||||
const factory SDUIWidgetModel.chipSelection({
|
||||
required ChipSelectionSDUIModel data,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _ChipSelection;
|
||||
|
||||
// ۴. لیست کشویی
|
||||
const factory SDUIWidgetModel.dropdown({
|
||||
required DropdownSDUIModel data,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _Dropdown;
|
||||
|
||||
// ۵. انتخاب عکس
|
||||
const factory SDUIWidgetModel.imagePicker({
|
||||
required ImagePickerSDUIModel data,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _ImagePicker;
|
||||
|
||||
// ۶. ستون (Container ویجت - فاقد شیء data در JSON جدید)
|
||||
const factory SDUIWidgetModel.column({
|
||||
required List<SDUIWidgetModel> children,
|
||||
@Default(0.0) double spacing,
|
||||
@Default('max') String mainAxisSize,
|
||||
@Default(0.0) double paddingHorizontal,
|
||||
@Default(0.0) double paddingVertical,
|
||||
@Default('center') String crossAxisAlignment,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _Column;
|
||||
|
||||
// ۷. ردیف (Container ویجت - فاقد شیء data در JSON جدید)
|
||||
const factory SDUIWidgetModel.row({
|
||||
required List<SDUIWidgetModel> children,
|
||||
@Default(0.0) double spacing,
|
||||
@Default('start') String mainAxisAlignment,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _Row;
|
||||
|
||||
// ۸. استپر
|
||||
const factory SDUIWidgetModel.stepper({
|
||||
required StepperSDUIModel data,
|
||||
List<SDUIWidgetModel>? children,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _Stepper;
|
||||
|
||||
// ۹. پیج ویو
|
||||
const factory SDUIWidgetModel.pageView({
|
||||
required PageViewSDUIModel data,
|
||||
required List<SDUIWidgetModel> children,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _PageView;
|
||||
|
||||
// ۱۰. جعبه با اندازه ثابت
|
||||
const factory SDUIWidgetModel.sizedBox({
|
||||
double? width,
|
||||
double? height,
|
||||
@Default(true) bool visible,
|
||||
String? visibleCondition,
|
||||
}) = _SizedBox;
|
||||
|
||||
|
||||
factory SDUIWidgetModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$SDUIWidgetModelFromJson(json);
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,194 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'sdui_widget.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_TextFormField _$TextFormFieldFromJson(Map<String, dynamic> json) =>
|
||||
_TextFormField(
|
||||
data: TextFormFieldSDUIModel.fromJson(
|
||||
json['data'] as Map<String, dynamic>,
|
||||
),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TextFormFieldToJson(_TextFormField instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_CardLabelItem _$CardLabelItemFromJson(Map<String, dynamic> json) =>
|
||||
_CardLabelItem(
|
||||
data: CardLabelItemData.fromJson(json['data'] as Map<String, dynamic>),
|
||||
child: json['child'] == null
|
||||
? null
|
||||
: SDUIWidgetModel.fromJson(json['child'] as Map<String, dynamic>),
|
||||
children: (json['children'] as List<dynamic>?)
|
||||
?.map((e) => SDUIWidgetModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$CardLabelItemToJson(_CardLabelItem instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data,
|
||||
'child': instance.child,
|
||||
'children': instance.children,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_ChipSelection _$ChipSelectionFromJson(Map<String, dynamic> json) =>
|
||||
_ChipSelection(
|
||||
data: ChipSelectionSDUIModel.fromJson(
|
||||
json['data'] as Map<String, dynamic>,
|
||||
),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ChipSelectionToJson(_ChipSelection instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_Dropdown _$DropdownFromJson(Map<String, dynamic> json) => _Dropdown(
|
||||
data: DropdownSDUIModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$DropdownToJson(_Dropdown instance) => <String, dynamic>{
|
||||
'data': instance.data,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_ImagePicker _$ImagePickerFromJson(Map<String, dynamic> json) => _ImagePicker(
|
||||
data: ImagePickerSDUIModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ImagePickerToJson(_ImagePicker instance) =>
|
||||
<String, dynamic>{
|
||||
'data': instance.data,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_Column _$ColumnFromJson(Map<String, dynamic> json) => _Column(
|
||||
children: (json['children'] as List<dynamic>)
|
||||
.map((e) => SDUIWidgetModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
spacing: (json['spacing'] as num?)?.toDouble() ?? 0.0,
|
||||
mainAxisSize: json['main_axis_size'] as String? ?? 'max',
|
||||
paddingHorizontal: (json['padding_horizontal'] as num?)?.toDouble() ?? 0.0,
|
||||
paddingVertical: (json['padding_vertical'] as num?)?.toDouble() ?? 0.0,
|
||||
crossAxisAlignment: json['cross_axis_alignment'] as String? ?? 'center',
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ColumnToJson(_Column instance) => <String, dynamic>{
|
||||
'children': instance.children,
|
||||
'spacing': instance.spacing,
|
||||
'main_axis_size': instance.mainAxisSize,
|
||||
'padding_horizontal': instance.paddingHorizontal,
|
||||
'padding_vertical': instance.paddingVertical,
|
||||
'cross_axis_alignment': instance.crossAxisAlignment,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_Row _$RowFromJson(Map<String, dynamic> json) => _Row(
|
||||
children: (json['children'] as List<dynamic>)
|
||||
.map((e) => SDUIWidgetModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
spacing: (json['spacing'] as num?)?.toDouble() ?? 0.0,
|
||||
mainAxisAlignment: json['main_axis_alignment'] as String? ?? 'start',
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$RowToJson(_Row instance) => <String, dynamic>{
|
||||
'children': instance.children,
|
||||
'spacing': instance.spacing,
|
||||
'main_axis_alignment': instance.mainAxisAlignment,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_Stepper _$StepperFromJson(Map<String, dynamic> json) => _Stepper(
|
||||
data: StepperSDUIModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||
children: (json['children'] as List<dynamic>?)
|
||||
?.map((e) => SDUIWidgetModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$StepperToJson(_Stepper instance) => <String, dynamic>{
|
||||
'data': instance.data,
|
||||
'children': instance.children,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_PageView _$PageViewFromJson(Map<String, dynamic> json) => _PageView(
|
||||
data: PageViewSDUIModel.fromJson(json['data'] as Map<String, dynamic>),
|
||||
children: (json['children'] as List<dynamic>)
|
||||
.map((e) => SDUIWidgetModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PageViewToJson(_PageView instance) => <String, dynamic>{
|
||||
'data': instance.data,
|
||||
'children': instance.children,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
|
||||
_SizedBox _$SizedBoxFromJson(Map<String, dynamic> json) => _SizedBox(
|
||||
width: (json['width'] as num?)?.toDouble(),
|
||||
height: (json['height'] as num?)?.toDouble(),
|
||||
visible: json['visible'] as bool? ?? true,
|
||||
visibleCondition: json['visible_condition'] as String?,
|
||||
$type: json['type'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SizedBoxToJson(_SizedBox instance) => <String, dynamic>{
|
||||
'width': instance.width,
|
||||
'height': instance.height,
|
||||
'visible': instance.visible,
|
||||
'visible_condition': instance.visibleCondition,
|
||||
'type': instance.$type,
|
||||
};
|
||||
7
packages/chicken/lib/presentation/widget/sdui/sdui.dart
Normal file
7
packages/chicken/lib/presentation/widget/sdui/sdui.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
// SDUI Export file
|
||||
export 'form/sdui_form_widget.dart';
|
||||
export 'model/sdui_widget.dart'; // Sealed class برای type-safe widget handling
|
||||
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';
|
||||
1108
packages/chicken/lib/presentation/widget/sdui/sdui.json
Normal file
1108
packages/chicken/lib/presentation/widget/sdui/sdui.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -0,0 +1,109 @@
|
||||
import 'package:flutter/material.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) ...[
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
model.label!,
|
||||
style: AppFonts.yekan14Bold.copyWith(
|
||||
color: AppColor.textColor2,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 9.h),
|
||||
],
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
spacing: spacing,
|
||||
children: options.asMap().entries.map((entry) {
|
||||
final option = entry.value;
|
||||
final optionIndex = option.index ?? entry.key;
|
||||
return containerChips(
|
||||
selectedIndex: selectedIndex,
|
||||
index: optionIndex,
|
||||
label: option.label ?? '',
|
||||
onTap: (index) {
|
||||
if (onChanged != null && model.key != null) {
|
||||
onChanged!(model.key!, index, option.value);
|
||||
}
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
GestureDetector containerChips({
|
||||
required int selectedIndex,
|
||||
required int index,
|
||||
required String label,
|
||||
required Function(int) onTap,
|
||||
}) {
|
||||
return GestureDetector(
|
||||
onTap: () => onTap(index),
|
||||
child: Container(
|
||||
height: 24.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
color: index == selectedIndex
|
||||
? AppColor.green1Normal
|
||||
: AppColor.whiteGreyNormal,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: index == selectedIndex
|
||||
? Border.fromBorderSide(BorderSide.none)
|
||||
: Border.all(width: 1, color: AppColor.blackLightHover),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
spacing: 5,
|
||||
children: [
|
||||
if (index == selectedIndex)
|
||||
Icon(Icons.check, color: Colors.white, size: 16),
|
||||
Text(
|
||||
label,
|
||||
style: index == selectedIndex
|
||||
? AppFonts.yekan14Bold.copyWith(color: Colors.white)
|
||||
: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user