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 {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
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
|
sdk.dir=C:\\Users\\Housh11\\AppData\\Local\\Android\\sdk
|
||||||
flutter.sdk=C:\\src\\flutter
|
flutter.sdk=C:\\src\\flutter
|
||||||
flutter.buildMode=debug
|
flutter.buildMode=debug
|
||||||
flutter.versionName=1.3.41
|
flutter.versionName=1.3.42
|
||||||
flutter.versionCode=37
|
flutter.versionCode=38
|
||||||
@@ -13,6 +13,7 @@ pluginManagement {
|
|||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
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 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:rasadyar_app/data/model/app_info_model.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),
|
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.forward();
|
||||||
rotateController.addStatusListener((status) {
|
rotateController.addStatusListener((status) {
|
||||||
@@ -152,8 +159,10 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
|||||||
|
|
||||||
Future.delayed(const Duration(milliseconds: 250), () async {
|
Future.delayed(const Duration(milliseconds: 250), () async {
|
||||||
try {
|
try {
|
||||||
|
if (!kDebugMode) {
|
||||||
final isUpdateNeeded = await checkVersion();
|
final isUpdateNeeded = await checkVersion();
|
||||||
if (isUpdateNeeded) return;
|
if (isUpdateNeeded) return;
|
||||||
|
}
|
||||||
|
|
||||||
final module = gService.getSelectedModule();
|
final module = gService.getSelectedModule();
|
||||||
final target = gService.getTargetPage(module);
|
final target = gService.getTargetPage(module);
|
||||||
@@ -164,8 +173,6 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
|||||||
if (target != null) {
|
if (target != null) {
|
||||||
var mFuns = getFunctionsList(target.functions);
|
var mFuns = getFunctionsList(target.functions);
|
||||||
await Future.wait(mFuns ?? []);
|
await Future.wait(mFuns ?? []);
|
||||||
|
|
||||||
iLog("target.route ===>${target.route!}");
|
|
||||||
Get.offAndToNamed(target.route!);
|
Get.offAndToNamed(target.route!);
|
||||||
}
|
}
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
@@ -185,7 +192,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
|||||||
try {
|
try {
|
||||||
final info = await PackageInfo.fromPlatform();
|
final info = await PackageInfo.fromPlatform();
|
||||||
int version = info.version.versionNumber;
|
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);
|
appInfoModel = AppInfoModel.fromJson(res.data);
|
||||||
|
|
||||||
@@ -244,7 +253,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
|||||||
Future<void> installApk() async {
|
Future<void> installApk() async {
|
||||||
try {
|
try {
|
||||||
eLog(_updateFilePath.value);
|
eLog(_updateFilePath.value);
|
||||||
await platform.invokeMethod('apk_installer', {'appPath': _updateFilePath.value});
|
await platform.invokeMethod('apk_installer', {
|
||||||
|
'appPath': _updateFilePath.value,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
eLog(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/data/common/dio_error_handler.dart';
|
||||||
import 'package:rasadyar_chicken/features/common/presentation/routes/routes.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/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/poultry_science/data/di/poultry_science_di.dart';
|
||||||
import 'package:rasadyar_chicken/features/steward/data/di/steward_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';
|
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
|
// Setup jahad feature DI
|
||||||
await setupJahadDI(diChicken, dioRemote);
|
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 {
|
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/features/kill_house/data/model/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/features/kill_house/data/model/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/kill_request_list/kill_request_list.dart'
|
||||||
as listModel;
|
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/features/kill_house/data/model/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_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
abstract class KillHouseRemoteDataSource {
|
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/features/kill_house/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/features/kill_house/data/model/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/features/kill_house/data/model/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/kill_request_list/kill_request_list.dart'
|
||||||
as listModel;
|
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/features/kill_house/data/model/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_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
class KillHouseRemoteDataSourceImpl extends KillHouseRemoteDataSource {
|
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/features/kill_house/data/model/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/features/kill_house/data/model/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/features/kill_house/data/model/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/kill_request_list/kill_request_list.dart'
|
||||||
as listModel
|
as listModel
|
||||||
show KillRequestList;
|
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/features/kill_house/data/model/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_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
|
||||||
import 'package:rasadyar_core/data/model/pagination_model/pagination_model.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/features/kill_house/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/features/kill_house/data/model/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/features/kill_house/data/model/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/features/kill_house/data/model/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/kill_request_list/kill_request_list.dart'
|
||||||
as ListModel;
|
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/features/kill_house/data/model/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_sales_info_dashboard/kill_house_sales_info_dashboard.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
import 'kill_house_repository.dart';
|
import 'kill_house_repository.dart';
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rasadyar_chicken/data/di/chicken_di.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/features/common/presentation/page/profile/view.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/pages.dart';
|
import 'package:rasadyar_chicken/presentation/routes/pages.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
import 'package:rasadyar_chicken/presentation/routes/routes.dart';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/features/kill_house/data/model/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/features/kill_house/data/model/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/features/kill_house/data/model/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/kill_request_list/kill_request_list.dart'
|
||||||
as listModel;
|
as listModel;
|
||||||
import 'package:rasadyar_chicken/features/kill_house/root/logic.dart';
|
import 'package:rasadyar_chicken/features/kill_house/root/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.dart';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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
|
as listModel
|
||||||
show KillRequestList;
|
show KillRequestList;
|
||||||
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
|
import 'package:rasadyar_chicken/presentation/utils/nested_keys_utils.dart';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.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 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
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/features/kill_house/warehouse_and_distribution/root/logic.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
|
import 'package:rasadyar_chicken/presentation/utils/utils.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.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 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
import 'logic.dart';
|
import 'logic.dart';
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import 'dart:async';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:rasadyar_chicken/data/di/chicken_di.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/features/kill_house/data/model/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/kill_house/data/repository/kill_house_repository.dart';
|
||||||
import 'package:rasadyar_chicken/features/common/profile/view.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/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/home/view.dart';
|
||||||
import 'package:rasadyar_chicken/features/kill_house/warehouse_and_distribution/sale/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';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
Widget farmInfoWidget({
|
Widget farmInfoWidget({
|
||||||
required CreateInspectionBottomSheetLogic controller,
|
CreateInspectionBottomSheetLogic? controller,
|
||||||
required String title,
|
required String title,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
EdgeInsets? padding,
|
EdgeInsets? padding,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/card_info.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),
|
onTap: () => onTap(index),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 24.h,
|
height: 24.h,
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: index == selectedIndex
|
color: index == selectedIndex
|
||||||
? AppColor.green1Normal
|
? AppColor.green1Normal
|
||||||
|
|||||||
@@ -12,4 +12,8 @@ abstract class VetFarmRemoteDataSource {
|
|||||||
required String token,
|
required String token,
|
||||||
required SubmitInspectionResponse request,
|
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/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_chicken/features/vet_farm/data/datasources/remote/vet_farm_remote_data_source.dart';
|
||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
@@ -36,4 +36,16 @@ class VetFarmRemoteDataSourceImpl implements VetFarmRemoteDataSource {
|
|||||||
data: request.toJson(),
|
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 String token,
|
||||||
required SubmitInspectionResponse request,
|
required SubmitInspectionResponse request,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({
|
||||||
|
required String token,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,4 +27,8 @@ class VetFarmRepositoryImpl implements VetFarmRepository {
|
|||||||
}) async {
|
}) async {
|
||||||
return await _remote.submitInspection(token: token, request: request);
|
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,
|
route: VetFarmRoutes.newInspectionVetFarm,
|
||||||
icon: Assets.vec.activeFramSvg.path,
|
icon: Assets.vec.activeFramSvg.path,
|
||||||
),
|
),
|
||||||
|
VetFarmHomeItem(
|
||||||
|
title: "صفحه جدید",
|
||||||
|
route: VetFarmRoutes.newPageVetFarm,
|
||||||
|
icon: Assets.vec.activeFramSvg.path,
|
||||||
|
),
|
||||||
].obs;
|
].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/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/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_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/features/vet_farm/presentation/routes/routes.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/routes/global_binding.dart';
|
import 'package:rasadyar_chicken/presentation/routes/global_binding.dart';
|
||||||
import 'package:rasadyar_chicken/presentation/widget/base_page/logic.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 actionVetFarm = '$_base/action';
|
||||||
static const activeHatchingVetFarm = '$_base/activeHatching';
|
static const activeHatchingVetFarm = '$_base/activeHatching';
|
||||||
static const newInspectionVetFarm = '$_base/newInspection';
|
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