2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-07-01 11:20:41 +00:00
Files
inventree-app/lib/widget/fields.dart
Ben Hagen 4444884afa Format Code and Add Format Checks to CI (#643)
* Remove unused lib/generated/i18n.dart

* Use `fvm dart format .`

* Add contributing guidelines

* Enforce dart format

* Add `dart format off` directive to generated files
2025-06-24 09:55:01 +10:00

218 lines
5.3 KiB
Dart

import "dart:async";
import "dart:io";
import "package:file_picker/file_picker.dart";
import "package:flutter/material.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:image_picker/image_picker.dart";
import "package:one_context/one_context.dart";
import "package:inventree/l10.dart";
class FilePickerDialog {
static Future<File?> pickImageFromCamera() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(source: ImageSource.camera);
if (pickedImage != null) {
return File(pickedImage.path);
}
return null;
}
static Future<File?> pickImageFromGallery() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
return File(pickedImage.path);
}
return null;
}
static Future<File?> 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<void> pickFile({
String message = "",
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<Widget> actions = [];
if (message.isNotEmpty) {
actions.add(ListTile(title: Text(message)));
}
actions.add(
SimpleDialogOption(
child: ListTile(
leading: Icon(TablerIcons.arrow_up),
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: Icon(TablerIcons.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);
},
);
}
}
class CheckBoxField extends FormField<bool> {
CheckBoxField({
String? label,
bool? initial = false,
bool tristate = false,
Function(bool?)? onSaved,
TextStyle? labelStyle,
String? helperText,
TextStyle? helperStyle,
}) : super(
onSaved: onSaved,
initialValue: initial,
builder: (FormFieldState<bool> state) {
return CheckboxListTile(
title: label != null ? Text(label, style: labelStyle) : null,
value: state.value,
tristate: tristate,
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(String?)? 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) as String?;
}
return null;
},
);
}
/*
* Helper class for quantity values
*/
class QuantityField extends TextFormField {
QuantityField({
String label = "",
String hint = "",
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;
},
);
}