// ignore_for_file: deprecated_member_use, invalid_use_of_visible_for_testing_member import 'dart:io'; import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:cssd/config/colors.dart'; import 'package:cssd/providers/input.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image_picker_gallery_camera/image_picker_gallery_camera.dart'; import 'package:multiselect_formfield/multiselect_formfield.dart'; import 'package:provider/provider.dart'; import '../../../providers/test_results.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 { List formItems = []; DateTime selectedDate = DateTime.now(); int? rangeValue; String? selectValue; _FormCreatorState(form); 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() { var items = Provider.of(context).inputItems; List listWidgets = []; formItems = items; for (var count = 0; count < formItems.length; count++) { Map item = formItems[count]; if (item['type'] == "Date") { selectedDate = formItems[count]['value']; listWidgets.add( Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: OutlinedButton( onPressed: () { _selectDate().then((_) { formItems[count]['value'] = selectedDate; _handleChanged(); }); }, child: Text( 'Date: ${selectedDate.year}/${selectedDate.month}/${selectedDate.day}'), ), ), ); } if (item['type'] == 'Image') { final testProviderObject = Provider.of(context); final mediaData = MediaQuery.of(context); final deviceWidth = mediaData.size.width; final _deviceBlockSize = deviceWidth / 100; listWidgets.insert( 3, Container( // height: 70, child: Directionality( textDirection: TextDirection.rtl, child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( margin: EdgeInsets.only(top: 20), height: testProviderObject.catchImages.length != 0 ? 60 : 0, child: ImageBox( deviceBlockSize: _deviceBlockSize, testProvider: testProviderObject, ), ), SizedBox( height: testProviderObject.catchImages.length != 0 ? 10 : 0, ), InkWell( onTap: () async { await loadAssetsFromFilePicker(context); }, child: Container( width: MediaQuery.of(context).size.width - 40, padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: Colors.black, ), child: Text( '+ Add an image or file from device', textDirection: TextDirection.ltr, style: TextStyle(color: Colors.white), textAlign: TextAlign.center, ), ), ), SizedBox( height: 10, ), InkWell( onTap: () async { await loadAssetsFromCamera(context); // await captureImage(context); }, child: Container( width: MediaQuery.of(context).size.width - 40, padding: EdgeInsets.symmetric(vertical: 10, horizontal: 30), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), color: Colors.black, ), child: Text( '+ Add an image from camera', textDirection: TextDirection.ltr, style: TextStyle(color: Colors.white), textAlign: TextAlign.center, ), ), ), ], ), ), ), ); } 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" && item['name'] != null) { // print(item['require_scanner'].toString()); TextEditingController idCTRL = new TextEditingController(); final _media = MediaQuery.of(context); // final double _pixelRatio = (_media.size.height / _media.size.width * 7 / 5); final double _devicewidth = _media.size.width; final double _deviceBlockSize = _devicewidth / 100; listWidgets.add( Padding( padding: const EdgeInsets.all(8.0), child: item['require_scanner'].toString() != '1' ? TextFormField( controller: idCTRL, decoration: InputDecoration( labelText: item['name'] ?? "", border: UnderlineInputBorder(), contentPadding: EdgeInsets.all(0), ), // initialValue: item['value'] ?? '', onChanged: (String value) { formItems[count]['value'] = value; _handleChanged(); }, ) : Container( child: Row( children: [ Flexible( flex: 8, child: TextFormField( controller: idCTRL, decoration: InputDecoration( labelText: item['name'] ?? "", border: UnderlineInputBorder(), contentPadding: EdgeInsets.all(0), ), // initialValue: item['value'] ?? '', onChanged: (String value) { formItems[count]['value'] = value; _handleChanged(); }, ), ), Flexible( flex: 1, child: InkWell( onTap: () { scan().then( (String result) { if (result == 'cancel') { print('cancel'); } else if (result == 'error') { print('error'); } else if (result == 'access') { print('access'); } else { print(result); idCTRL.text = result; formItems[count]['value'] = result; _handleChanged(); // Navigator.of(context).pushNamed( // CycleDetailScreen.route, // arguments: result, // ); } }, ); }, child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.black, ), child: Icon( Icons.qr_code_scanner, size: 5 * _deviceBlockSize, color: Colors.white, ), ), ), ), ], ), ), ), ); } if (item['type'] == "Form") { List formWidget = []; formWidget.add(Text( item['name'], style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0), )); var children = item['children'] as List; for (var index = 0; index < children.length; index++) { Map child = children[index]; if (child['type'] == "Time") { formWidget.add( Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( inputFormatters: [ LengthLimitingTextInputFormatter(5), FilteringTextInputFormatter.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: child['name'] ?? "", border: UnderlineInputBorder(), contentPadding: EdgeInsets.all(0), ), // initialValue: item['value'] ?? '', onChanged: (String value) { children[index]['value'] = value; _handleChanged(); }, ), ), ); } if (child['type'] == "Range" || child['type'] == "Temperature" || child['type'] == "Pressure") { double startValue, endValue; if (child['type'] == "Range") { startValue = double.parse(child['options'][0]['title']); endValue = double.parse(child['options'][1]['title']); } else { startValue = child['type'] == "Temperature" ? 0.0 : -1.0; endValue = child['type'] == "Temperature" ? 200.0 : 3.0; } children[index]['value'] = children[index]['value'] ?? startValue; // int divisions = (endValue - startValue).round(); formWidget.add( Padding( padding: EdgeInsets.only(top: 35, left: 10, right: 10), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(child['type']), Text(children[index]['value'].toString()), ], ), Slider( min: startValue, max: endValue, value: children[index]['value'], // label: '${formItems[count]['value'].round()}', // divisions: divisions, onChanged: (double value) { setState(() { children[index]['value'] = double.parse(value.toStringAsFixed(2)); }); // print(formItems[count]['value']); }, // semanticFormatterCallback: (double newValue) { // return '${newValue.round()}'; // }, ), ], ), ), ); } } listWidgets.add(Container( margin: EdgeInsets.only(top: 10), decoration: BoxDecoration(border: Border.all(color: Colors.grey)), child: ListView.builder( padding: EdgeInsets.all(widget.padding ?? 6.0), itemCount: formWidget.length, itemBuilder: (context, index) { return formWidget[index]; }, shrinkWrap: true, controller: ScrollController(keepScrollOffset: false), ), )); } 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, left: 10, right: 10), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(item['type']), Text(formItems[count]['value'].toString()), ], ), Slider( min: startValue, max: endValue, value: formItems[count]['value'], // label: '${formItems[count]['value'].round()}', // divisions: divisions, onChanged: (double value) { setState(() { formItems[count]['value'] = double.parse(value.toStringAsFixed(2)); }); // print(formItems[count]['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), FilteringTextInputFormatter.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: AutovalidateMode.disabled, title: Text(item['name']), dataSource: listItems, textField: 'title', valueField: 'id', okButtonLabel: 'OK', cancelButtonLabel: 'CANCEL', errorText: 'Please choose one or more', validator: (value) { if (value == null || value.isEmpty) { return 'Please choose one or more options.'; } return null; // Return null if validation succeeds }, 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: kBlue, inactiveTrackColor: kPink.withAlpha(150), inactiveThumbColor: kPink, title: Text(item['name']), value: item['value'] ?? false, onChanged: (bool value) { this.setState(() { formItems[count]['value'] = value; _handleChanged(); }); }, ), ); } // if (item['type'] == "Form") { // List children = item['children']; // print(children); // 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), // ), // ), // Container( // height: 200, // width: double.infinity, // child: 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; } Future captureImage(BuildContext context) async { var profileProviderObject = Provider.of(context, listen: false); List files = profileProviderObject.catchImages; try { files.add( await ImagePickerGC.pickImage( context: context, source: ImgSource.Camera, cameraIcon: Icon( Icons.camera_alt, color: Colors.red, ), //cameraIcon and galleryIcon can change. If no icon provided default icon will be present cameraText: Text( "From Camera", style: TextStyle(color: Colors.red), ), ), ); } catch (e) {} profileProviderObject.setCatchImages(files); profileProviderObject.setImages(); } Future loadAssetsFromFilePicker(BuildContext context) async { var providerObject = Provider.of(context, listen: false); List files = providerObject.catchImages; var image = await ImagePicker.platform.pickImage( source: ImageSource.gallery, imageQuality: 25, maxHeight: 1080, maxWidth: 1920, ); print('Picked image size (bytes) in test: ${await image?.path.length}'); if (image != null) { files.add( PlatformFile( path: image.path, name: "item_image", bytes: File(image.path).readAsBytesSync(), size: File(image.path).lengthSync(), ), ); providerObject.setCatchImages(files); providerObject.setImages(); } } Future loadAssetsFromCamera(BuildContext context) async { var providerObject = Provider.of(context, listen: false); List _catchImages = providerObject.catchImages; var image = await ImagePicker.platform.pickImage( source: ImageSource.camera, imageQuality: 25, maxHeight: 1080, maxWidth: 1920, ); if (image != null) { _catchImages.add( PlatformFile( path: image.path, name: "item_image", bytes: File(image.path).readAsBytesSync(), size: File(image.path).lengthSync(), ), ); providerObject.setCatchImages(_catchImages); providerObject.setImages(); } } // _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), ); } } class ImageBox extends StatelessWidget { const ImageBox({ Key? key, required double deviceBlockSize, required TestResultsProvider testProvider, }) : _deviceBlockSize = deviceBlockSize, _testProvider = testProvider, super(key: key); final double _deviceBlockSize; final TestResultsProvider _testProvider; @override Widget build(BuildContext context) { return ListView.separated( shrinkWrap: true, scrollDirection: Axis.horizontal, itemBuilder: (ctx, index) { bool isPdf = _testProvider.catchImages[index].path!.endsWith('pdf'); bool isWord = _testProvider.catchImages[index].path!.endsWith('docx') || _testProvider.catchImages[index].path!.endsWith('doc'); // print(_testProvider.catchImages[index].path.endsWith('jpg')); // .substring(_testProvider.catchImages[index].path.length - 4)); return ClipRRect( borderRadius: BorderRadius.circular(5), child: Container( width: 60, height: 60, child: Stack( children: [ Positioned( top: 10, left: 0, child: GestureDetector( onTap: () => isPdf ? print('pdf') : isWord ? print('word') : Navigator.of(context).push( MaterialPageRoute( builder: (_) => Container( color: Colors.white, child: Center( child: Image.memory( _testProvider.catchImages[index].bytes!, fit: BoxFit.contain, ), ), ), ), ), child: isPdf ? Image.asset( 'assets/Images/pdf.png', width: 60, height: 60, fit: BoxFit.fill, ) : isWord ? Image.asset( 'assets/Images/word.png', width: 60, height: 60, fit: BoxFit.fill, ) : Image.memory( _testProvider.catchImages[index].bytes!, // asset: _images[index], width: 60, height: 60, fit: BoxFit.contain, ), ), ), Positioned( top: 0, right: 0, child: GestureDetector( onTap: () { // setState(() { _testProvider.removeImage(index); // }); }, child: CircleAvatar( backgroundColor: Colors.red, radius: 10, child: Icon( Icons.close, size: 12, color: Colors.white, ), ), ), ) ], ), ), ); }, itemCount: _testProvider.catchImages.length, separatorBuilder: (BuildContext context, int index) => SizedBox( width: 3 * _deviceBlockSize, ), ); } } Future scan() async { try { var barcode = await BarcodeScanner.scan(); if (barcode.type.name == 'Cancelled') { return 'cancel'; } else if (barcode.type.name == 'Failed') { return 'error'; } try { var id = barcode.rawContent.contains('www.cssd-doc.com') ? barcode.rawContent.split('/')[5] : barcode.rawContent; return id; } catch (_) { return 'null'; } } on PlatformException catch (_) { return 'access'; } catch (_) { return 'error'; } }