Rumahjo-Android-APP/lib/Ui/screens/widgets/DynamicField/dynamic_field.dart
2024-09-07 07:58:50 +07:00

1330 lines
46 KiB
Dart

// ignore_for_file: public_member_api_docs, sort_constructors_first
// ignore_for_file: invalid_use_of_visible_for_testing_member
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:ebroker/exports/main_export.dart';
import 'package:ebroker/utils/Extensions/extensions.dart';
import 'package:ebroker/utils/helper_utils.dart';
import 'package:ebroker/utils/responsiveSize.dart';
import 'package:ebroker/utils/ui_utils.dart';
import 'package:file_icon/src/data.dart' as d;
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../../../../utils/AppIcon.dart';
import '../custom_text_form_field.dart';
/// Note: Here i have used abstract factory pattern and builder pattern
/// You can learn design patterns from internet
/// so don't be confuse
List kDoNotReBuildThese = [];
List kDoNotReBuildDropdown = [];
abstract class AbstractField {
final BuildContext context;
static Map fieldsData = {};
AbstractField(this.context);
Widget createField(Map parameters);
}
class AbstractTextField extends AbstractField {
AbstractTextField(BuildContext context)
: super(
context,
);
// TextEditingController? _controller;
///Here Builder pattern to set values,
/// because when if we get it from constructor it will be messed in Factory class so it
///You can uncomment it if you want to use controller out side of the class
// AbstractTextField setController(TextEditingController controller) {
// _controller = controller;
// return this;
// }
@override
Widget createField(parameters) {
return Column(
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(parameters['name'])
.size(context.font.large)
.bold(weight: FontWeight.w500)
.color(context.color.textColorDark)
],
),
SizedBox(
height: 14.rh(context),
),
CustomTextFieldDynamic(
action: TextInputAction.next,
initController: parameters['value'] != null ? true : false,
value: parameters['value'].toString(),
hintText: "writeSomething".translate(context),
id: parameters['id'],
)
],
);
}
}
class AbstractTextAreaField extends AbstractField {
AbstractTextAreaField(BuildContext context)
: super(
context,
);
// TextEditingController? _controller;
/// Here Builder pattern to set values,
/// because when if we get it from constructor it will be messed in Factory class so it
/// You can uncomment it if you want to use controller out side of class
//AbstractTextAreaField setController(TextEditingController controller) {
// // _controller = controller;
// return this;
//}
@override
Widget createField(parameters) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: .0,
),
child: Column(
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(parameters['name'])
.size(context.font.large)
.color(
context.color.textColorDark,
)
.bold(weight: FontWeight.w500)
],
),
SizedBox(
height: 14.rh(context),
),
CustomTextFormField(
hintText: "Write something...",
minLine: 4,
maxLine: 100,
validator: CustomTextFieldValidator.maxFifty,
controller: parameters['value'] != null
? TextEditingController(text: parameters['value'].toString())
: null,
onChange: (value) {
AbstractField.fieldsData.addAll({parameters['id']: value});
},
)
],
),
);
// return TextFormField(
// maxLines: null,
// minLines: 5,
// onChanged: (value) {
// AbstractField.fieldsData.addAll({parameters['id']: value});
// },
// decoration: InputDecoration(hintText: parameters['name']),
// );
}
}
class AbstractNumberField extends AbstractField {
AbstractNumberField(BuildContext context)
: super(
context,
);
// TextEditingController? _controller;
///Here, Builder pattern to set values,
/// because when if we get it from constructor it will be messed in Factory class so it
///You can uncomment it if you want to use controller out side of class
// AbstractNumberField setController(TextEditingController controller) {
// _controller = controller;
// return this;
// }
@override
Widget createField(parameters) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 0.0),
child: Column(
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: SizedBox(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(parameters['name'])
.size(context.font.large)
.bold(weight: FontWeight.w500)
.color(context.color.textColorDark)
],
),
SizedBox(
height: 14.rh(context),
),
CustomTextFieldDynamic(
initController: parameters['value'] != null ? true : false,
value: parameters['value'].toString(),
hintText: "addNumerical".translate(context),
formaters: [
FilteringTextInputFormatter.allow(
RegExp("[0-9]"),
),
],
action: TextInputAction.next,
keyboardType: TextInputType.number,
id: parameters['id'],
),
],
));
}
}
class AbstractDropdown extends AbstractField {
Function(dynamic onData)? _onChange;
List kDropdownSelected = [];
UniqueKey _key = UniqueKey();
List? _items;
dynamic selectedItem;
AbstractDropdown(
BuildContext context,
) : super(context);
///We can say it method chaining
///Here this is builder pattern used here it will return it self after assign value so new class has already assigned value
AbstractDropdown setOnChange(Function(dynamic onChange) onChange) {
_onChange = onChange;
return this;
}
AbstractDropdown setItems(List items) {
_items = items;
return this;
}
AbstractDropdown setSelectedItem(dynamic item) {
if (item != null) {
if (!kDoNotReBuildDropdown.contains(_key)) {
kDoNotReBuildDropdown.add(_key);
dropDownItemChange.value = item;
}
}
return this;
}
late ValueNotifier<String> dropDownItemChange =
ValueNotifier<String>(_items?.first);
@override
Widget createField(parameters) {
return CustomDropdownState(
key: _key,
dropDownItemChange: dropDownItemChange,
parameters: parameters,
items: _items ?? [],
);
return ValueListenableBuilder(
valueListenable: dropDownItemChange,
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(
0.1,
),
borderRadius: BorderRadius.circular(
10,
),
),
child: UiUtils.imageType(parameters['image'],
fit: BoxFit.none),
),
SizedBox(
width: 10.rw(
context,
),
),
Text(
parameters['name'],
)
.size(
context.font.large,
)
.color(
context.color.textColorDark,
)
],
),
SizedBox(
height: 10.rh(context),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 3,
),
child: Container(
decoration: BoxDecoration(
color: context.color.secondaryColor,
borderRadius: BorderRadius.circular(
10,
),
border: Border.all(
width: 1.5,
color: context.color.borderColor,
)),
child: Padding(
padding: const EdgeInsets.all(
8.0,
),
child: SizedBox(
width: double.infinity,
child: DropdownButton(
value: value,
isExpanded: true,
padding: EdgeInsets.symmetric(vertical: 5),
icon: SvgPicture.asset(AppIcons.downArrow),
isDense: true,
borderRadius: BorderRadius.circular(
10,
),
underline: const SizedBox.shrink(),
items: _items
?.map((e) => DropdownMenuItem(
value: e,
child: Text(
e,
),
))
.toList(),
onChanged: (dynamic v) {
dropDownItemChange.value = v;
AbstractField.fieldsData.addAll(
{
parameters['id']: v,
},
);
_onChange?.call(v);
},
),
),
),
),
),
SizedBox(
height: 10.rh(
context,
),
)
],
);
});
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AbstractDropdown &&
runtimeType == other.runtimeType &&
_onChange == other._onChange &&
kDropdownSelected == other.kDropdownSelected &&
_key == other._key &&
_items == other._items &&
selectedItem == other.selectedItem &&
dropDownItemChange == other.dropDownItemChange;
@override
int get hashCode =>
_onChange.hashCode ^
kDropdownSelected.hashCode ^
_key.hashCode ^
_items.hashCode ^
selectedItem.hashCode ^
dropDownItemChange.hashCode;
}
class AbstractRadioButton extends AbstractField {
AbstractRadioButton(BuildContext context) : super(context);
List? _radioValues;
// late ValueNotifier selectedRadio;
AbstractRadioButton setValues(
List values,
) {
_radioValues = values;
// selectedRadio = ValueNotifier(_radioValues?.first);
return this;
}
@override
Widget createField(parameters) {
return CustomRadioButtonWidget(
parameters: parameters,
radioValues: _radioValues,
);
// return ValueListenableBuilder(
// valueListenable: selectedRadio,
// builder: (context, value, child) {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// Container(
// width: 48.rw(context),
// height: 48.rh(context),
// decoration: BoxDecoration(
// color: context.color.teritoryColor.withOpacity(0.1),
// borderRadius: BorderRadius.circular(10),
// ),
// child: UiUtils.imageType(parameters['image'],
// fit: BoxFit.none),
// ),
// SizedBox(
// width: 10.rw(context),
// ),
// Text(parameters['name'])
// .size(context.font.large)
// .color(context.color.textColorDark)
// ],
// ),
// SizedBox(
// height: 10.rh(context),
// ),
// Wrap(
// alignment: WrapAlignment.start,
// runAlignment: WrapAlignment.start,
// crossAxisAlignment: WrapCrossAlignment.start,
// children: List.generate(
// _radioValues?.length ?? 0,
// (index) => Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Radio(
// value: _radioValues?[index],
// groupValue: value,
// fillColor: MaterialStatePropertyAll(
// context.color.teritoryColor),
// onChanged: (dynamic e) {
// selectedRadio.value = e;
// AbstractField.fieldsData
// .addAll({parameters['id']: e});
// },
// ),
// Text(_radioValues?[index])
// ],
// )))
// ],
// );
// // return Column(
// // crossAxisAlignment: CrossAxisAlignment.start,
// // children: [
// // Text(parameters['name']),
// // Wrap(
// // children: _radioValues
// // ?.map((item) {
// // return Row(
// // mainAxisSize: MainAxisSize.min,
// // children: [
// // Text(item),
// // Radio(
// // value: item,
// // groupValue: value,
// // onChanged: (dynamic e) {
// // selectedRadio.value = e;
// // AbstractField.fieldsData
// // .addAll({parameters['id']: e});
// // }),
// // ],
// // );
// // })
// // .toList()
// // .cast() ??
// // [],
// // ),
// // ],
// // );
// });
}
}
class AbstractCheckBoxButton extends AbstractField {
AbstractCheckBoxButton(BuildContext context) : super(context);
List? _checkValues;
bool initComplete = false;
AbstractCheckBoxButton setCheckBoxValues(List values) {
_checkValues = values;
return this;
}
@override
Widget createField(parameters) {
return CustomCheckBox(
parameters: parameters,
checkValues: _checkValues,
index: 0,
initComplete: true,
);
}
void dispose() {
// checked.dispose();
}
}
class AbstractPickFileButton extends AbstractField {
AbstractPickFileButton(BuildContext context) : super(context);
ValueNotifier filePicked = ValueNotifier(false);
ValueNotifier<String?> picked = ValueNotifier(null);
Future<File?> pickFile() async {
FilePickerResult? picker = await FilePicker.platform.pickFiles();
if (picker != null) {
filePicked.value = true;
File file = File(
picker.files.single.path!,
);
picked.value = file.path;
return file;
}
filePicked.value = false;
picked.value = null;
return null;
}
@override
Widget createField(parameters) {
picked.value = parameters['value'];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(parameters['name'])
.size(context.font.large)
.bold(weight: FontWeight.w500)
.color(context.color.textColorDark),
],
),
SizedBox(
height: 14.rh(context),
),
GestureDetector(
onTap: () async {
File? file = await pickFile();
if (file != null) {
MultipartFile multipartFile =
await MultipartFile.fromFile(file.path);
/// Add data to static Map
AbstractField.fieldsData
.addAll({parameters['id']: multipartFile});
}
},
child: DottedBorder(
borderType: BorderType.RRect,
radius: const Radius.circular(10),
color: context.color.textLightColor,
strokeCap: StrokeCap.round,
padding: const EdgeInsets.all(5),
dashPattern: const [3, 3],
child: Container(
width: double.infinity,
height: 43,
decoration:
BoxDecoration(borderRadius: BorderRadius.circular(10)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.add),
const SizedBox(
width: 5,
),
const Text("Add File")
.color(context.color.textLightColor)
.size(context.font.large)
],
),
)),
),
ValueListenableBuilder(
valueListenable: picked,
builder: (context, String? pickedFilePath, c) {
if (pickedFilePath == null) {
return const SizedBox.shrink();
}
return Container(
child: Row(
children: [
Icon(
IconData(
d.iconSetMap[".${pickedFilePath.split(".").last}"]!
.codePoint,
fontFamily: 'Seti',
fontPackage: 'file_icon',
),
color: context.color.tertiaryColor,
size: 35,
),
const SizedBox(
width: 5,
),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(pickedFilePath.split("/").last)
.setMaxLines(lines: 1)
.bold(weight: FontWeight.w500),
if (!(pickedFilePath.startsWith("http") ||
pickedFilePath.startsWith("https")))
Text(HelperUtils.getFileSizeString(
bytes: File(pickedFilePath).lengthSync(),
).toUpperCase())
.size(context.font.smaller)
],
)),
const Spacer(flex: 1),
IconButton(
onPressed: () {
AbstractField.fieldsData.remove(parameters['id']);
picked.value = null;
},
icon: Icon(Icons.close))
],
),
);
})
],
);
// return MaterialButton(
// onPressed: () async {
// File? file = await pickFile();
// if (file != null) {
// MultipartFile multipartFile = await MultipartFile.fromFile(file.path);
// /// Add data to static Map
// AbstractField.fieldsData.addAll({parameters['id']: multipartFile});
// }
// },
// color: Colors.grey.shade200,
// child: const Text("Pick"),
// );
}
}
///Factory class which will return class according to type
class FieldFactory {
static AbstractField getField(BuildContext context, String fieldType) {
if (fieldType == 'textbox') {
return AbstractTextField(context);
} else if (fieldType == 'dropdown') {
return AbstractDropdown(context);
} else if (fieldType == 'radiobutton') {
return AbstractRadioButton(context);
} else if (fieldType == 'number') {
return AbstractNumberField(
context,
);
} else if (fieldType == "checkbox") {
return AbstractCheckBoxButton(context);
} else if (fieldType == "textarea") {
return AbstractTextAreaField(context);
} else if (fieldType == "file") {
return AbstractPickFileButton(context);
}
throw Exception('Invalid field type: $fieldType');
}
}
class CustomRadioButtonWidget extends StatefulWidget {
final dynamic parameters;
final dynamic radioValues;
const CustomRadioButtonWidget({super.key, this.parameters, this.radioValues});
@override
State<CustomRadioButtonWidget> createState() =>
_CustomRadioButtonWidgetState();
}
class _CustomRadioButtonWidgetState extends State<CustomRadioButtonWidget> {
late ValueNotifier selectedRadio;
bool isInitialized = false;
@override
void initState() {
selectedRadio = ValueNotifier(widget.radioValues?.first);
if (widget.parameters['value'] != null && isInitialized == false) {
selectedRadio.value = widget.parameters['value'];
isInitialized = true;
}
super.initState();
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: selectedRadio,
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(widget.parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(widget.parameters['name'])
.size(context.font.large)
.bold(weight: FontWeight.w500)
.color(context.color.textColorDark)
],
),
SizedBox(
height: 14.rh(context),
),
Wrap(
alignment: WrapAlignment.start,
runAlignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
children:
List.generate(widget.radioValues?.length ?? 0, (index) {
return Padding(
padding: EdgeInsetsDirectional.only(
start: index == 0 ? 0 : 4,
end: 4,
bottom: 4,
top: 4,
),
child: InkWell(
borderRadius: BorderRadius.circular(10),
onTap: () {
selectedRadio.value = widget.radioValues?[index];
AbstractField.fieldsData.addAll({
widget.parameters['id']: widget.radioValues?[index]
});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: context.color.borderColor, width: 1.5),
color: selectedRadio.value ==
widget.radioValues?[index]
? context.color.tertiaryColor.withOpacity(0.1)
: context.color.secondaryColor,
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 15),
child: Text(widget.radioValues?[index]).color(
selectedRadio.value ==
widget.radioValues?[index]
? context.color.tertiaryColor
: context.color.textLightColor)),
),
),
);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Radio(
value: widget.radioValues?[index],
groupValue: value,
fillColor: MaterialStatePropertyAll(
context.color.tertiaryColor),
onChanged: (dynamic e) {
selectedRadio.value = e;
AbstractField.fieldsData
.addAll({widget.parameters['id']: e});
},
),
Text(widget.radioValues?[index])
],
);
}))
],
);
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(parameters['name']),
// Wrap(
// children: _radioValues
// ?.map((item) {
// return Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(item),
// Radio(
// value: item,
// groupValue: value,
// onChanged: (dynamic e) {
// selectedRadio.value = e;
// AbstractField.fieldsData
// .addAll({parameters['id']: e});
// }),
// ],
// );
// })
// .toList()
// .cast() ??
// [],
// ),
// ],
// );
});
}
}
class CustomCheckBox extends StatefulWidget {
final dynamic parameters;
final dynamic checkValues;
final dynamic initComplete;
final dynamic index;
const CustomCheckBox(
{super.key,
this.parameters,
this.checkValues,
this.initComplete,
this.index});
@override
State<CustomCheckBox> createState() => _CustomCheckBoxState();
}
class _CustomCheckBoxState extends State<CustomCheckBox> {
final ValueNotifier<List> checked = ValueNotifier([]);
@override
void initState() {
// log("VA ${widget.parameters}");
if (widget.parameters.containsKey("value")) {
List<String> valueList = widget.parameters['value'].toString().split(",");
if (valueList.isNotEmpty) {
checked.value.addAll(valueList);
// checked.value.add(widget.checkValues?[widget.index]);
var entries = checked.value.asMap().entries;
Map<int, dynamic> data = Map.fromEntries(entries);
Map<String, dynamic> stringedData = data.map((key, value) {
return MapEntry(key.toString(), value);
});
AbstractField.fieldsData
.addAll({widget.parameters['id']: json.encode(stringedData)});
}
}
super.initState();
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: checked,
builder: (context, List value, Widget? c) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(10),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(widget.parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(context),
),
Text(widget.parameters['name'])
.size(context.font.large)
.bold(weight: FontWeight.w500)
.color(context.color.textColorDark)
],
),
SizedBox(
height: 14.rh(context),
),
Wrap(
alignment: WrapAlignment.start,
runAlignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
children: List.generate(
widget.checkValues?.length ?? 0,
(index) {
//this variable will prevent adding when state change
///this will work like init state text
if (widget.initComplete == false &&
(!kDoNotReBuildThese.contains(widget.parameters['id']))) {
kDoNotReBuildThese.add(widget.parameters['id']);
// widget.initComplete = true;
}
return Padding(
padding: EdgeInsetsDirectional.only(
start: index == 0 ? 0 : 4, bottom: 4, top: 4, end: 4),
child: InkWell(
borderRadius: BorderRadius.circular(10),
onTap: () {
if (checked.value
.contains(widget.checkValues?[index])) {
checked.value.remove(widget.checkValues?[index]);
// ignore: invalid_use_of_protected_member
checked.notifyListeners();
} else {
checked.value.add(widget.checkValues?[index]);
// ignore: invalid_use_of_protected_member
checked.notifyListeners();
}
var entries = checked.value.asMap().entries;
Map<int, dynamic> data = Map.fromEntries(entries);
Map<String, dynamic> temp = {};
data.forEach((key, value) {
temp[key.toString()] = value;
});
AbstractField.fieldsData.addAll(
{widget.parameters['id']: json.encode(temp)});
},
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: context.color.borderColor, width: 1.5),
color: value.contains(widget.checkValues?[index])
? context.color.tertiaryColor.withOpacity(0.1)
: context.color.secondaryColor,
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 14),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
value.contains(widget.checkValues?[index])
? Icons.done
: Icons.add,
color:
value.contains(widget.checkValues?[index])
? context.color.tertiaryColor
: context.color.textColorDark,
),
const SizedBox(
width: 5,
),
Text(widget.checkValues?[index]).color(
value.contains(widget.checkValues?[index])
? context.color.tertiaryColor
: context.color.textLightColor)
],
),
),
),
),
);
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(
fillColor: MaterialStatePropertyAll(
context.color.tertiaryColor),
value: value.contains(widget.checkValues?[index]),
onChanged: (v) {
if (checked.value
.contains(widget.checkValues?[index])) {
checked.value.remove(widget.checkValues?[index]);
// ignore: invalid_use_of_protected_member
checked.notifyListeners();
} else {
checked.value.add(widget.checkValues?[index]);
// ignore: invalid_use_of_protected_member
checked.notifyListeners();
}
var entries = checked.value.asMap().entries;
Map<int, dynamic> data = Map.fromEntries(entries);
Map<String, dynamic> temp = {};
data.forEach((key, value) {
temp[key.toString()] = value;
});
AbstractField.fieldsData.addAll(
{widget.parameters['id']: json.encode(temp)});
},
),
Text(widget.checkValues?[index])
],
);
},
),
)
],
);
},
);
}
}
class CustomTextFieldDynamic extends StatefulWidget {
final String? value;
final bool initController;
final dynamic id;
final String hintText;
final TextInputType? keyboardType;
final TextInputAction? action;
final List<TextInputFormatter>? formaters;
const CustomTextFieldDynamic({
Key? key,
required this.initController,
required this.value,
this.id,
required this.hintText,
this.keyboardType,
this.action,
this.formaters,
}) : super(key: key);
@override
State<CustomTextFieldDynamic> createState() => CustomTextFieldDynamicState();
}
class CustomTextFieldDynamicState extends State<CustomTextFieldDynamic> {
TextEditingController? _controller;
@override
void initState() {
if (widget.initController) {
_controller = TextEditingController(text: widget.value);
}
super.initState();
}
@override
Widget build(BuildContext context) {
return CustomTextFormField(
hintText: widget.hintText,
action: widget.action,
formaters: widget.formaters,
validator: CustomTextFieldValidator.nullCheck,
keyboard: widget.keyboardType,
controller: _controller,
onChange: (value) {
AbstractField.fieldsData.addAll({widget.id: value});
},
);
}
}
class CustomDropdownState extends StatefulWidget {
final ValueNotifier dropDownItemChange;
final Map parameters;
final List items;
CustomDropdownState(
{Key? key,
required this.dropDownItemChange,
required this.parameters,
required this.items})
: super(key: key);
@override
State<CustomDropdownState> createState() => _CustomDropdownStateState();
}
class _CustomDropdownStateState extends State<CustomDropdownState>
with AutomaticKeepAliveClientMixin {
List<DropdownMenuItem<Object>>? wid = [];
@override
void initState() {
wid = widget.items
.map((e) => DropdownMenuItem(
value: e,
child: Text(
e,
),
))
.toList();
super.initState();
}
@override
Widget build(BuildContext context) {
super.build(context);
return ValueListenableBuilder(
valueListenable: widget.dropDownItemChange,
builder: (context, value, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 48.rw(context),
height: 48.rh(context),
decoration: BoxDecoration(
color: context.color.tertiaryColor.withOpacity(
0.1,
),
borderRadius: BorderRadius.circular(
10,
),
),
child: Container(
height: 24,
width: 24,
child: FittedBox(
fit: BoxFit.none,
child: UiUtils.imageType(widget.parameters['image'],
color: Constant.adaptThemeColorSvg
? context.color.tertiaryColor
: null,
width: 24,
height: 24,
fit: BoxFit.cover),
),
),
),
SizedBox(
width: 10.rw(
context,
),
),
Text(
widget.parameters['name'],
)
.size(
context.font.large,
)
.bold(weight: FontWeight.w500)
.color(
context.color.textColorDark,
)
],
),
SizedBox(
height: 14.rh(context),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 0,
),
child: Container(
decoration: BoxDecoration(
color: context.color.secondaryColor,
borderRadius: BorderRadius.circular(
10,
),
border: Border.all(
width: 1.5,
color: context.color.borderColor,
)),
child: Padding(
padding: const EdgeInsets.all(
8.0,
),
child: SizedBox(
width: double.infinity,
child: DropdownButton(
value: value,
dropdownColor: context.color.secondaryColor,
isExpanded: true,
padding: const EdgeInsets.symmetric(vertical: 5),
icon: SvgPicture.asset(AppIcons.downArrow),
isDense: true,
borderRadius: BorderRadius.circular(
10,
),
style: TextStyle(
color: context.color.textLightColor,
fontSize: context.font.large),
underline: const SizedBox.shrink(),
items: wid,
onChanged: (dynamic v) {
widget.dropDownItemChange.value = v;
AbstractField.fieldsData.addAll(
{
widget.parameters['id']: v,
},
);
},
),
),
),
),
),
],
);
});
}
@override
bool get wantKeepAlive => true;
}