Compare commits

...

10 Commits

Author SHA1 Message Date
f842940bef some changes 2026-01-18 14:23:55 +03:30
f25b8514cd refactor: update text form field model to use dynamic value type, enhance condition evaluator for step index extraction, and improve SDK path formatting 2026-01-07 15:57:01 +03:30
17f8a2d79b refactor: update getSDUIForm method to require token parameter, enhance error handling in SDUIFormWidget, and clean up code formatting across various files 2026-01-06 15:59:42 +03:30
0f0fa8da09 chore: update Android SDK version to 1.3.42+38, enhance SDUIFormWidget with improved button layout and padding, and remove unused JSON configuration file 2026-01-05 09:24:43 +03:30
6a65aa2883 chore: update version number to 1.3.42+38 in pubspec.yaml 2026-01-04 12:03:11 +03:30
a6cf440840 feat: introduce _SpacingWidget for conditional spacing in SDUIFormWidget, enhance visibility handling with reactive updates, and improve error handling for child widgets 2026-01-04 11:57:32 +03:30
4dcc574e19 refactor: update SDUIFormWidget error handling, enhance StepperSDUI with state management and scrolling behavior, and clean up SDUIWidgetModel documentation 2026-01-04 10:03:28 +03:30
26f94345f6 feat: enhance SDUI widget model with dynamic visibility conditions, refactor NewPageLogic for improved form handling, and update UI components to support new visibility features 2025-12-31 15:28:17 +03:30
fb0b817cf9 feat: refactor SDUI widget model to use sealed classes for type-safe handling, enhance form widget with stepper support, and improve error handling in SDUIFormWidget 2025-12-31 13:36:13 +03:30
8c25e2c65c chore: remove unused dependencies from pubspec.lock files and update Flutter SDK version constraints 2025-12-30 09:54:30 +03:30
46 changed files with 4696 additions and 1253 deletions

View File

@@ -2,6 +2,7 @@ allprojects {
repositories {
google()
mavenCentral()
maven { url = uri("https://archive.ito.gov.ir/gradle/maven_central/") }
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
sdk.dir=C:\\Users\\Housh11\\AppData\\Local\\Android\\sdk
flutter.sdk=C:\\src\\flutter
flutter.buildMode=debug
flutter.versionName=1.3.41
flutter.versionCode=37
flutter.versionName=1.3.42
flutter.versionCode=38

View File

@@ -10,9 +10,10 @@ pluginManagement {
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
mavenCentral()
gradlePluginPortal()
google()
mavenCentral()
gradlePluginPortal()
maven { url = uri("https://archive.ito.gov.ir/gradle/maven_central/") }
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:rasadyar_app/data/model/app_info_model.dart';
@@ -35,9 +36,15 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
duration: const Duration(milliseconds: 8000),
);
scaleAnimation.value = Tween<double>(begin: 0.8, end: 1.2).animate(scaleController);
scaleAnimation.value = Tween<double>(
begin: 0.8,
end: 1.2,
).animate(scaleController);
rotationAnimation.value = Tween<double>(begin: 0.0, end: 1).animate(rotateController);
rotationAnimation.value = Tween<double>(
begin: 0.0,
end: 1,
).animate(rotateController);
rotateController.forward();
rotateController.addStatusListener((status) {
@@ -152,8 +159,10 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
Future.delayed(const Duration(milliseconds: 250), () async {
try {
final isUpdateNeeded = await checkVersion();
if (isUpdateNeeded) return;
if (!kDebugMode) {
final isUpdateNeeded = await checkVersion();
if (isUpdateNeeded) return;
}
final module = gService.getSelectedModule();
final target = gService.getTargetPage(module);
@@ -164,8 +173,6 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
if (target != null) {
var mFuns = getFunctionsList(target.functions);
await Future.wait(mFuns ?? []);
iLog("target.route ===>${target.route!}");
Get.offAndToNamed(target.route!);
}
} catch (e, st) {
@@ -185,7 +192,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
try {
final info = await PackageInfo.fromPlatform();
int version = info.version.versionNumber;
var res = await _dio.get("https://rsibackend.rasadyar.com/app/rasadyar-app-info/");
var res = await _dio.get(
"https://rsibackend.rasadyar.com/app/rasadyar-app-info/",
);
appInfoModel = AppInfoModel.fromJson(res.data);
@@ -244,7 +253,9 @@ class SplashLogic extends GetxController with GetTickerProviderStateMixin {
Future<void> installApk() async {
try {
eLog(_updateFilePath.value);
await platform.invokeMethod('apk_installer', {'appPath': _updateFilePath.value});
await platform.invokeMethod('apk_installer', {
'appPath': _updateFilePath.value,
});
} catch (e) {
eLog(e);
}

View File

@@ -1 +0,0 @@
{"format-version":[1,0,0],"native-assets":{}}

View File

@@ -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"]}

View File

@@ -1 +0,0 @@
[{"family":"packages/cupertino_icons/CupertinoIcons","fonts":[{"asset":"packages/cupertino_icons/assets/CupertinoIcons.ttf"}]}]

View File

@@ -1 +0,0 @@
{"format-version":[1,0,0],"native-assets":{}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -27,7 +27,7 @@ class NewInspectionLogic extends GetxController {
RxnString searchedValue = RxnString();
Rx<Jalali> fromDateFilter = Jalali.now().obs;
Rx<Jalali> toDateFilter = Jalali.now().obs;
@override
void onInit() {
super.onInit();

View File

@@ -619,6 +619,7 @@ GestureDetector containerChips({
onTap: () => onTap(index),
child: Container(
height: 24.h,
padding: EdgeInsets.symmetric(horizontal: 12.w),
decoration: BoxDecoration(
color: index == selectedIndex
? AppColor.green1Normal

View File

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

View File

@@ -1,5 +1,5 @@
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/request/submit_inspection/submit_inspection_response.dart';
import 'package:rasadyar_chicken/features/poultry_science/data/model/response/poultry_science_report/poultry_science_report.dart';
import 'package:rasadyar_chicken/features/vet_farm/data/datasources/remote/vet_farm_remote_data_source.dart';
import 'package:rasadyar_core/core.dart';
@@ -38,18 +38,14 @@ class VetFarmRemoteDataSourceImpl implements VetFarmRemoteDataSource {
}
@override
Future<DioResponse<Map<String, dynamic>>> getSDUIForm({String? token}) async {
DioRemote dio = DioRemote(baseUrl: "http://testbackend.rasadyaar.ir/");
await dio.init();
var res = await dio.get(
'inspection_form_sd_ui/',
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;
},
);
return res;
}
}

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/vet_farm/presentation/pages/root/logic.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget_model.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/model/sdui_widget.dart';
import 'package:rasadyar_core/core.dart';
class NewPageLogic extends GetxController {
@@ -14,19 +15,11 @@ class NewPageLogic extends GetxController {
@override
void onInit() {
super.onInit();
getSDUIForm();
}
@override
void onReady() {
super.onReady();
// Ready logic here
}
@override
void onClose() {
// Dispose all controllers
for (var controller in controllers.values) {
controller.dispose();
}
@@ -36,23 +29,19 @@ class NewPageLogic extends GetxController {
Future<void> getSDUIForm() async {
await safeCall(
call: () async => await rootLogic.vetFarmRepository.getSDUIForm(),
call: () async => await rootLogic.vetFarmRepository.getSDUIForm(
token: rootLogic.tokenService.accessToken.value ?? '',
),
onSuccess: (result) {
if (result.data != null) {
try {
iLog('SDUI JSON received: ${result.data}');
// Extract SDUI data from info structure
// JSON structure: { "info": { "type": "column", "visible": true, "data": {...}, "children": [...] } }
Map<String, dynamic>? sduiData;
if (result.data!['info'] != null && result.data!['info'] is Map) {
final infoMap = result.data!['info'] as Map<String, dynamic>;
// Check if info has type field (meaning it's the SDUI structure itself)
if (infoMap.containsKey('type')) {
sduiData = infoMap;
iLog(
'SDUI data extracted from info (info contains type field)',
);
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>;
@@ -69,8 +58,60 @@ class NewPageLogic extends GetxController {
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: ${sduiModel.value?.type}, Visible: ${sduiModel.value?.visible}, Children count: ${sduiModel.value?.children?.length ?? 0}',
'SDUI Model parsed successfully. Type: $modelType, Visible: ${sduiModel.value?.visible}, Children count: $childrenCount',
);
_initializeControllers(sduiModel.value!);
} else {
@@ -98,23 +139,64 @@ class NewPageLogic extends GetxController {
}
void _extractTextFields(SDUIWidgetModel model) {
if (model.type == 'text_form_field' && model.data != null) {
final key = model.data!['key'] as String?;
final value = model.data!['value'] as String?;
if (key != null && !controllers.containsKey(key)) {
controllers[key] = TextEditingController(text: value ?? '');
}
}
// 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: () {},
);
if (model.child != null) {
_extractTextFields(SDUIWidgetModel.fromJson(model.child!));
}
if (model.children != null) {
for (var child in model.children!) {
_extractTextFields(SDUIWidgetModel.fromJson(child));
}
}
// 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() {

View File

@@ -29,15 +29,16 @@ class NewPage extends GetView<NewPageLogic> {
SizedBox(height: 24.h),
RElevated(
text: 'دکمه نمونه',
onPressed: () {
onPressed: () async {
await controller.getSDUIForm();
Get.bottomSheet(
isScrollControlled: true,
enableDrag: true,
BaseBottomSheet(
height: Get.height * 0.8,
child: ObxValue((data) {
rootChild: ObxValue((data) {
if (data.value == null) {
return Center(child: CircularProgressIndicator());
}
@@ -61,6 +62,27 @@ class NewPage extends GetView<NewPageLogic> {
},
),
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),
],
),
),
);
},
),
],
),
);

View File

@@ -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;
}
}

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

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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,
};

View File

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

View File

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

View File

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

View File

@@ -1,8 +1,7 @@
// SDUI Export file
export 'form/sdui_form_widget.dart';
export 'model/sdui_widget_model.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';

View File

@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/features/poultry_science/presentation/widgets/submit_inspection_bottom_sheet/step2_page.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/chip_selection/model/chip_selection_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
@@ -32,20 +31,27 @@ class ChipSelectionSDUI extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
if (model.label != null && model.label!.isNotEmpty) ...[
Text(
model.label!,
style: AppFonts.yekan14Bold.copyWith(color: AppColor.textColor2),
Row(
children: [
Text(
model.label!,
style: AppFonts.yekan14Bold.copyWith(
color: AppColor.textColor2,
),
),
],
),
SizedBox(height: 9.h),
],
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: spacing,
children: options.asMap().entries.map((entry) {
final option = entry.value;
final optionIndex = option.index ?? entry.key;
return Expanded(
child: containerChips(
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 ?? '',
@@ -54,12 +60,50 @@ class ChipSelectionSDUI extends StatelessWidget {
onChanged!(model.key!, index, option.value);
}
},
),
);
}).toList(),
);
}).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),
),
],
),
),
);
}

View File

@@ -2,40 +2,91 @@ import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/stepper/model/stepper_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class StepperSDUI extends StatelessWidget {
class StepperSDUI extends StatefulWidget {
final StepperSDUIModel model;
final RxMap<String, dynamic>? state;
const StepperSDUI({super.key, required this.model, this.state});
@override
State<StepperSDUI> createState() => _StepperSDUIState();
}
class _StepperSDUIState extends State<StepperSDUI> {
late final ScrollController _scrollController;
List<GlobalKey>? itemKeys;
int? _lastActiveStep;
late int totalSteps;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
totalSteps = widget.model.totalSteps ?? 1;
itemKeys = List.generate(totalSteps, (index) => GlobalKey());
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final totalSteps = model.totalSteps ?? 5;
// Update keys if totalSteps changed
if (itemKeys == null || itemKeys!.length != totalSteps) {
itemKeys = List.generate(totalSteps, (index) => GlobalKey());
}
if ((totalSteps * 24.w + ((totalSteps - 1) * (40.w))) < Get.width) {
return Obx(() {
final activeStep =
widget.state?[widget.model.key] as int? ??
widget.model.activeStep ??
0;
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: _buildSteps(totalSteps, activeStep),
);
});
}
return Obx(() {
final activeStep = state?[model.key] as int? ?? model.activeStep ?? 0;
final activeStep =
widget.state?[widget.model.key] as int? ??
widget.model.activeStep ??
0;
return Directionality(
textDirection: TextDirection.ltr,
child: SizedBox(
height: 24,
width: Get.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildSteps(totalSteps, activeStep),
),
// Scroll to active step if it changed
if (_lastActiveStep != activeStep) {
_lastActiveStep = activeStep;
WidgetsBinding.instance.addPostFrameCallback((_) {
scrollToActive(activeStep);
});
}
return SizedBox(
height: 30.h,
child: SingleChildScrollView(
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: Row(children: _buildScrolledSteps(totalSteps, activeStep)),
),
);
});
}
List<Widget> _buildSteps(int totalSteps, int activeStep) {
List<Widget> _buildScrolledSteps(int totalSteps, int activeStep) {
final List<Widget> widgets = [];
for (int i = 0; i < totalSteps; i++) {
// Add step circle
widgets.add(
Container(
key: itemKeys?[i],
alignment: Alignment.center,
decoration: BoxDecoration(
color: activeStep >= i
@@ -58,7 +109,8 @@ class StepperSDUI extends StatelessWidget {
// Add divider between steps (except after last step)
if (i < totalSteps - 1) {
widgets.add(
Expanded(
SizedBox(
width: 40.w,
child: Divider(
color: activeStep >= i + 1
? AppColor.greenNormalHover
@@ -72,4 +124,84 @@ class StepperSDUI extends StatelessWidget {
return widgets;
}
List<Widget> _buildSteps(int totalSteps, int activeStep) {
final List<Widget> widgets = [];
double space = 0;
if (totalSteps < 2) {
space = 0;
} else if (totalSteps == 2) {
space = Get.width - (2 * (24.w)) - (51.w);
} else {
space = ((Get.width - (51.w)) - (totalSteps * (24.w))) / (totalSteps - 1);
}
for (int i = 0; i < totalSteps; i++) {
// Add step circle
widgets.add(
Container(
key: itemKeys?[i],
alignment: Alignment.center,
decoration: BoxDecoration(
color: activeStep >= i
? AppColor.greenNormalHover
: AppColor.whiteNormalActive,
shape: BoxShape.circle,
),
width: 24.w,
height: 24.h,
child: Text(
'${i + 1}',
textAlign: TextAlign.center,
style: AppFonts.yekan16.copyWith(
color: activeStep >= i ? Colors.white : AppColor.iconColor,
),
),
),
);
// Add divider between steps (except after last step)
if (i < totalSteps - 1) {
widgets.add(
SizedBox(
width: space,
child: Divider(
color: activeStep >= i + 1
? AppColor.greenNormalHover
: AppColor.whiteNormalActive,
thickness: 8,
),
),
);
}
}
return widgets;
}
void scrollToActive(int index) {
if (itemKeys == null || index < 0 || index >= itemKeys!.length) return;
final context = itemKeys![index].currentContext;
if (context != null) {
Scrollable.ensureVisible(
context,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
alignment: 0.5, // دکمه بیاد وسط صفحه
);
} else if (_scrollController.hasClients) {
// Fallback: calculate position manually
final double itemWidth = 24.w + 40.w; // step width + divider width
final double targetOffset =
(index * itemWidth) - (Get.width / 2) + (24.w / 2);
final double maxScroll = _scrollController.position.maxScrollExtent;
_scrollController.animateTo(
targetOffset.clamp(0.0, maxScroll),
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
}
}

View File

@@ -11,14 +11,14 @@ abstract class TextFormFieldSDUIModel with _$TextFormFieldSDUIModel {
String? hintText,
String? variant,
String? keyboardType,
String? value,
dynamic value,
int? maxLength,
int? minLine,
int? maxLine,
bool? required,
bool? enabled,
bool? readonly,
bool? commaSperator,
bool? commaSeparator,
bool? decimal,
int? decimalPlaces,
String? type,

View File

@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$TextFormFieldSDUIModel {
String? get key; String? get label; String? get hintText; String? get variant; String? get keyboardType; String? get value; int? get maxLength; int? get minLine; int? get maxLine; bool? get required; bool? get enabled; bool? get readonly; bool? get commaSperator; bool? get decimal; int? get decimalPlaces; String? get type;
String? get key; String? get label; String? get hintText; String? get variant; String? get keyboardType; dynamic get value; int? get maxLength; int? get minLine; int? get maxLine; bool? get required; bool? get enabled; bool? get readonly; bool? get commaSeparator; bool? get decimal; int? get decimalPlaces; String? get type;
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -28,16 +28,16 @@ $TextFormFieldSDUIModelCopyWith<TextFormFieldSDUIModel> get copyWith => _$TextFo
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&(identical(other.value, value) || other.value == value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSperator, commaSperator) || other.commaSperator == commaSperator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
return identical(this, other) || (other.runtimeType == runtimeType&&other is TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&const DeepCollectionEquality().equals(other.value, value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSeparator, commaSeparator) || other.commaSeparator == commaSeparator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,value,maxLength,minLine,maxLine,required,enabled,readonly,commaSperator,decimal,decimalPlaces,type);
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,const DeepCollectionEquality().hash(value),maxLength,minLine,maxLine,required,enabled,readonly,commaSeparator,decimal,decimalPlaces,type);
@override
String toString() {
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSperator: $commaSperator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSeparator: $commaSeparator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
}
@@ -48,7 +48,7 @@ abstract mixin class $TextFormFieldSDUIModelCopyWith<$Res> {
factory $TextFormFieldSDUIModelCopyWith(TextFormFieldSDUIModel value, $Res Function(TextFormFieldSDUIModel) _then) = _$TextFormFieldSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type
String? key, String? label, String? hintText, String? variant, String? keyboardType, dynamic value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSeparator, bool? decimal, int? decimalPlaces, String? type
});
@@ -65,7 +65,7 @@ class _$TextFormFieldSDUIModelCopyWithImpl<$Res>
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSperator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSeparator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
@@ -73,13 +73,13 @@ as String?,hintText: freezed == hintText ? _self.hintText : hintText // ignore:
as String?,variant: freezed == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable
as String?,keyboardType: freezed == keyboardType ? _self.keyboardType : keyboardType // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as dynamic,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as int?,minLine: freezed == minLine ? _self.minLine : minLine // ignore: cast_nullable_to_non_nullable
as int?,maxLine: freezed == maxLine ? _self.maxLine : maxLine // ignore: cast_nullable_to_non_nullable
as int?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,readonly: freezed == readonly ? _self.readonly : readonly // ignore: cast_nullable_to_non_nullable
as bool?,commaSperator: freezed == commaSperator ? _self.commaSperator : commaSperator // ignore: cast_nullable_to_non_nullable
as bool?,commaSeparator: freezed == commaSeparator ? _self.commaSeparator : commaSeparator // ignore: cast_nullable_to_non_nullable
as bool?,decimal: freezed == decimal ? _self.decimal : decimal // ignore: cast_nullable_to_non_nullable
as bool?,decimalPlaces: freezed == decimalPlaces ? _self.decimalPlaces : decimalPlaces // ignore: cast_nullable_to_non_nullable
as int?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable
@@ -168,10 +168,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, dynamic value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSeparator, bool? decimal, int? decimalPlaces, String? type)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSeparator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return orElse();
}
@@ -189,10 +189,10 @@ return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboar
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, dynamic value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSeparator, bool? decimal, int? decimalPlaces, String? type) $default,) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel():
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSeparator,_that.decimal,_that.decimalPlaces,_that.type);case _:
throw StateError('Unexpected subclass');
}
@@ -209,10 +209,10 @@ return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboar
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, String? hintText, String? variant, String? keyboardType, dynamic value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSeparator, bool? decimal, int? decimalPlaces, String? type)? $default,) {final _that = this;
switch (_that) {
case _TextFormFieldSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSperator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboardType,_that.value,_that.maxLength,_that.minLine,_that.maxLine,_that.required,_that.enabled,_that.readonly,_that.commaSeparator,_that.decimal,_that.decimalPlaces,_that.type);case _:
return null;
}
@@ -224,7 +224,7 @@ return $default(_that.key,_that.label,_that.hintText,_that.variant,_that.keyboar
@JsonSerializable()
class _TextFormFieldSDUIModel implements TextFormFieldSDUIModel {
const _TextFormFieldSDUIModel({this.key, this.label, this.hintText, this.variant, this.keyboardType, this.value, this.maxLength, this.minLine, this.maxLine, this.required, this.enabled, this.readonly, this.commaSperator, this.decimal, this.decimalPlaces, this.type});
const _TextFormFieldSDUIModel({this.key, this.label, this.hintText, this.variant, this.keyboardType, this.value, this.maxLength, this.minLine, this.maxLine, this.required, this.enabled, this.readonly, this.commaSeparator, this.decimal, this.decimalPlaces, this.type});
factory _TextFormFieldSDUIModel.fromJson(Map<String, dynamic> json) => _$TextFormFieldSDUIModelFromJson(json);
@override final String? key;
@@ -232,14 +232,14 @@ class _TextFormFieldSDUIModel implements TextFormFieldSDUIModel {
@override final String? hintText;
@override final String? variant;
@override final String? keyboardType;
@override final String? value;
@override final dynamic value;
@override final int? maxLength;
@override final int? minLine;
@override final int? maxLine;
@override final bool? required;
@override final bool? enabled;
@override final bool? readonly;
@override final bool? commaSperator;
@override final bool? commaSeparator;
@override final bool? decimal;
@override final int? decimalPlaces;
@override final String? type;
@@ -257,16 +257,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&(identical(other.value, value) || other.value == value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSperator, commaSperator) || other.commaSperator == commaSperator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _TextFormFieldSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.hintText, hintText) || other.hintText == hintText)&&(identical(other.variant, variant) || other.variant == variant)&&(identical(other.keyboardType, keyboardType) || other.keyboardType == keyboardType)&&const DeepCollectionEquality().equals(other.value, value)&&(identical(other.maxLength, maxLength) || other.maxLength == maxLength)&&(identical(other.minLine, minLine) || other.minLine == minLine)&&(identical(other.maxLine, maxLine) || other.maxLine == maxLine)&&(identical(other.required, required) || other.required == required)&&(identical(other.enabled, enabled) || other.enabled == enabled)&&(identical(other.readonly, readonly) || other.readonly == readonly)&&(identical(other.commaSeparator, commaSeparator) || other.commaSeparator == commaSeparator)&&(identical(other.decimal, decimal) || other.decimal == decimal)&&(identical(other.decimalPlaces, decimalPlaces) || other.decimalPlaces == decimalPlaces)&&(identical(other.type, type) || other.type == type));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,value,maxLength,minLine,maxLine,required,enabled,readonly,commaSperator,decimal,decimalPlaces,type);
int get hashCode => Object.hash(runtimeType,key,label,hintText,variant,keyboardType,const DeepCollectionEquality().hash(value),maxLength,minLine,maxLine,required,enabled,readonly,commaSeparator,decimal,decimalPlaces,type);
@override
String toString() {
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSperator: $commaSperator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
return 'TextFormFieldSDUIModel(key: $key, label: $label, hintText: $hintText, variant: $variant, keyboardType: $keyboardType, value: $value, maxLength: $maxLength, minLine: $minLine, maxLine: $maxLine, required: $required, enabled: $enabled, readonly: $readonly, commaSeparator: $commaSeparator, decimal: $decimal, decimalPlaces: $decimalPlaces, type: $type)';
}
@@ -277,7 +277,7 @@ abstract mixin class _$TextFormFieldSDUIModelCopyWith<$Res> implements $TextForm
factory _$TextFormFieldSDUIModelCopyWith(_TextFormFieldSDUIModel value, $Res Function(_TextFormFieldSDUIModel) _then) = __$TextFormFieldSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, String? hintText, String? variant, String? keyboardType, String? value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSperator, bool? decimal, int? decimalPlaces, String? type
String? key, String? label, String? hintText, String? variant, String? keyboardType, dynamic value, int? maxLength, int? minLine, int? maxLine, bool? required, bool? enabled, bool? readonly, bool? commaSeparator, bool? decimal, int? decimalPlaces, String? type
});
@@ -294,7 +294,7 @@ class __$TextFormFieldSDUIModelCopyWithImpl<$Res>
/// Create a copy of TextFormFieldSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSperator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? key = freezed,Object? label = freezed,Object? hintText = freezed,Object? variant = freezed,Object? keyboardType = freezed,Object? value = freezed,Object? maxLength = freezed,Object? minLine = freezed,Object? maxLine = freezed,Object? required = freezed,Object? enabled = freezed,Object? readonly = freezed,Object? commaSeparator = freezed,Object? decimal = freezed,Object? decimalPlaces = freezed,Object? type = freezed,}) {
return _then(_TextFormFieldSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
@@ -302,13 +302,13 @@ as String?,hintText: freezed == hintText ? _self.hintText : hintText // ignore:
as String?,variant: freezed == variant ? _self.variant : variant // ignore: cast_nullable_to_non_nullable
as String?,keyboardType: freezed == keyboardType ? _self.keyboardType : keyboardType // ignore: cast_nullable_to_non_nullable
as String?,value: freezed == value ? _self.value : value // ignore: cast_nullable_to_non_nullable
as String?,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as dynamic,maxLength: freezed == maxLength ? _self.maxLength : maxLength // ignore: cast_nullable_to_non_nullable
as int?,minLine: freezed == minLine ? _self.minLine : minLine // ignore: cast_nullable_to_non_nullable
as int?,maxLine: freezed == maxLine ? _self.maxLine : maxLine // ignore: cast_nullable_to_non_nullable
as int?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,enabled: freezed == enabled ? _self.enabled : enabled // ignore: cast_nullable_to_non_nullable
as bool?,readonly: freezed == readonly ? _self.readonly : readonly // ignore: cast_nullable_to_non_nullable
as bool?,commaSperator: freezed == commaSperator ? _self.commaSperator : commaSperator // ignore: cast_nullable_to_non_nullable
as bool?,commaSeparator: freezed == commaSeparator ? _self.commaSeparator : commaSeparator // ignore: cast_nullable_to_non_nullable
as bool?,decimal: freezed == decimal ? _self.decimal : decimal // ignore: cast_nullable_to_non_nullable
as bool?,decimalPlaces: freezed == decimalPlaces ? _self.decimalPlaces : decimalPlaces // ignore: cast_nullable_to_non_nullable
as int?,type: freezed == type ? _self.type : type // ignore: cast_nullable_to_non_nullable

View File

@@ -14,14 +14,14 @@ _TextFormFieldSDUIModel _$TextFormFieldSDUIModelFromJson(
hintText: json['hint_text'] as String?,
variant: json['variant'] as String?,
keyboardType: json['keyboard_type'] as String?,
value: json['value'] as String?,
value: json['value'],
maxLength: (json['max_length'] as num?)?.toInt(),
minLine: (json['min_line'] as num?)?.toInt(),
maxLine: (json['max_line'] as num?)?.toInt(),
required: json['required'] as bool?,
enabled: json['enabled'] as bool?,
readonly: json['readonly'] as bool?,
commaSperator: json['comma_sperator'] as bool?,
commaSeparator: json['comma_separator'] as bool?,
decimal: json['decimal'] as bool?,
decimalPlaces: (json['decimal_places'] as num?)?.toInt(),
type: json['type'] as String?,
@@ -42,7 +42,7 @@ Map<String, dynamic> _$TextFormFieldSDUIModelToJson(
'required': instance.required,
'enabled': instance.enabled,
'readonly': instance.readonly,
'comma_sperator': instance.commaSperator,
'comma_separator': instance.commaSeparator,
'decimal': instance.decimal,
'decimal_places': instance.decimalPlaces,
'type': instance.type,

View File

@@ -7,24 +7,23 @@ import 'model/text_form_field_sdui_model.dart';
Widget textFormFiledSDUI({
required TextFormFieldSDUIModel model,
TextEditingController? controller,
ValueChanged<String>? onChanged,
}) {
List<TextInputFormatter>? inputFormatters = [];
TextInputType? keyboardType;
VoidCallback? onTap;
bool isReadonly = model.readonly ?? false;
String? initValue;
final textController = controller ?? TextEditingController(text: model.value);
if (model.type == 'date_picker') {
// برای date picker، readonly می‌کنیم و onTap اضافه می‌کنیم
isReadonly = true;
onTap = () {
// پارس کردن تاریخ فعلی اگر وجود دارد
Jalali? initialDate;
if (textController.text.isNotEmpty) {
try {
// فرض می‌کنیم تاریخ به فرمت '1404/01/01' یا '1404-01-01' است
final dateStr = textController.text.replaceAll('-', '/');
final parts = dateStr.split('/');
if (parts.length == 3) {
@@ -40,16 +39,15 @@ Widget textFormFiledSDUI({
}
}
// اگر نتوانستیم parse کنیم، از تاریخ امروز استفاده می‌کنیم
initialDate ??= Jalali.now();
// نمایش date picker
Get.bottomSheet(
modalDatePicker(
initialDate: initialDate,
onDateSelected: (selectedDate) {
// فرمت کردن تاریخ و قرار دادن در controller
textController.text = selectedDate.formatCompactDate();
final formattedDate = selectedDate.formatCompactDate();
textController.text = formattedDate;
onChanged?.call(formattedDate);
},
),
isScrollControlled: true,
@@ -67,16 +65,29 @@ Widget textFormFiledSDUI({
}
}
if ((model.commaSperator ?? false) &&
(model.decimal == null || model.decimal == false)) {
if ((model.commaSeparator ?? false) && (model.decimal == null || model.decimal == false)) {
inputFormatters.add(SeparatorInputFormatter());
// FIX: اگر مقدار اولیه وجود دارد، باید آن را هم فرمت کنیم تا با فرمتر هماهنگ باشد
if (model.value != null) {
try {
String tmp = model.value.replaceAll(',', '');
if (model.commaSeparator ?? false) {
textController.text = tmp.replaceAll(',', '').separatedByComma;
} else {
textController.text = int.tryParse(tmp).toString();
}
} catch (e) {
// اگر پارس نشد، همان مقدار اصلی می‌ماند
}
}
}
}
return RTextField(
controller: textController,
onChanged: (data) {
iLog(data);
onChanged?.call(data);
},
onTap: onTap,
label: model.label,

View File

@@ -49,14 +49,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.7.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024"
url: "https://pub.dev"
source: hosted
version: "1.6.5"
async:
dependency: transitive
description:
@@ -337,14 +329,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_frame_plus:
dependency: transitive
description:
name: device_frame_plus
sha256: ccc94abccd4d9f0a9f19ef239001b3a59896e678ad42601371d7065889f2bf78
url: "https://pub.dev"
source: hosted
version: "1.5.0"
device_info_plus:
dependency: transitive
description:
@@ -361,14 +345,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.3"
device_preview_plus:
dependency: transitive
description:
name: device_preview_plus
sha256: eb3e67929c9f04759e0d3708ad91d1018235549bcf8699f8a94909684c6555ae
url: "https://pub.dev"
source: hosted
version: "2.5.5"
dio:
dependency: transitive
description:
@@ -385,14 +361,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
encrypt:
dependency: transitive
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
fake_async:
dependency: transitive
description:
@@ -1309,14 +1277,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
pool:
dependency: transitive
description:
@@ -1380,22 +1340,6 @@ packages:
relative: true
source: path
version: "1.3.0"
rive:
dependency: transitive
description:
name: rive
sha256: "2551a44fa766a7ed3f52aa2b94feda6d18d00edc25dee5f66e72e9b365bb6d6c"
url: "https://pub.dev"
source: hosted
version: "0.13.20"
rive_common:
dependency: transitive
description:
name: rive_common
sha256: "2ba42f80d37a4efd0696fb715787c4785f8a13361e8aea9227c50f1e78cf763a"
url: "https://pub.dev"
source: hosted
version: "0.4.15"
rxdart:
dependency: transitive
description:
@@ -1412,62 +1356,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
shared_preferences:
dependency: transitive
description:
name: shared_preferences
sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc"
url: "https://pub.dev"
source: hosted
version: "2.4.18"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
url: "https://pub.dev"
source: hosted
version: "2.5.6"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf:
dependency: transitive
description:
@@ -1843,4 +1731,4 @@ packages:
version: "2.1.0"
sdks:
dart: ">=3.10.0 <4.0.0"
flutter: ">=3.35.7"
flutter: ">=3.35.0"

View File

@@ -49,14 +49,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.7.0"
asn1lib:
dependency: transitive
description:
name: asn1lib
sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024"
url: "https://pub.dev"
source: hosted
version: "1.6.5"
async:
dependency: transitive
description:
@@ -337,14 +329,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_frame_plus:
dependency: transitive
description:
name: device_frame_plus
sha256: ccc94abccd4d9f0a9f19ef239001b3a59896e678ad42601371d7065889f2bf78
url: "https://pub.dev"
source: hosted
version: "1.5.0"
device_info_plus:
dependency: transitive
description:
@@ -361,14 +345,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.3"
device_preview_plus:
dependency: transitive
description:
name: device_preview_plus
sha256: d55e6197bad38b5eb304ba4e3ec3979971d8f69599b5109406022cf978dd2be2
url: "https://pub.dev"
source: hosted
version: "2.5.6"
dio:
dependency: transitive
description:
@@ -385,14 +361,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
encrypt:
dependency: transitive
description:
name: encrypt
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
url: "https://pub.dev"
source: hosted
version: "5.0.3"
fake_async:
dependency: transitive
description:
@@ -1316,14 +1284,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
url: "https://pub.dev"
source: hosted
version: "3.9.1"
pool:
dependency: transitive
description:
@@ -1416,22 +1376,6 @@ packages:
relative: true
source: path
version: "2.0.1"
rive:
dependency: transitive
description:
name: rive
sha256: "2551a44fa766a7ed3f52aa2b94feda6d18d00edc25dee5f66e72e9b365bb6d6c"
url: "https://pub.dev"
source: hosted
version: "0.13.20"
rive_common:
dependency: transitive
description:
name: rive_common
sha256: "2ba42f80d37a4efd0696fb715787c4785f8a13361e8aea9227c50f1e78cf763a"
url: "https://pub.dev"
source: hosted
version: "0.4.15"
rxdart:
dependency: transitive
description:
@@ -1448,62 +1392,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
shared_preferences:
dependency: transitive
description:
name: shared_preferences
sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64"
url: "https://pub.dev"
source: hosted
version: "2.5.4"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "83af5c682796c0f7719c2bbf74792d113e40ae97981b8f266fa84574573556bc"
url: "https://pub.dev"
source: hosted
version: "2.4.18"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f"
url: "https://pub.dev"
source: hosted
version: "2.5.6"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
url: "https://pub.dev"
source: hosted
version: "2.4.1"
shelf:
dependency: transitive
description:
@@ -1839,4 +1727,4 @@ packages:
version: "2.1.0"
sdks:
dart: ">=3.10.0 <4.0.0"
flutter: ">=3.35.7"
flutter: ">=3.35.0"

View File

@@ -1,7 +1,7 @@
name: rasadyar_app
description: "A new Flutter project."
publish_to: "none"
version: 1.3.41+37
version: 1.3.42+38
environment:
sdk: ^3.10.0