import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:meta/meta.dart'; import 'package:multiselect_formfield/multiselect_formfield.dart'; class FormCreator extends StatefulWidget { const FormCreator({ @required this.form, @required this.onChanged, this.padding, }); final dynamic form; final double padding; final ValueChanged onChanged; @override _FormCreatorState createState() => _FormCreatorState(form); } class _FormCreatorState extends State { final dynamic formItems; DateTime selectedDate = DateTime.now(); int rangeValue; String selectValue; Future _selectDate() async { final DateTime picked = await showDatePicker( context: context, initialDate: selectedDate, firstDate: DateTime(2015, 8), lastDate: DateTime(2101)); if (picked != null && picked != selectedDate) setState(() { selectedDate = picked; }); } List jsonToForm() { List listWidgets = List(); for (var count = 0; count < formItems.length; count++) { Map item = formItems[count]; if (item['type'] == "Date") { selectedDate = formItems[count]['value']; listWidgets.add( OutlineButton( onPressed: () { _selectDate().then((_) { formItems[count]['value'] = selectedDate; _handleChanged(); }); }, child: Text( 'Date: ${selectedDate.year}/${selectedDate.month}/${selectedDate.day}'), padding: EdgeInsets.symmetric(vertical: 20), ), ); } if (item['type'] == "Label") { listWidgets.add( Container( decoration: BoxDecoration( border: Border.all(), borderRadius: BorderRadius.circular(30), color: Colors.black, ), padding: EdgeInsets.only(top: 20, bottom: 20), margin: EdgeInsets.only(bottom: 20), child: Text( item['name'], textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 20), ), ), ); } if (item['type'] == "Text") { listWidgets.add( Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( decoration: InputDecoration( labelText: item['name'] ?? "", border: UnderlineInputBorder(), contentPadding: EdgeInsets.all(0), ), initialValue: item['value'] ?? '', onChanged: (String value) { formItems[count]['value'] = value; _handleChanged(); }, ), ), ); } if (item['type'] == "Range" || item['type'] == "Temperature" || item['type'] == "Pressure") { double startValue, endValue; if (item['type'] == "Range") { startValue = double.parse(item['options'][0]['title']); endValue = double.parse(item['options'][1]['title']); } else { startValue = item['type'] == "Temperature" ? 0.0 : -1.0; endValue = item['type'] == "Temperature" ? 200.0 : 3.0; } formItems[count]['value'] = formItems[count]['value'] ?? startValue; int divisions = (endValue - startValue).round(); listWidgets.add( Padding( padding: EdgeInsets.only(top: 35), child: Slider( min: startValue, max: endValue, value: formItems[count]['value'], label: '${formItems[count]['value'].round()}', divisions: divisions, onChanged: (double value) { setState(() { formItems[count]['value'] = value; }); }, semanticFormatterCallback: (double newValue) { return '${newValue.round()}'; }, ), ), ); } if (item['type'] == "Time") { listWidgets.add( Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( inputFormatters: [ LengthLimitingTextInputFormatter(5), WhitelistingTextInputFormatter.digitsOnly, // BlacklistingTextInputFormatter.singleLineFormatter, TextInputFormatter.withFunction( (TextEditingValue oldValue, TextEditingValue newValue) { final int newTextLength = newValue.text.length; int selectionIndex = newValue.selection.end; int usedSubstringIndex = 0; final StringBuffer newText = StringBuffer(); if (newTextLength >= 2) { newText.write( newValue.text.substring(0, usedSubstringIndex = 2) + ':'); if (newValue.selection.end >= 2) selectionIndex++; } // Dump the rest. if (newTextLength >= usedSubstringIndex) newText.write(newValue.text.substring(usedSubstringIndex)); return TextEditingValue( text: newText.toString(), selection: TextSelection.collapsed(offset: selectionIndex), ); }) ], keyboardType: TextInputType.datetime, decoration: InputDecoration( labelText: item['name'] ?? "", border: UnderlineInputBorder(), contentPadding: EdgeInsets.all(0), ), initialValue: item['value'] ?? '', onChanged: (String value) { formItems[count]['value'] = value; _handleChanged(); }, ), ), ); } if (item['type'] == "Select") { var listItems = item['options'] as List; listWidgets.add(MultiSelectFormField( autovalidate: false, titleText: item['name'], dataSource: listItems, textField: 'title', valueField: 'id', okButtonLabel: 'OK', cancelButtonLabel: 'CANCEL', hintText: 'Please choose one or more', value: item['value'], onSaved: (value) { if (value == null) return; setState(() { item['value'] = value; }); _handleChanged(); }, )); // listWidgets.add( // DropdownButtonFormField( // items: listItems.map((dynamic value) { // String stringValue = value['id'].toString(); // String textValue = value['title'].toString(); // return DropdownMenuItem( // value: stringValue, // child: Text(textValue), // ); // }).toList(), // isDense: true, // value: item['value'], // hint: Text(item['name']), // onChanged: (String value) { // this.setState( // () { // _setInput(item['name'], value); // formItems[count]['value'] = value; // _handleChanged(); // }, // ); // }, // ), // ); } if (item['type'] == "Radiobutton") { listWidgets.add( Container( margin: EdgeInsets.only(top: 14.0, bottom: 0), child: Text( item['name'], style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), ), ), ); var valueOrFirst = formItems[count]['value'] ?? formItems[count]['options'][0]['id']; for (var i = 0; i < item['options'].length; i++) { var isSelected = formItems[count]['options'][i]['id'] == valueOrFirst; formItems[count]['value'] = valueOrFirst; listWidgets.add( RadioListTile( dense: true, controlAffinity: ListTileControlAffinity.trailing, title: Text(formItems[count]['options'][i]['title']), value: formItems[count]['options'][i]['id'], selected: isSelected, groupValue: formItems[count]['value'], onChanged: (int value) { this.setState( () { _setInput(item['name'], value.toString()); formItems[count]['value'] = value; _handleChanged(); }, ); }, ), ); } } if (item['type'] == "Switch") { listWidgets.add(SwitchListTile( activeColor: Colors.green, inactiveTrackColor: Colors.red.withAlpha(150), inactiveThumbColor: Colors.red, title: Text(item['name']), value: item['value'] ?? false, onChanged: (bool value) { this.setState(() { formItems[count]['value'] = value; _handleChanged(); }); })); } if (item['type'] == "Form") { listWidgets.add( Container( margin: EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration(border: Border.all()), child: Column( children: [ Container( margin: EdgeInsets.only(top: 10), child: Text( item['name'], style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), ), ), FormCreator( form: item['children'], padding: 4, onChanged: (value) { // _handleChanged(); }, ), ], ), ), ); } if (item['type'] == "Checkbox") { formItems[count]['value'] = formItems[count]['value'] ?? []; listWidgets.add( Container( margin: EdgeInsets.only(top: 14.0, bottom: 0), child: Text( item['name'], style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), ), ), ); for (var i = 0; i < item['options'].length; i++) { listWidgets.add( CheckboxListTile( title: Text(formItems[count]['options'][i]['title']), value: (formItems[count]['value'] ?? []) .contains(formItems[count]['options'][i]['id']), onChanged: (bool value) { this.setState( () { setState(() { if (value) { (formItems[count]['value'] as List) .add(formItems[count]['options'][i]['id']); } else { (formItems[count]['value'] as List) .remove(formItems[count]['options'][i]['id']); } }); _handleChanged(); }, ); }, ), ); } } // listWidgets.add( // TestResultAddSaveButton( // deviceBlockSize: null, // ), // ); } return listWidgets; } _FormCreatorState(this.formItems); void _handleChanged() { widget.onChanged(formItems); } void _setInput(String key, String value) {} @override Widget build(BuildContext context) { return ListView.builder( padding: EdgeInsets.all(widget.padding ?? 16.0), itemCount: jsonToForm().length, itemBuilder: (context, index) { return jsonToForm()[index]; }, shrinkWrap: true, controller: ScrollController(keepScrollOffset: false), ); } }