feat : dynamic form navigation

This commit is contained in:
2025-04-26 16:50:19 +03:30
parent 6e6d2b22f6
commit c10ddaf0d5
11 changed files with 568 additions and 369 deletions

View File

@@ -9,5 +9,5 @@ export 'package:rasadyar_core/presentation/widget/widget.dart';
export 'package:flutter_slidable/flutter_slidable.dart';
export 'package:font_awesome_flutter/font_awesome_flutter.dart';
export 'package:flutter_rating_bar/flutter_rating_bar.dart';
export 'package:persian_datetime_picker/persian_datetime_picker.dart';
import 'package:dartx/dartx.dart' as dartx;

View File

@@ -0,0 +1,26 @@
extension ListExtensions<T> on List<T> {
void toggle(T item) {
if (contains(item)) {
if (length > 1) {
remove(item);
}
} else {
add(item);
}
}
void ensureContainsAtStart(T item) {
if (!contains(item)) {
insert(0, item);
}
}
void removeIfPresent(T item) {
remove(item);
}
void resetWith(T item) {
clear();
add(item);
}
}

View File

@@ -1 +1,2 @@
export 'color_utils.dart';
export 'color_utils.dart';
export 'list_extensions.dart';

View File

@@ -43,7 +43,7 @@ class _ROutlinedElevatedStateIcon extends State<ROutlinedElevatedIcon> {
return OutlinedButton.icon(
icon: widget.icon,
label: Text(widget.text),
onPressed: () {},
onPressed: widget.onPressed,
style: ButtonStyle(
side: WidgetStateProperty.resolveWith<BorderSide?>((states) {
if (states.contains(WidgetState.pressed)) {

View File

@@ -1,110 +1,115 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:rasadyar_core/core.dart';
@immutable
class RTextField extends StatefulWidget {
RTextField(
{super.key,
this.maxLines,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.isForNumber = false,
this.style,
this.hintStyle,
this.suffixIcon,
this.prefixIcon,
this.validator,
this.readonly = false,
this.boxConstraints,
this.minLines,
this.radius,
this.filled,
this.filledColor,
this.enabled,
this.errorStyle,
this.labelStyle,
this.label}) {
RTextField({
super.key,
this.maxLines,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.isForNumber = false,
this.style,
this.hintStyle,
this.suffixIcon,
this.prefixIcon,
this.validator,
this.readonly = false,
this.boxConstraints,
this.minLines,
this.radius,
this.filled,
this.filledColor,
this.enabled,
this.errorStyle,
this.labelStyle,
this.label,
}) {
filled = filled ?? false;
obscure = false;
_inputBorder = OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(radius ?? 16));
borderSide: BorderSide(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(radius ?? 8),
);
}
RTextField.noBorder(
{super.key,
this.maxLines,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.style,
this.hintStyle,
this.suffixIcon,
this.radius,
this.validator,
this.boxConstraints,
this.minLines,
this.isForNumber = false,
this.readonly = false,
this.label,
this.filled,
this.filledColor,
this.errorStyle,
this.labelStyle,
this.enabled}) {
RTextField.noBorder({
super.key,
this.maxLines,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.style,
this.hintStyle,
this.suffixIcon,
this.radius,
this.validator,
this.boxConstraints,
this.minLines,
this.isForNumber = false,
this.readonly = false,
this.label,
this.filled,
this.filledColor,
this.errorStyle,
this.labelStyle,
this.enabled,
}) {
_inputBorder = OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(radius ?? 16));
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(radius ?? 16),
);
obscure = false;
filled = filled ?? true;
}
RTextField.password(
{super.key,
this.maxLines = 1,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.style,
this.hintStyle,
this.suffixIcon,
this.prefixIcon,
this.radius,
this.validator,
this.boxConstraints,
this.minLines,
this.isForNumber = false,
this.readonly = false,
this.label,
this.filled,
this.filledColor,
this.errorStyle,
this.labelStyle,
this.enabled}) {
RTextField.password({
super.key,
this.maxLines = 1,
this.maxLength,
this.hintText,
this.padding,
this.onChanged,
this.onSubmitted,
this.keyboardType,
this.showCounter = false,
this.isDense,
this.initText,
this.style,
this.hintStyle,
this.suffixIcon,
this.prefixIcon,
this.radius,
this.validator,
this.boxConstraints,
this.minLines,
this.isForNumber = false,
this.readonly = false,
this.label,
this.filled,
this.filledColor,
this.errorStyle,
this.labelStyle,
this.enabled,
}) {
_inputBorder = OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(radius ?? 16));
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(radius ?? 16),
);
filled = filled ?? true;
obscure = true;
_isPassword = true;
@@ -170,53 +175,61 @@ class _RTextFieldState extends State<RTextField> {
@override
Widget build(BuildContext context) {
return Padding(
padding: widget.padding ?? const EdgeInsets.symmetric(vertical: 6.0),
child: TextFormField(
controller: _controller,
readOnly: widget.readonly,
minLines: widget.minLines,
maxLines: widget.maxLines,
onChanged: widget.onChanged,
validator: widget.validator,
enabled: widget.enabled,
obscureText: obscure ?? false,
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
onFieldSubmitted: widget.onSubmitted,
maxLength: widget.maxLength,
textDirection: TextDirection.rtl,
style: widget.style ,
keyboardType: widget.keyboardType,
decoration: InputDecoration(
errorStyle: widget.errorStyle,
errorMaxLines: 1,
isDense: widget.isDense,
suffixIcon: widget.suffixIcon ??
(widget._isPassword
? IconButton(
onPressed: () {
setState(() {
obscure = !obscure!;
});
},
icon: Icon(!obscure!
? CupertinoIcons.eye_slash
: CupertinoIcons.eye))
: null),
suffixIconConstraints: widget.boxConstraints,
prefixIcon: widget.prefixIcon,
prefixIconConstraints: widget.boxConstraints,
hintText: widget.hintText,
labelText: widget.label,
labelStyle: widget.labelStyle??AppFonts.yekan14.copyWith(color: AppColor.lightGreyDarkActive),
filled: widget.filled,
fillColor: widget.filledColor,
counter: widget.showCounter ? null : const SizedBox(),
hintStyle: widget.hintStyle,
enabledBorder: widget._inputBorder,
focusedBorder: widget._inputBorder,
border: widget._inputBorder),
));
padding: widget.padding ?? EdgeInsets.zero,
child: TextFormField(
controller: _controller,
readOnly: widget.readonly,
minLines: widget.minLines,
maxLines: widget.maxLines,
onChanged: widget.onChanged,
validator: widget.validator,
enabled: widget.enabled,
obscureText: obscure ?? false,
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
onFieldSubmitted: widget.onSubmitted,
maxLength: widget.maxLength,
textDirection: TextDirection.rtl,
style: widget.style,
keyboardType: widget.keyboardType,
decoration: InputDecoration(
contentPadding: EdgeInsets.symmetric(horizontal: 16),
errorStyle: widget.errorStyle,
errorMaxLines: 1,
isDense: widget.isDense,
suffixIcon:
widget.suffixIcon ??
(widget._isPassword
? IconButton(
onPressed: () {
setState(() {
obscure = !obscure!;
});
},
icon: Icon(
!obscure! ? CupertinoIcons.eye_slash : CupertinoIcons.eye,
),
)
: null),
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,
fillColor: widget.filledColor,
counter: widget.showCounter ? null : const SizedBox(),
hintStyle: widget.hintStyle,
enabledBorder: widget._inputBorder,
focusedBorder: widget._inputBorder,
border: widget._inputBorder,
),
),
);
}
}
}