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:
2025-12-28 16:05:37 +03:30
parent 71952bef5a
commit fc0161e261
4 changed files with 1343 additions and 113 deletions

View File

@@ -213,86 +213,98 @@ class _RTextFieldState extends State<RTextField> {
return widget.height;
}
bool get _isMultiLine {
return (widget.maxLines != null && widget.maxLines! > 1) ||
(widget.minLines != null && widget.minLines! > 1);
}
@override
Widget build(BuildContext context) {
return SizedBox(
height: _calculateHeight().h,
child: Padding(
padding: widget.padding ?? EdgeInsets.zero,
child: TextFormField(
key: _formFieldKey,
textAlignVertical: TextAlignVertical.center,
controller: widget.controller,
focusNode: widget.focusNode,
textAlign: widget.textAlign ?? TextAlign.start,
readOnly: widget.readonly,
minLines: widget.minLines,
maxLines: widget.maxLines,
onChanged: (value) {
widget.onChanged?.call(value);
},
validator: (value) {
final error = widget.validator?.call(value);
final Widget textField = Padding(
padding: widget.padding ?? EdgeInsets.zero,
child: TextFormField(
key: _formFieldKey,
textAlignVertical: _isMultiLine
? TextAlignVertical.top
: TextAlignVertical.center,
controller: widget.controller,
focusNode: widget.focusNode,
textAlign: widget.textAlign ?? TextAlign.start,
readOnly: widget.readonly,
minLines: widget.minLines,
maxLines: widget.maxLines,
onChanged: (value) {
widget.onChanged?.call(value);
},
validator: (value) {
final error = widget.validator?.call(value);
if (widget.isFullHeight) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {});
}
});
}
return error;
},
inputFormatters: widget.inputFormatters,
enabled: widget.enabled,
obscureText: obscure,
onTap: widget.onTap,
onTapOutside: (_) => FocusScope.of(context).unfocus(),
onFieldSubmitted: widget.onSubmitted,
maxLength: widget.maxLength,
textDirection: textDirection,
style: widget.style,
keyboardType: widget.keyboardType,
autovalidateMode:
widget.autoValidateMode ?? AutovalidateMode.disabled,
cursorColor: widget.cursorColor,
textCapitalization: widget.textCapitalization,
autocorrect: widget.autocorrect ?? true,
enableSuggestions: widget.enableSuggestions ?? true,
textInputAction: widget.textInputAction,
autofillHints: widget.autofillHints,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
horizontal: 16,
vertical: 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,
if (widget.isFullHeight) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {});
}
});
}
return error;
},
inputFormatters: widget.inputFormatters,
enabled: widget.enabled,
obscureText: obscure,
onTap: widget.onTap,
onTapOutside: (_) => FocusScope.of(context).unfocus(),
onFieldSubmitted: widget.onSubmitted,
maxLength: widget.maxLength,
textDirection: textDirection,
style: widget.style,
keyboardType: widget.keyboardType,
autovalidateMode: widget.autoValidateMode ?? AutovalidateMode.disabled,
cursorColor: widget.cursorColor,
textCapitalization: widget.textCapitalization,
autocorrect: widget.autocorrect ?? true,
enableSuggestions: widget.enableSuggestions ?? true,
textInputAction: widget.textInputAction,
autofillHints: widget.autofillHints,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(
horizontal: 16,
vertical: _isMultiLine
? 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,
),
),
);
// برای فیلدهای تک خطی، ارتفاع ثابت اعمال می‌کنیم
// برای فیلدهای چند خطی، اجازه می‌دهیم ارتفاع به صورت خودکار تنظیم شود
if (_isMultiLine) {
return textField;
}
return SizedBox(height: _calculateHeight().h, child: textField);
}
@override