import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:image_picker/image_picker.dart'; import 'package:inventree/l10.dart'; import 'dart:async'; import 'dart:io'; import 'package:one_context/one_context.dart'; class FilePickerDialog { static Future pickImageFromCamera() async { final picker = ImagePicker(); final pickedImage = await picker.pickImage(source: ImageSource.camera); if (pickedImage != null) { return File(pickedImage.path); } return null; } static Future pickImageFromGallery() async { final picker = ImagePicker(); final pickedImage = await picker.pickImage(source: ImageSource.gallery); if (pickedImage != null) { return File(pickedImage.path); } return null; } static Future pickFileFromDevice() async { final FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result != null) { String? path = result.files.single.path; if (path != null) { return File(path); } return null; } } // Present a dialog to pick a file, either from local file system or from camera static Future pickFile({bool allowImages = true, bool allowFiles = true, Function(File)? onPicked}) async { String title = ""; if (allowImages && !allowFiles) { title = L10().selectImage; } else { title = L10().selectFile; } // Construct actions List actions = []; actions.add( SimpleDialogOption( child: ListTile( leading: FaIcon(FontAwesomeIcons.fileUpload), title: Text(allowFiles ? L10().selectFile : L10().selectImage), ), onPressed: () async { // Close the dialog OneContext().popDialog(); File? file; if (allowFiles) { file = await pickFileFromDevice(); } else { file = await pickImageFromGallery(); } if (file != null) { if (onPicked != null) { onPicked(file); } } }, ) ); if (allowImages) { actions.add( SimpleDialogOption( child: ListTile( leading: FaIcon(FontAwesomeIcons.camera), title: Text(L10().takePicture), ), onPressed: () async { // Close the dialog OneContext().popDialog(); File? file = await pickImageFromCamera(); if (file != null) { if (onPicked != null) { onPicked(file); } } } ) ); } OneContext().showDialog( builder: (context) { return SimpleDialog( title: Text(title), children: actions, ); } ); } } /* * Form field for selecting an image file, * either from the gallery, or from the camera. */ class ImagePickerField extends FormField { static void _selectFromGallery(FormFieldState field) { _getImageFromGallery(field); } static void _selectFromCamera(FormFieldState field) { _getImageFromCamera(field); } static Future _getImageFromGallery(FormFieldState field) async { final picker = ImagePicker(); final pickedImage = await picker.getImage(source: ImageSource.gallery); if (pickedImage != null) { field.didChange(File(pickedImage.path)); } } static Future _getImageFromCamera(FormFieldState field) async { final picker = ImagePicker(); final pickedImage = await picker.getImage(source: ImageSource.camera); if (pickedImage != null) { field.didChange(File(pickedImage.path)); } } ImagePickerField(BuildContext context, {String? label, Function(File?)? onSaved, bool required = false}) : super( onSaved: onSaved, validator: (File? img) { if (required && (img == null)) { return L10().required; } return null; }, builder: (FormFieldState state) { String _label = label ?? L10().attachImage; return InputDecorator( decoration: InputDecoration( errorText: state.errorText, labelText: required ? _label + "*" : _label, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ TextButton( child: Text(L10().selectImage), onPressed: () { _selectFromGallery(state); }, ), TextButton( child: Text(L10().takePicture), onPressed: () { _selectFromCamera(state); }, ) ], ), ); } ); } class CheckBoxField extends FormField { CheckBoxField({ String? label, bool initial = false, Function(bool?)? onSaved, TextStyle? labelStyle, String? helperText, TextStyle? helperStyle, }) : super( onSaved: onSaved, initialValue: initial, builder: (FormFieldState state) { return CheckboxListTile( //dense: state.hasError, title: label != null ? Text(label, style: labelStyle) : null, value: state.value, onChanged: state.didChange, subtitle: helperText != null ? Text(helperText, style: helperStyle) : null, contentPadding: EdgeInsets.zero, ); } ); } class StringField extends TextFormField { StringField({String label = "", String? hint, String? initial, Function(String?)? onSaved, Function? validator, bool allowEmpty = false, bool isEnabled = true}) : super( decoration: InputDecoration( labelText: allowEmpty ? label : label + "*", hintText: hint ), initialValue: initial, onSaved: onSaved, enabled: isEnabled, validator: (value) { if (!allowEmpty && value != null && value.isEmpty) { return L10().valueCannotBeEmpty; } if (validator != null) { return validator(value); } return null; } ); } /* * Helper class for quantity values */ class QuantityField extends TextFormField { QuantityField({String label = "", String hint = "", String initial = "", double? max, TextEditingController? controller}) : super( decoration: InputDecoration( labelText: label, hintText: hint, ), controller: controller, keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), validator: (value) { if (value != null && value.isEmpty) return L10().quantityEmpty; double quantity = double.tryParse(value.toString()) ?? 0; if (quantity <= 0) return L10().quantityPositive; if ((max != null) && (quantity > max)) return "Quantity must not exceed ${max}"; return null; }, ); }