feat: enhance NewPage UI with dynamic bottom sheet for form input and restructure SDUI JSON schema for improved data handling
This commit is contained in:
@@ -25,30 +25,39 @@ class NewPage extends GetView<NewPageLogic> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
ObxValue((data) {
|
Row(children: []),
|
||||||
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),
|
SizedBox(height: 24.h),
|
||||||
RElevated(
|
RElevated(
|
||||||
text: 'دکمه نمونه',
|
text: 'دکمه نمونه',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.onButtonPressed();
|
Get.bottomSheet(
|
||||||
|
isScrollControlled: true,
|
||||||
|
enableDrag: true,
|
||||||
|
|
||||||
|
|
||||||
|
BaseBottomSheet(
|
||||||
|
height: Get.height * 0.8,
|
||||||
|
child: ObxValue((data) {
|
||||||
|
if (data.value == null) {
|
||||||
|
return Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
return Obx(
|
||||||
|
() => SDUIFormWidget(
|
||||||
|
model: data.value!,
|
||||||
|
controllers: controller.controllers,
|
||||||
|
state: controller.formState,
|
||||||
|
onStateChanged: (key, value) {
|
||||||
|
controller.formState[key] = value;
|
||||||
|
},
|
||||||
|
images: controller.images,
|
||||||
|
onImagesChanged: (key, imageList) {
|
||||||
|
controller.images[key] = imageList;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}, controller.sduiModel),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(height: 24.h),
|
SizedBox(height: 24.h),
|
||||||
|
|||||||
@@ -1,13 +1,149 @@
|
|||||||
{
|
{
|
||||||
"type": "card_label_item",
|
"info": {
|
||||||
"visible": true,
|
"type": "column",
|
||||||
"data": {
|
"visible": true,
|
||||||
"title": "اطلاعات مزرعه",
|
"data": {
|
||||||
"padding_horizontal": 12.0,
|
"spacing": 10.0,
|
||||||
"padding_vertical": 11.0
|
"crossAxisAlignment": "start"
|
||||||
},
|
},
|
||||||
"child": {
|
"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",
|
||||||
|
"label": "پروانه بهداشتی",
|
||||||
|
"keyboard_type": "number"
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text_form_field",
|
||||||
|
"visible": true,
|
||||||
|
"data": {
|
||||||
|
"key": "unit_date",
|
||||||
|
"label": "نام تاریییییییییییخ",
|
||||||
|
"keyboard_type": "text",
|
||||||
|
"type": "date_picker"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": "ضعیف"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "dropdown",
|
||||||
|
"visible": true,
|
||||||
|
"data": {
|
||||||
|
"key": "training_status",
|
||||||
|
"label": "آموزشدیده در حوزه بهداشت و امنیت زیستی",
|
||||||
|
"placeholder": "آموزشدیده در حوزه بهداشت و امنیت زیستی",
|
||||||
|
"items": [
|
||||||
|
"بله",
|
||||||
|
"خیر"
|
||||||
|
],
|
||||||
|
"selectedValue": null,
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image_picker",
|
||||||
|
"visible": true,
|
||||||
|
"data": {
|
||||||
|
"key": "hall_images",
|
||||||
|
"label": "ثبت عکس سالن (حداقل ۳ زاویه)",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image_picker",
|
||||||
|
"visible": true,
|
||||||
|
"data": {
|
||||||
|
"key": "hall_images_klllll",
|
||||||
|
"label": "ثبت عکس",
|
||||||
|
"required": true,
|
||||||
|
"max_images": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -213,86 +213,98 @@ class _RTextFieldState extends State<RTextField> {
|
|||||||
return widget.height;
|
return widget.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get _isMultiLine {
|
||||||
|
return (widget.maxLines != null && widget.maxLines! > 1) ||
|
||||||
|
(widget.minLines != null && widget.minLines! > 1);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
final Widget textField = Padding(
|
||||||
height: _calculateHeight().h,
|
padding: widget.padding ?? EdgeInsets.zero,
|
||||||
child: Padding(
|
child: TextFormField(
|
||||||
padding: widget.padding ?? EdgeInsets.zero,
|
key: _formFieldKey,
|
||||||
child: TextFormField(
|
textAlignVertical: _isMultiLine
|
||||||
key: _formFieldKey,
|
? TextAlignVertical.top
|
||||||
textAlignVertical: TextAlignVertical.center,
|
: TextAlignVertical.center,
|
||||||
controller: widget.controller,
|
controller: widget.controller,
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
textAlign: widget.textAlign ?? TextAlign.start,
|
textAlign: widget.textAlign ?? TextAlign.start,
|
||||||
readOnly: widget.readonly,
|
readOnly: widget.readonly,
|
||||||
minLines: widget.minLines,
|
minLines: widget.minLines,
|
||||||
maxLines: widget.maxLines,
|
maxLines: widget.maxLines,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
widget.onChanged?.call(value);
|
widget.onChanged?.call(value);
|
||||||
},
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
final error = widget.validator?.call(value);
|
final error = widget.validator?.call(value);
|
||||||
|
|
||||||
if (widget.isFullHeight) {
|
if (widget.isFullHeight) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
},
|
},
|
||||||
inputFormatters: widget.inputFormatters,
|
inputFormatters: widget.inputFormatters,
|
||||||
enabled: widget.enabled,
|
enabled: widget.enabled,
|
||||||
obscureText: obscure,
|
obscureText: obscure,
|
||||||
onTap: widget.onTap,
|
onTap: widget.onTap,
|
||||||
onTapOutside: (_) => FocusScope.of(context).unfocus(),
|
onTapOutside: (_) => FocusScope.of(context).unfocus(),
|
||||||
onFieldSubmitted: widget.onSubmitted,
|
onFieldSubmitted: widget.onSubmitted,
|
||||||
maxLength: widget.maxLength,
|
maxLength: widget.maxLength,
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
style: widget.style,
|
style: widget.style,
|
||||||
keyboardType: widget.keyboardType,
|
keyboardType: widget.keyboardType,
|
||||||
autovalidateMode:
|
autovalidateMode: widget.autoValidateMode ?? AutovalidateMode.disabled,
|
||||||
widget.autoValidateMode ?? AutovalidateMode.disabled,
|
cursorColor: widget.cursorColor,
|
||||||
cursorColor: widget.cursorColor,
|
textCapitalization: widget.textCapitalization,
|
||||||
textCapitalization: widget.textCapitalization,
|
autocorrect: widget.autocorrect ?? true,
|
||||||
autocorrect: widget.autocorrect ?? true,
|
enableSuggestions: widget.enableSuggestions ?? true,
|
||||||
enableSuggestions: widget.enableSuggestions ?? true,
|
textInputAction: widget.textInputAction,
|
||||||
textInputAction: widget.textInputAction,
|
autofillHints: widget.autofillHints,
|
||||||
autofillHints: widget.autofillHints,
|
decoration: InputDecoration(
|
||||||
decoration: InputDecoration(
|
contentPadding: EdgeInsets.symmetric(
|
||||||
contentPadding: EdgeInsets.symmetric(
|
horizontal: 16,
|
||||||
horizontal: 16,
|
vertical: _isMultiLine
|
||||||
vertical: widget.isFullHeight ? widget.height / 3 : 0,
|
? 12
|
||||||
),
|
: (widget.isFullHeight ? widget.height / 3 : 0),
|
||||||
|
|
||||||
errorStyle: widget.errorStyle,
|
|
||||||
errorMaxLines: 1,
|
|
||||||
isDense: widget.isDense,
|
|
||||||
suffix: widget.suffix,
|
|
||||||
suffixIcon: _buildSuffixIcon(),
|
|
||||||
suffixIconConstraints: widget.boxConstraints,
|
|
||||||
prefixIcon: widget.prefixIcon,
|
|
||||||
prefixIconConstraints: widget.boxConstraints,
|
|
||||||
hintText: widget.hintText,
|
|
||||||
labelText: widget.label,
|
|
||||||
alignLabelWithHint: true,
|
|
||||||
labelStyle: AppFonts.yekan14
|
|
||||||
.copyWith(color: AppColor.lightGreyDarkActive)
|
|
||||||
.merge(widget.labelStyle),
|
|
||||||
filled:
|
|
||||||
widget.filled || widget._noBorder || widget._passwordNoBorder,
|
|
||||||
fillColor: widget.filledColor,
|
|
||||||
counter: widget.showCounter ? null : const SizedBox(),
|
|
||||||
hintStyle: widget.hintStyle,
|
|
||||||
enabledBorder: widget._inputBorder,
|
|
||||||
focusedBorder: widget.focusedBorder ?? widget._inputBorder,
|
|
||||||
border: widget._inputBorder,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
errorStyle: widget.errorStyle,
|
||||||
|
errorMaxLines: 1,
|
||||||
|
isDense: widget.isDense,
|
||||||
|
suffix: widget.suffix,
|
||||||
|
suffixIcon: _buildSuffixIcon(),
|
||||||
|
suffixIconConstraints: widget.boxConstraints,
|
||||||
|
prefixIcon: widget.prefixIcon,
|
||||||
|
prefixIconConstraints: widget.boxConstraints,
|
||||||
|
hintText: widget.hintText,
|
||||||
|
labelText: widget.label,
|
||||||
|
alignLabelWithHint: true,
|
||||||
|
labelStyle: AppFonts.yekan14
|
||||||
|
.copyWith(color: AppColor.lightGreyDarkActive)
|
||||||
|
.merge(widget.labelStyle),
|
||||||
|
filled: widget.filled || widget._noBorder || widget._passwordNoBorder,
|
||||||
|
fillColor: widget.filledColor,
|
||||||
|
counter: widget.showCounter ? null : const SizedBox(),
|
||||||
|
hintStyle: widget.hintStyle,
|
||||||
|
enabledBorder: widget._inputBorder,
|
||||||
|
focusedBorder: widget.focusedBorder ?? widget._inputBorder,
|
||||||
|
border: widget._inputBorder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// برای فیلدهای تک خطی، ارتفاع ثابت اعمال میکنیم
|
||||||
|
// برای فیلدهای چند خطی، اجازه میدهیم ارتفاع به صورت خودکار تنظیم شود
|
||||||
|
if (_isMultiLine) {
|
||||||
|
return textField;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SizedBox(height: _calculateHeight().h, child: textField);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
Reference in New Issue
Block a user