feat: refactor NewPageLogic to utilize SDUIWidgetModel, enhance form handling with dynamic controllers, and implement SDUIFormWidget for rendering UI components

This commit is contained in:
2025-12-28 13:50:48 +03:30
parent 0b49302434
commit 71952bef5a
27 changed files with 3022 additions and 52 deletions

View File

@@ -3,18 +3,10 @@ import 'package:rasadyar_core/core.dart';
import 'model/card_label_item_sdui_model.dart';
import 'package:flutter/material.dart';
Widget cardLabelItemSDUI({required CardLabelItemSDUI model}) {
Widget cardLabelItemSDUI({required CardLabelItemSDUI model, Widget? child}) {
return farmInfoWidget(
title: model.data?.title ?? '',
child: Container(),
padding:
model.data?.paddingHorizontal != null &&
model.data?.paddingVertical != null
? EdgeInsets.symmetric(
horizontal: model.data?.paddingHorizontal ?? 0,
vertical: model.data?.paddingVertical ?? 0,
)
: null,
child: child ?? Container(),
);
}
@@ -26,17 +18,19 @@ Widget farmInfoWidget({
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.50, color: AppColor.mediumGrey),
),
padding:
padding ?? EdgeInsets.symmetric(horizontal: 12.w, vertical: 11.h),
child: child,
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(width: 0.50, color: AppColor.mediumGrey),
),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 11.h),
child: Column(
children: [
SizedBox(height: 8.h),
child,
],
),
),
Positioned(

View File

@@ -0,0 +1,65 @@
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';
class ChipSelectionSDUI extends StatelessWidget {
final ChipSelectionSDUIModel model;
final RxMap<String, dynamic>? state;
final Function(String key, int index, String? value)? onChanged;
const ChipSelectionSDUI({
super.key,
required this.model,
this.state,
this.onChanged,
});
@override
Widget build(BuildContext context) {
final options = model.options ?? [];
final spacing = 10.0;
if (options.isEmpty) {
return const SizedBox.shrink();
}
return Obx(() {
final selectedIndex =
state?[model.key] as int? ?? model.selectedIndex ?? -1;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
if (model.label != null && model.label!.isNotEmpty) ...[
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(
selectedIndex: selectedIndex,
index: optionIndex,
label: option.label ?? '',
onTap: (index) {
if (onChanged != null && model.key != null) {
onChanged!(model.key!, index, option.value);
}
},
),
);
}).toList(),
),
],
);
});
}
}

View File

@@ -0,0 +1,30 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'chip_selection_sdui_model.freezed.dart';
part 'chip_selection_sdui_model.g.dart';
@freezed
abstract class ChipSelectionSDUIModel with _$ChipSelectionSDUIModel {
const factory ChipSelectionSDUIModel({
String? key,
String? label,
List<ChipOption>? options,
int? selectedIndex,
}) = _ChipSelectionSDUIModel;
factory ChipSelectionSDUIModel.fromJson(Map<String, dynamic> json) =>
_$ChipSelectionSDUIModelFromJson(json);
}
@freezed
abstract class ChipOption with _$ChipOption {
const factory ChipOption({
int? index,
String? label,
String? value,
}) = _ChipOption;
factory ChipOption.fromJson(Map<String, dynamic> json) =>
_$ChipOptionFromJson(json);
}

View File

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

View File

@@ -0,0 +1,40 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'chip_selection_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_ChipSelectionSDUIModel _$ChipSelectionSDUIModelFromJson(
Map<String, dynamic> json,
) => _ChipSelectionSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
options: (json['options'] as List<dynamic>?)
?.map((e) => ChipOption.fromJson(e as Map<String, dynamic>))
.toList(),
selectedIndex: (json['selected_index'] as num?)?.toInt(),
);
Map<String, dynamic> _$ChipSelectionSDUIModelToJson(
_ChipSelectionSDUIModel instance,
) => <String, dynamic>{
'key': instance.key,
'label': instance.label,
'options': instance.options,
'selected_index': instance.selectedIndex,
};
_ChipOption _$ChipOptionFromJson(Map<String, dynamic> json) => _ChipOption(
index: (json['index'] as num?)?.toInt(),
label: json['label'] as String?,
value: json['value'] as String?,
);
Map<String, dynamic> _$ChipOptionToJson(_ChipOption instance) =>
<String, dynamic>{
'index': instance.index,
'label': instance.label,
'value': instance.value,
};

View File

@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/dropdown/model/dropdown_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class DropdownSDUI extends StatelessWidget {
final DropdownSDUIModel model;
final RxMap<String, dynamic>? state;
final Function(String key, String value)? onChanged;
const DropdownSDUI({
super.key,
required this.model,
this.state,
this.onChanged,
});
@override
Widget build(BuildContext context) {
final items = model.items ?? [];
if (items.isEmpty) {
return const SizedBox.shrink();
}
return Obx(() {
final selectedValue = state?[model.key] as String? ?? model.selectedValue;
return ResourceOverlayDropdown<String>(
items: Resource.success(items),
selectedItem: selectedValue,
onChanged: (item) {
if (onChanged != null && model.key != null) {
onChanged!(model.key!, item);
}
},
itemBuilder: (item) => Text(item),
labelBuilder: (selected) =>
Text(selected ?? (model.placeholder ?? model.label ?? '')),
isDisabled: model.enabled == false,
);
});
}
}

View File

@@ -0,0 +1,20 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'dropdown_sdui_model.freezed.dart';
part 'dropdown_sdui_model.g.dart';
@freezed
abstract class DropdownSDUIModel with _$DropdownSDUIModel {
const factory DropdownSDUIModel({
String? key,
String? label,
String? placeholder,
List<String>? items,
String? selectedValue,
bool? enabled,
}) = _DropdownSDUIModel;
factory DropdownSDUIModel.fromJson(Map<String, dynamic> json) =>
_$DropdownSDUIModelFromJson(json);
}

View File

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

View File

@@ -0,0 +1,29 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'dropdown_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_DropdownSDUIModel _$DropdownSDUIModelFromJson(Map<String, dynamic> json) =>
_DropdownSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
placeholder: json['placeholder'] as String?,
items: (json['items'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
selectedValue: json['selected_value'] as String?,
enabled: json['enabled'] as bool?,
);
Map<String, dynamic> _$DropdownSDUIModelToJson(_DropdownSDUIModel instance) =>
<String, dynamic>{
'key': instance.key,
'label': instance.label,
'placeholder': instance.placeholder,
'items': instance.items,
'selected_value': instance.selectedValue,
'enabled': instance.enabled,
};

View File

@@ -0,0 +1,251 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:rasadyar_chicken/presentation/widget/sdui/widgets/image_picker/model/image_picker_sdui_model.dart';
import 'package:rasadyar_core/core.dart';
class ImagePickerSDUI extends StatefulWidget {
final ImagePickerSDUIModel model;
final Map<String, RxList<XFile>>? images;
final Function(String key, RxList<XFile> images)? onImagesChanged;
const ImagePickerSDUI({
super.key,
required this.model,
this.images,
this.onImagesChanged,
});
@override
State<ImagePickerSDUI> createState() => _ImagePickerSDUIState();
}
class _ImagePickerSDUIState extends State<ImagePickerSDUI> {
late RImagePickerController imagePickerController;
RxList<XFile>? imageList;
Set<String> _addedImagePaths = {}; // برای track کردن عکس‌های اضافه شده
@override
void initState() {
super.initState();
imagePickerController = RImagePickerController();
final key = widget.model.key ?? '';
if (key.isNotEmpty) {
// Get or create the images list for this key
if (widget.images != null && widget.images!.containsKey(key)) {
imageList = widget.images![key]!;
// اضافه کردن path های عکس‌های موجود به set
_addedImagePaths = imageList!.map((img) => img.path).toSet();
} else {
imageList = RxList<XFile>();
if (widget.images != null) {
widget.images![key] = imageList!;
}
_addedImagePaths = {};
}
imagePickerController.capturedImages.clear();
// Listen to controller changes
imagePickerController.addListener(() {
if (imagePickerController.capturedImages.isNotEmpty &&
imageList != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final maxImages = widget.model.maxImages;
final allCapturedImages = imagePickerController.capturedImages;
// فقط عکس‌های جدید را پیدا می‌کنیم (عکس‌هایی که قبلاً اضافه نشده‌اند)
final newImages = allCapturedImages
.where((img) => !_addedImagePaths.contains(img.path))
.toList();
if (newImages.isNotEmpty) {
if (maxImages != null) {
// اگر محدودیت وجود دارد، فقط تا maxImages عکس اضافه می‌کنیم
final currentCount = imageList!.length;
final remainingSlots = maxImages - currentCount;
if (remainingSlots > 0) {
final imagesToAdd = newImages.take(remainingSlots).toList();
imageList!.addAll(imagesToAdd);
// اضافه کردن path های عکس‌های جدید به set
_addedImagePaths.addAll(imagesToAdd.map((img) => img.path));
}
} else {
// اگر محدودیت وجود ندارد، همه عکس‌های جدید را اضافه می‌کنیم
imageList!.addAll(newImages);
// اضافه کردن path های عکس‌های جدید به set
_addedImagePaths.addAll(newImages.map((img) => img.path));
}
}
if (widget.onImagesChanged != null) {
widget.onImagesChanged!(key, imageList!);
}
});
}
});
}
}
@override
void dispose() {
imagePickerController.disposeCameraController();
super.dispose();
}
@override
Widget build(BuildContext context) {
final key = widget.model.key ?? '';
if (key.isEmpty || imageList == null) {
return const SizedBox.shrink();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 10.h),
Row(
children: [
Expanded(
child: Obx(() {
final maxImages = widget.model.maxImages;
final currentImageCount = imageList!.length;
final canAddMore =
maxImages == null || currentImageCount < maxImages;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
physics: BouncingScrollPhysics(),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
spacing: 8,
children: [
...imageList!.map(
(entry) => Stack(
children: [
Container(
height: 80.h,
width: 80.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(entry.path),
fit: BoxFit.cover,
),
),
),
// Delete button
Positioned(
top: 4,
left: 4,
child: GestureDetector(
onTap: () {
imageList!.removeWhere(
(element) => element.path == entry.path,
);
// حذف path از set
_addedImagePaths.remove(entry.path);
if (widget.onImagesChanged != null) {
widget.onImagesChanged!(key, imageList!);
}
},
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
color: Colors.white,
size: 16,
),
),
),
),
],
),
),
// Add image button - only show if we can add more
if (canAddMore)
GestureDetector(
onTap: () {
imagePickerController.capturedImages.clear();
final existingPaths = imageList!
.map((img) => img.path)
.toSet();
_addedImagePaths = existingPaths;
Get.to(
() => RImagePicker(
controller: imagePickerController,
maxImages: maxImages != null
? maxImages - currentImageCount
: null,
),
fullscreenDialog: true,
transition: Transition.fade,
duration: Duration(milliseconds: 300),
);
},
child: Container(
height: 80.h,
width: 80.w,
padding: EdgeInsets.all(22),
decoration: BoxDecoration(
color: Color(0xFFE9E9E9),
border: Border.all(
width: 1,
color: AppColor.blackLightHover,
),
borderRadius: BorderRadius.circular(8),
),
child: Assets.vec.galleryAddSvg.svg(
width: 36,
height: 36,
),
),
),
],
),
);
}),
),
],
),
if (widget.model.label != null && widget.model.label!.isNotEmpty) ...[
SizedBox(height: 9.h),
RichText(
text: TextSpan(
children: [
TextSpan(
text: widget.model.label!,
style: AppFonts.yekan14.copyWith(
color: AppColor.textColorLight,
),
),
if (widget.model.required == true)
TextSpan(
text: ' *',
style: AppFonts.yekan14.copyWith(color: Colors.red),
),
],
),
),
],
],
);
}
}

View File

@@ -0,0 +1,18 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'image_picker_sdui_model.freezed.dart';
part 'image_picker_sdui_model.g.dart';
@freezed
abstract class ImagePickerSDUIModel with _$ImagePickerSDUIModel {
const factory ImagePickerSDUIModel({
String? key,
String? label,
bool? required,
int? maxImages,
}) = _ImagePickerSDUIModel;
factory ImagePickerSDUIModel.fromJson(Map<String, dynamic> json) =>
_$ImagePickerSDUIModelFromJson(json);
}

View File

@@ -0,0 +1,286 @@
// 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 'image_picker_sdui_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ImagePickerSDUIModel {
String? get key; String? get label; bool? get required; int? get maxImages;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ImagePickerSDUIModelCopyWith<ImagePickerSDUIModel> get copyWith => _$ImagePickerSDUIModelCopyWithImpl<ImagePickerSDUIModel>(this as ImagePickerSDUIModel, _$identity);
/// Serializes this ImagePickerSDUIModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is ImagePickerSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.required, required) || other.required == required)&&(identical(other.maxImages, maxImages) || other.maxImages == maxImages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,required,maxImages);
@override
String toString() {
return 'ImagePickerSDUIModel(key: $key, label: $label, required: $required, maxImages: $maxImages)';
}
}
/// @nodoc
abstract mixin class $ImagePickerSDUIModelCopyWith<$Res> {
factory $ImagePickerSDUIModelCopyWith(ImagePickerSDUIModel value, $Res Function(ImagePickerSDUIModel) _then) = _$ImagePickerSDUIModelCopyWithImpl;
@useResult
$Res call({
String? key, String? label, bool? required, int? maxImages
});
}
/// @nodoc
class _$ImagePickerSDUIModelCopyWithImpl<$Res>
implements $ImagePickerSDUIModelCopyWith<$Res> {
_$ImagePickerSDUIModelCopyWithImpl(this._self, this._then);
final ImagePickerSDUIModel _self;
final $Res Function(ImagePickerSDUIModel) _then;
/// Create a copy of ImagePickerSDUIModel
/// 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? required = freezed,Object? maxImages = freezed,}) {
return _then(_self.copyWith(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,maxImages: freezed == maxImages ? _self.maxImages : maxImages // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// Adds pattern-matching-related methods to [ImagePickerSDUIModel].
extension ImagePickerSDUIModelPatterns on ImagePickerSDUIModel {
/// 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( _ImagePickerSDUIModel value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() 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( _ImagePickerSDUIModel value) $default,){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel():
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( _ImagePickerSDUIModel value)? $default,){
final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String? key, String? label, bool? required, int? maxImages)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String? key, String? label, bool? required, int? maxImages) $default,) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel():
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String? key, String? label, bool? required, int? maxImages)? $default,) {final _that = this;
switch (_that) {
case _ImagePickerSDUIModel() when $default != null:
return $default(_that.key,_that.label,_that.required,_that.maxImages);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _ImagePickerSDUIModel implements ImagePickerSDUIModel {
const _ImagePickerSDUIModel({this.key, this.label, this.required, this.maxImages});
factory _ImagePickerSDUIModel.fromJson(Map<String, dynamic> json) => _$ImagePickerSDUIModelFromJson(json);
@override final String? key;
@override final String? label;
@override final bool? required;
@override final int? maxImages;
/// Create a copy of ImagePickerSDUIModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ImagePickerSDUIModelCopyWith<_ImagePickerSDUIModel> get copyWith => __$ImagePickerSDUIModelCopyWithImpl<_ImagePickerSDUIModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ImagePickerSDUIModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _ImagePickerSDUIModel&&(identical(other.key, key) || other.key == key)&&(identical(other.label, label) || other.label == label)&&(identical(other.required, required) || other.required == required)&&(identical(other.maxImages, maxImages) || other.maxImages == maxImages));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,key,label,required,maxImages);
@override
String toString() {
return 'ImagePickerSDUIModel(key: $key, label: $label, required: $required, maxImages: $maxImages)';
}
}
/// @nodoc
abstract mixin class _$ImagePickerSDUIModelCopyWith<$Res> implements $ImagePickerSDUIModelCopyWith<$Res> {
factory _$ImagePickerSDUIModelCopyWith(_ImagePickerSDUIModel value, $Res Function(_ImagePickerSDUIModel) _then) = __$ImagePickerSDUIModelCopyWithImpl;
@override @useResult
$Res call({
String? key, String? label, bool? required, int? maxImages
});
}
/// @nodoc
class __$ImagePickerSDUIModelCopyWithImpl<$Res>
implements _$ImagePickerSDUIModelCopyWith<$Res> {
__$ImagePickerSDUIModelCopyWithImpl(this._self, this._then);
final _ImagePickerSDUIModel _self;
final $Res Function(_ImagePickerSDUIModel) _then;
/// Create a copy of ImagePickerSDUIModel
/// 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? required = freezed,Object? maxImages = freezed,}) {
return _then(_ImagePickerSDUIModel(
key: freezed == key ? _self.key : key // ignore: cast_nullable_to_non_nullable
as String?,label: freezed == label ? _self.label : label // ignore: cast_nullable_to_non_nullable
as String?,required: freezed == required ? _self.required : required // ignore: cast_nullable_to_non_nullable
as bool?,maxImages: freezed == maxImages ? _self.maxImages : maxImages // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
// dart format on

View File

@@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'image_picker_sdui_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_ImagePickerSDUIModel _$ImagePickerSDUIModelFromJson(
Map<String, dynamic> json,
) => _ImagePickerSDUIModel(
key: json['key'] as String?,
label: json['label'] as String?,
required: json['required'] as bool?,
maxImages: (json['max_images'] as num?)?.toInt(),
);
Map<String, dynamic> _$ImagePickerSDUIModelToJson(
_ImagePickerSDUIModel instance,
) => <String, dynamic>{
'key': instance.key,
'label': instance.label,
'required': instance.required,
'max_images': instance.maxImages,
};

View File

@@ -4,26 +4,81 @@ import 'package:rasadyar_core/core.dart';
import 'model/text_form_field_sdui_model.dart';
Widget textFormFiledSDUI({required TextFormFieldSDUIModel model}) {
Widget textFormFiledSDUI({
required TextFormFieldSDUIModel model,
TextEditingController? controller,
}) {
List<TextInputFormatter>? inputFormatters = [];
TextInputType? keyboardType;
VoidCallback? onTap;
bool isReadonly = model.readonly ?? false;
if (model.keyboardType == 'text') {
keyboardType = TextInputType.text;
} else if (model.keyboardType == 'number') {
keyboardType = TextInputType.numberWithOptions(
decimal: model.decimal ?? false,
);
final textController = controller ?? TextEditingController(text: model.value);
inputFormatters.add(FilteringTextInputFormatter.digitsOnly);
}
if (model.type == 'date_picker') {
// برای date picker، readonly می‌کنیم و onTap اضافه می‌کنیم
isReadonly = true;
if (model.commaSperator ?? false) {
inputFormatters.add(SeparatorInputFormatter());
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) {
final year = int.tryParse(parts[0]);
final month = int.tryParse(parts[1]);
final day = int.tryParse(parts[2]);
if (year != null && month != null && day != null) {
initialDate = Jalali(year, month, day);
}
}
} catch (e) {
iLog('Error parsing date: $e');
}
}
// اگر نتوانستیم parse کنیم، از تاریخ امروز استفاده می‌کنیم
initialDate ??= Jalali.now();
// نمایش date picker
Get.bottomSheet(
modalDatePicker(
initialDate: initialDate,
onDateSelected: (selectedDate) {
// فرمت کردن تاریخ و قرار دادن در controller
textController.text = selectedDate.formatCompactDate();
},
),
isScrollControlled: true,
);
};
} else {
if (model.keyboardType == 'text') {
keyboardType = TextInputType.text;
} else if (model.keyboardType == 'number') {
final isDecimal = model.decimal ?? false;
keyboardType = TextInputType.numberWithOptions(decimal: isDecimal);
if (!isDecimal) {
inputFormatters.add(FilteringTextInputFormatter.digitsOnly);
}
}
if ((model.commaSperator ?? false) &&
(model.decimal == null || model.decimal == false)) {
inputFormatters.add(SeparatorInputFormatter());
}
}
return RTextField(
controller: TextEditingController(text: model.value),
controller: textController,
onChanged: (data) {
iLog(data);
},
onTap: onTap,
label: model.label,
filled: true,
filledColor: AppColor.bgLight,
@@ -32,8 +87,8 @@ Widget textFormFiledSDUI({required TextFormFieldSDUIModel model}) {
maxLength: model.maxLength,
minLines: model.minLine,
maxLines: model.maxLine,
enabled: model.enabled ?? false,
enabled: model.enabled ?? true,
inputFormatters: inputFormatters,
readonly: model.readonly ?? false,
readonly: isReadonly,
);
}