Refactor category handling in inventory and pantry forms
Test Suite / test (24.15.0) (push) Has been cancelled

- Introduced `_categorySearchController` and `_categoryOptions` in both `_InventoryFormDialogState` and `_PantryFormDialogState` to manage category selection more effectively.
- Implemented `_flattenCategoryOptions` method to create a flat list of category options from nested category nodes.
- Updated the initialization and disposal of the new controllers to ensure proper resource management.
- Made minor adjustments to the PopupMenuItem definitions in `AppShell` for consistency.
This commit is contained in:
Nils-Johan Gynther
2026-05-11 17:03:58 +02:00
parent d038d30831
commit 9b4d1f94bf
6 changed files with 84459 additions and 79916 deletions
+1 -1
View File
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"59aa584fdf100e6c78c785d8a5b565d1de4b48
_flutter.loader.load({ _flutter.loader.load({
serviceWorkerSettings: { serviceWorkerSettings: {
serviceWorkerVersion: "3795187910" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */ serviceWorkerVersion: "2742817442" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
} }
}); });
+84414 -79910
View File
File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -210,8 +210,8 @@ class AppShell extends ConsumerWidget {
break; break;
} }
}, },
itemBuilder: (context) => const [ itemBuilder: (context) => [
PopupMenuItem<String>( const PopupMenuItem<String>(
value: 'profile', value: 'profile',
child: ListTile( child: ListTile(
leading: Icon(Icons.person_outline), leading: Icon(Icons.person_outline),
@@ -220,7 +220,7 @@ class AppShell extends ConsumerWidget {
), ),
), ),
if (isAdmin) if (isAdmin)
PopupMenuItem<String>( const PopupMenuItem<String>(
value: 'admin', value: 'admin',
child: ListTile( child: ListTile(
leading: Icon(Icons.admin_panel_settings_outlined), leading: Icon(Icons.admin_panel_settings_outlined),
@@ -228,8 +228,8 @@ class AppShell extends ConsumerWidget {
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
), ),
), ),
PopupMenuDivider(), const PopupMenuDivider(),
PopupMenuItem<String>( const PopupMenuItem<String>(
value: 'logout', value: 'logout',
child: ListTile( child: ListTile(
leading: Icon(Icons.logout), leading: Icon(Icons.logout),
@@ -781,6 +781,8 @@ class _InventoryFormDialogState extends State<_InventoryFormDialog> {
late final TextEditingController _receiptNameController; late final TextEditingController _receiptNameController;
late final TextEditingController _suitableForController; late final TextEditingController _suitableForController;
late final TextEditingController _commentController; late final TextEditingController _commentController;
late final TextEditingController _categorySearchController;
late List<CategorySelectOption> _categoryOptions;
int? _ownerUserId; int? _ownerUserId;
int? _productId; int? _productId;
@@ -806,6 +808,8 @@ class _InventoryFormDialogState extends State<_InventoryFormDialog> {
_receiptNameController = TextEditingController(text: initial?.receiptName ?? ''); _receiptNameController = TextEditingController(text: initial?.receiptName ?? '');
_suitableForController = TextEditingController(text: initial?.suitableFor ?? ''); _suitableForController = TextEditingController(text: initial?.suitableFor ?? '');
_commentController = TextEditingController(text: initial?.comment ?? ''); _commentController = TextEditingController(text: initial?.comment ?? '');
_categorySearchController = TextEditingController(text: _categoryPath ?? '');
_categoryOptions = _flattenCategoryOptions(widget.categories);
} }
@override @override
@@ -817,6 +821,7 @@ class _InventoryFormDialogState extends State<_InventoryFormDialog> {
_receiptNameController.dispose(); _receiptNameController.dispose();
_suitableForController.dispose(); _suitableForController.dispose();
_commentController.dispose(); _commentController.dispose();
_categorySearchController.dispose();
super.dispose(); super.dispose();
} }
@@ -853,6 +858,20 @@ class _InventoryFormDialogState extends State<_InventoryFormDialog> {
.toList(); .toList();
} }
List<CategorySelectOption> _flattenCategoryOptions(
List<AdminCategoryNode> nodes, [
List<String> parents = const [],
]) {
final result = <CategorySelectOption>[];
for (final node in nodes) {
final pathParts = [...parents, node.name];
final path = pathParts.join(' > ');
result.add((value: node.id.toString(), label: path));
result.addAll(_flattenCategoryOptions(node.children, pathParts));
}
return result;
}
Future<void> _pickCategory() async { Future<void> _pickCategory() async {
final selected = await CategoryThenProductPicker.showCategorySheet( final selected = await CategoryThenProductPicker.showCategorySheet(
context, context,
@@ -506,6 +506,9 @@ class _PantryFormDialog extends StatefulWidget {
class _PantryFormDialogState extends State<_PantryFormDialog> { class _PantryFormDialogState extends State<_PantryFormDialog> {
late final TextEditingController _locationController; late final TextEditingController _locationController;
late final TextEditingController _categorySearchController;
late List<CategorySelectOption> _categoryOptions;
int? _ownerUserId; int? _ownerUserId;
int? _productId; int? _productId;
int? _categoryId; int? _categoryId;
@@ -522,11 +525,14 @@ class _PantryFormDialogState extends State<_PantryFormDialog> {
_categoryId = initialProduct?.categoryId; _categoryId = initialProduct?.categoryId;
_categoryPath = initialProduct?.categoryPath; _categoryPath = initialProduct?.categoryPath;
_locationController = TextEditingController(text: initial?.location ?? ''); _locationController = TextEditingController(text: initial?.location ?? '');
_categorySearchController = TextEditingController(text: _categoryPath ?? '');
_categoryOptions = _flattenCategoryOptions(widget.categories);
} }
@override @override
void dispose() { void dispose() {
_locationController.dispose(); _locationController.dispose();
_categorySearchController.dispose();
super.dispose(); super.dispose();
} }
@@ -563,6 +569,20 @@ class _PantryFormDialogState extends State<_PantryFormDialog> {
.toList(); .toList();
} }
List<CategorySelectOption> _flattenCategoryOptions(
List<AdminCategoryNode> nodes, [
List<String> parents = const [],
]) {
final result = <CategorySelectOption>[];
for (final node in nodes) {
final pathParts = [...parents, node.name];
final path = pathParts.join(' > ');
result.add((value: node.id.toString(), label: path));
result.addAll(_flattenCategoryOptions(node.children, pathParts));
}
return result;
}
Future<void> _pickCategory() async { Future<void> _pickCategory() async {
final selected = await CategoryThenProductPicker.showCategorySheet( final selected = await CategoryThenProductPicker.showCategorySheet(
context, context,