diff --git a/android/version.properties b/android/version.properties index d74f2c0..fa3b254 100644 --- a/android/version.properties +++ b/android/version.properties @@ -1,2 +1,2 @@ flutter.versionCode=5 -flutter.versionName=0.4.0 \ No newline at end of file +flutter.versionName=0.4.1 \ No newline at end of file diff --git a/lib/database/daos/basket_items_dao.dart b/lib/database/daos/basket_items_dao.dart index 2845fd7..1d817d4 100644 --- a/lib/database/daos/basket_items_dao.dart +++ b/lib/database/daos/basket_items_dao.dart @@ -21,6 +21,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao int? categoryId, required int basketId, String? imagePath, + String? note, int? unitId, }) async { final existingItems = await findBasketItemsByNameCategoryUnit(name, basketId, categoryId, unitId); @@ -38,6 +39,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao category: Value(categoryId), basket: Value(basketId), imagePath: Value(imagePath), + note: Value(note), unit: Value(unitId), amount: Value(amount), ); @@ -51,6 +53,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao int? categoryId, int? basketId, String? imagePath, + String? note, int? unitId, bool? isChecked, }) { @@ -59,6 +62,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao category: Value.absentIfNull(categoryId), basket: Value.absentIfNull(basketId), imagePath: Value.absentIfNull(imagePath), + note: Value.absentIfNull(note), unit: Value.absentIfNull(unitId), amount: Value.absentIfNull(amount), isChecked: Value.absentIfNull(isChecked), @@ -73,6 +77,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao int? categoryId, required int basketId, String? imagePath, + String? note, int? unitId, bool? isChecked, }) { @@ -82,6 +87,7 @@ class BasketItemsDao extends DatabaseAccessor with _$BasketItemsDao category: Value(categoryId), basket: Value(basketId), imagePath: Value(imagePath), + note: Value(note), unit: Value(unitId), amount: Value(amount ?? 0), isChecked: Value(isChecked ?? false), diff --git a/lib/database/daos/item_templates_dao.dart b/lib/database/daos/item_templates_dao.dart index 7a45884..8a8bfe0 100644 --- a/lib/database/daos/item_templates_dao.dart +++ b/lib/database/daos/item_templates_dao.dart @@ -19,14 +19,12 @@ class ItemTemplatesDao extends DatabaseAccessor with _$ItemTemplate String name, { int? categoryId, required int libraryId, - int? variantKeyId, String? imagePath, }) { final companion = ItemTemplatesCompanion( name: Value(name), category: Value(categoryId), library: Value(libraryId), - variantKey: Value(variantKeyId), imagePath: Value(imagePath), ); return into(itemTemplates).insert(companion); @@ -37,14 +35,12 @@ class ItemTemplatesDao extends DatabaseAccessor with _$ItemTemplate String? name, int? categoryId, int? libraryId, - int? variantKeyId, String? imagePath, }) { final companion = ItemTemplatesCompanion( name: Value.absentIfNull(name), category: Value.absentIfNull(categoryId), library: Value.absentIfNull(libraryId), - variantKey: Value.absentIfNull(variantKeyId), imagePath: Value.absentIfNull(imagePath)); return (update(itemTemplates)..where((li) => li.id.equals(id))).write(companion); } @@ -54,7 +50,6 @@ class ItemTemplatesDao extends DatabaseAccessor with _$ItemTemplate required String name, int? categoryId, required int libraryId, - int? variantKeyId, String? imagePath, }) { final newItemTemplate = ItemTemplatesCompanion( @@ -62,7 +57,6 @@ class ItemTemplatesDao extends DatabaseAccessor with _$ItemTemplate name: Value(name), category: Value(categoryId), library: Value(libraryId), - variantKey: Value(variantKeyId), imagePath: Value(imagePath), ); return update(itemTemplates).replace(newItemTemplate); @@ -77,11 +71,6 @@ class ItemTemplatesDao extends DatabaseAccessor with _$ItemTemplate return _rowToViewModel(row); } - Future> getItemTemplatesByVariantKey(int variantKeyId) async { - final rows = await _joinValues(select(itemTemplates)..where((li) => li.variantKey.equals(variantKeyId))).get(); - return _rowsToViewModels(rows); - } - Future deleteItemTemplateWithId(int id) { return (delete(itemTemplates)..where((li) => li.id.equals(id))).go(); } diff --git a/lib/database/daos/variant_keys_dao.dart b/lib/database/daos/variant_keys_dao.dart deleted file mode 100644 index 643fb15..0000000 --- a/lib/database/daos/variant_keys_dao.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:drift/drift.dart'; -import 'package:rabenkorb/database/database.dart'; -import 'package:rabenkorb/database/tables/variant_keys.dart'; - -part 'variant_keys_dao.g.dart'; - -@DriftAccessor(tables: [VariantKeys]) -class VariantKeysDao extends DatabaseAccessor with _$VariantKeysDaoMixin { - VariantKeysDao(super.db); - - Future createVariantKey(String name) { - return into(variantKeys).insert(const VariantKeysCompanion()); - } - - Future getVariantKeyWithId(int id) { - return (select(variantKeys)..where((li) => li.id.equals(id))).getSingleOrNull(); - } - - Future deleteVariantKeyWithId(int id) { - return (delete(variantKeys)..where((li) => li.id.equals(id))).go(); - } -} diff --git a/lib/database/database.dart b/lib/database/database.dart index ea73a0a..3092c6a 100644 --- a/lib/database/database.dart +++ b/lib/database/database.dart @@ -12,7 +12,6 @@ import 'package:rabenkorb/database/daos/shopping_baskets_dao.dart'; import 'package:rabenkorb/database/daos/sort_orders_dao.dart'; import 'package:rabenkorb/database/daos/sort_rules_dao.dart'; import 'package:rabenkorb/database/daos/template_libraries_dao.dart'; -import 'package:rabenkorb/database/daos/variant_keys_dao.dart'; import 'package:rabenkorb/database/tables/basket_items.dart'; import 'package:rabenkorb/database/tables/item_categories.dart'; import 'package:rabenkorb/database/tables/item_templates.dart'; @@ -21,7 +20,6 @@ import 'package:rabenkorb/database/tables/shopping_basket.dart'; import 'package:rabenkorb/database/tables/sort_orders.dart'; import 'package:rabenkorb/database/tables/sort_rules.dart'; import 'package:rabenkorb/database/tables/template_libraries.dart'; -import 'package:rabenkorb/database/tables/variant_keys.dart'; part 'database.g.dart'; @@ -35,7 +33,6 @@ part 'database.g.dart'; SortOrders, SortRules, TemplateLibraries, - VariantKeys, ], daos: [ ItemCategoriesDao, @@ -46,11 +43,11 @@ part 'database.g.dart'; SortOrdersDao, SortRulesDao, TemplateLibrariesDao, - VariantKeysDao, ], ) class AppDatabase extends _$AppDatabase { static const databaseFileName = 'db.sqlite'; + AppDatabase() : super(_openConnection()); AppDatabase.forTesting(super.e); @@ -58,12 +55,24 @@ class AppDatabase extends _$AppDatabase { AppDatabase.forImport(String path, String fileName) : super(_openImportDatabase(path, fileName)); @override - int get schemaVersion => 1; + int get schemaVersion => 2; @override - MigrationStrategy get migration => MigrationStrategy(beforeOpen: (details) async { + MigrationStrategy get migration { + return MigrationStrategy( + beforeOpen: (details) async { await customStatement('PRAGMA foreign_keys = ON'); - }); + }, + onUpgrade: (Migrator m, int from, int to) async { + if (from < 2) { + m.deleteTable("variant_keys"); + await m.addColumn(basketItems, basketItems.note); + await m.alterTable(TableMigration(basketItems)); + await m.alterTable(TableMigration(itemTemplates)); + } + }, + ); + } Future exportInto(File file) async { await file.parent.create(recursive: true); diff --git a/lib/database/tables/basket_items.dart b/lib/database/tables/basket_items.dart index 2df9ab9..c7e0234 100644 --- a/lib/database/tables/basket_items.dart +++ b/lib/database/tables/basket_items.dart @@ -12,6 +12,8 @@ class BasketItems extends Table { TextColumn get imagePath => text().nullable()(); + TextColumn get note => text().nullable()(); + RealColumn get amount => real()(); IntColumn get category => integer().nullable().references(ItemCategories, #id, onDelete: KeyAction.setNull)(); diff --git a/lib/database/tables/item_templates.dart b/lib/database/tables/item_templates.dart index 891deaa..c1c0645 100644 --- a/lib/database/tables/item_templates.dart +++ b/lib/database/tables/item_templates.dart @@ -2,7 +2,6 @@ import 'package:drift/drift.dart'; import 'package:rabenkorb/database/constants.dart'; import 'package:rabenkorb/database/tables/item_categories.dart'; import 'package:rabenkorb/database/tables/template_libraries.dart'; -import 'package:rabenkorb/database/tables/variant_keys.dart'; @DataClassName('ItemTemplate') class ItemTemplates extends Table { @@ -12,8 +11,6 @@ class ItemTemplates extends Table { TextColumn get imagePath => text().nullable()(); - IntColumn get variantKey => integer().nullable().references(VariantKeys, #id, onDelete: KeyAction.setNull)(); - IntColumn get category => integer().nullable().references(ItemCategories, #id, onDelete: KeyAction.setNull)(); IntColumn get library => integer().references(TemplateLibraries, #id, onDelete: KeyAction.cascade)(); diff --git a/lib/database/tables/variant_keys.dart b/lib/database/tables/variant_keys.dart deleted file mode 100644 index a5756be..0000000 --- a/lib/database/tables/variant_keys.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:drift/drift.dart'; - -@DataClassName('VariantKey') -class VariantKeys extends Table { - IntColumn get id => integer().autoIncrement()(); -} diff --git a/lib/di/di_setup.dart b/lib/di/di_setup.dart index fe32658..3bb1fe4 100644 --- a/lib/di/di_setup.dart +++ b/lib/di/di_setup.dart @@ -26,7 +26,6 @@ import 'package:rabenkorb/services/data_access/shopping_basket_service.dart'; import 'package:rabenkorb/services/data_access/sort_order_service.dart'; import 'package:rabenkorb/services/data_access/sort_rule_service.dart'; import 'package:rabenkorb/services/data_access/template_library_service.dart'; -import 'package:rabenkorb/services/data_access/variant_key_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; import 'package:rabenkorb/services/state/data_management_navigation_state_service.dart'; import 'package:rabenkorb/services/state/data_management_state_service.dart'; @@ -109,7 +108,6 @@ void _registerDataAccessServices() { di.registerSingleton(SortOrderService()); di.registerSingleton(SortRuleService()); di.registerSingleton(TemplateLibraryService()); - di.registerSingleton(VariantKeyService()); } void _registerBusinessServices() { @@ -172,7 +170,7 @@ Future _unregisterDataAccessServices() async { await di.unregister(); await di.unregister(); await di.unregister(); - await di.unregister(); + await di.unregister(); } Future _unregisterDatabase() async { diff --git a/lib/features/backup/backup_create.dart b/lib/features/backup/backup_create.dart index 0762610..fed8e6c 100644 --- a/lib/features/backup/backup_create.dart +++ b/lib/features/backup/backup_create.dart @@ -1,6 +1,7 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:rabenkorb/generated/l10n.dart'; +import 'package:rabenkorb/services/core/snackbar_service.dart'; import 'package:rabenkorb/services/utility/backup_service.dart'; import 'package:rabenkorb/shared/helper_functions.dart'; import 'package:rabenkorb/shared/widgets/inputs/core_primary_button.dart'; @@ -26,8 +27,18 @@ class BackupCreate extends StatelessWidget { if (exportPath == null || exportPath.trim().isEmpty) { return; } - doWithLoadingIndicator(() async { - await di().backup(exportPath); + bool exportSuccess = false; + await doWithLoadingIndicator(() async { + exportSuccess = await di().backup(exportPath); }); + + if (!context.mounted) { + return; + } + if (exportSuccess) { + di().show(context: context, text: S.of(context).BackupCreated); + return; + } + di().show(context: context, text: S.of(context).BackupCreationFailed); } } diff --git a/lib/features/backup/backup_restore_screen.dart b/lib/features/backup/backup_restore_screen.dart index e4f43a0..5e45c1d 100644 --- a/lib/features/backup/backup_restore_screen.dart +++ b/lib/features/backup/backup_restore_screen.dart @@ -1,8 +1,10 @@ import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:path/path.dart' as p; import 'package:rabenkorb/features/core/structural/core_scaffold.dart'; import 'package:rabenkorb/generated/l10n.dart'; +import 'package:rabenkorb/services/core/snackbar_service.dart'; import 'package:rabenkorb/services/utility/backup_service.dart'; import 'package:rabenkorb/shared/helper_functions.dart'; import 'package:rabenkorb/shared/widgets/constant_widgets.dart'; @@ -114,9 +116,18 @@ class _BackupRestoreScreenState extends State { if (_backupFile == null) { return; } - + bool importSuccess = false; await doWithLoadingIndicator(() async { - await di().restore(_backupFile!); + importSuccess = await di().restore(_backupFile!); }); + if (!context.mounted) { + return; + } + if (importSuccess) { + di().show(context: context, text: S.of(context).BackupImported); + context.pop(); + return; + } + di().show(context: context, text: S.of(context).BackupImportFailed); } } diff --git a/lib/features/basket/basket_item_tile.dart b/lib/features/basket/basket_item_tile.dart index 1da06e4..014d215 100644 --- a/lib/features/basket/basket_item_tile.dart +++ b/lib/features/basket/basket_item_tile.dart @@ -25,6 +25,7 @@ class BasketItemTile extends StatelessWidget { @override Widget build(BuildContext context) { + final extraWidget = _extra(); return Card( key: Key(item.key), color: item.isChecked ? Theme.of(context).colorScheme.surface.withAlpha(220) : null, @@ -38,6 +39,7 @@ class BasketItemTile extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, children: [ + if (extraWidget != null) extraWidget, if (item.imagePath.isValid()) ItemImage( imagePath: item.imagePath!, @@ -69,7 +71,7 @@ class BasketItemTile extends StatelessWidget { ); } - Widget? _subtitle() { + Widget? _amountUnit() { final unit = item.unit; final amount = item.amount; final hasAmount = amount > 0; @@ -79,4 +81,24 @@ class BasketItemTile extends StatelessWidget { final subtitle = "${hasAmount ? amount.toFormattedString() : ''} ${unit?.name ?? ''}"; return Text(subtitle.trim()); } + + Widget? _note() { + final note = item.note; + if (!note.isValid()) { + return null; + } + final subtitle = note!; + return Text( + subtitle.trim(), + style: const TextStyle(fontSize: 14), + ); + } + + Widget? _subtitle() { + return _amountUnit(); + } + + Widget? _extra() { + return _note(); + } } diff --git a/lib/features/basket/basket_popup_menu.dart b/lib/features/basket/basket_popup_menu.dart index 065f671..0cc407e 100644 --- a/lib/features/basket/basket_popup_menu.dart +++ b/lib/features/basket/basket_popup_menu.dart @@ -21,13 +21,15 @@ enum BasketPopupMenuActions { class BasketPopupMenu extends StatelessWidget with WatchItMixin { final bool isShoppingMode; final bool isMultiSelectMode; + final bool disabled; - const BasketPopupMenu({super.key, required this.isShoppingMode, required this.isMultiSelectMode}); + const BasketPopupMenu({super.key, required this.isShoppingMode, required this.isMultiSelectMode, this.disabled = false}); @override Widget build(BuildContext context) { return PopupMenuButton( key: const Key("basket-popup-menu"), + enabled: !disabled, itemBuilder: isShoppingMode ? _shoppingModeItems : isMultiSelectMode diff --git a/lib/features/basket/basket_sort_control.dart b/lib/features/basket/basket_sort_control.dart index c045ff4..20308e4 100644 --- a/lib/features/basket/basket_sort_control.dart +++ b/lib/features/basket/basket_sort_control.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:rabenkorb/generated/l10n.dart'; import 'package:rabenkorb/models/sort_rule_view_model.dart'; import 'package:rabenkorb/services/business/basket_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; import 'package:rabenkorb/shared/default_sort_rules.dart'; +import 'package:rabenkorb/shared/sort_direction.dart'; import 'package:rabenkorb/shared/sort_mode.dart'; -import 'package:rabenkorb/shared/widgets/inputs/core_icon_text_button.dart'; -import 'package:rabenkorb/shared/widgets/sort_rule_dropdown.dart'; +import 'package:rabenkorb/shared/widgets/core_sort_control.dart'; import 'package:watch_it/watch_it.dart'; class BasketSortControl extends StatelessWidget with WatchItMixin { @@ -20,30 +19,18 @@ class BasketSortControl extends StatelessWidget with WatchItMixin { final sortMode = watchStream((BasketStateService p0) => p0.sortMode, initialValue: basketStateService.sortModeSync); final sortDirection = watchStream((BasketStateService p0) => p0.sortDirection, initialValue: basketStateService.sortDirectionSync); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - child: SortRuleDropdown( - sortMode: sortMode.data, - sortRuleId: sortRuleId.data, - availableSortRules: availableSortRules.data ?? [], - updateSortRuleDetails: _updateSortDetails, - onNewSortRule: (int newId) async { - await di().setSortRuleId(newId); - }, - )), - CoreIconTextButton( - icon: const Icon(Icons.sort), - label: Text(S.of(context).SortDirection(sortDirection.data?.name ?? "")), - onPressed: () async { - await basketStateService.switchSortDirection(); - }, - ), - ], - ), + return CoreSortControl( + sortRuleId: sortRuleId.data, + sortMode: sortMode.data, + sortDirection: sortDirection.data ?? SortDirection.asc, + onNewSortRule: (int newId) async { + await di().setSortRuleId(newId); + }, + updateSortRuleDetails: _updateSortDetails, + availableSortRules: availableSortRules.data ?? [], + onSwitchSortDirection: () async { + await basketStateService.switchSortDirection(); + }, ); } diff --git a/lib/features/basket/basket_title.dart b/lib/features/basket/basket_title.dart index fe54de9..1ec4b43 100644 --- a/lib/features/basket/basket_title.dart +++ b/lib/features/basket/basket_title.dart @@ -4,6 +4,8 @@ import 'package:rabenkorb/features/basket/shopping_mode_toggle.dart'; import 'package:rabenkorb/models/shopping_basket_view_model.dart'; import 'package:rabenkorb/services/business/basket_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; +import 'package:rabenkorb/shared/extensions.dart'; +import 'package:rabenkorb/shared/helper_functions.dart'; import 'package:rabenkorb/shared/widgets/form/basket_dropdown.dart'; import 'package:watch_it/watch_it.dart'; @@ -29,8 +31,17 @@ class BasketTitle extends StatelessWidget with WatchItMixin { await di().setBasketId(basket?.id); }, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createShoppingBasket(searchValue); - await di().setBasketId(newId); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createShoppingBasket(newName); + await di().setBasketId(newId); + }, + ); }, selectedBasket: activeBasket.data, inputDecoration: const InputDecoration( @@ -39,10 +50,11 @@ class BasketTitle extends StatelessWidget with WatchItMixin { disabled: isMultiSelectMode || isShoppingMode, ), ), - ShoppingModeToggle(disabled: isMultiSelectMode), + ShoppingModeToggle(disabled: isMultiSelectMode || !activeBasket.hasData), BasketPopupMenu( isShoppingMode: isShoppingMode, isMultiSelectMode: isMultiSelectMode, + disabled: !activeBasket.hasData, ), ], ); diff --git a/lib/features/basket/details/basket_item_details.dart b/lib/features/basket/details/basket_item_details.dart index 40cce67..12433ca 100644 --- a/lib/features/basket/details/basket_item_details.dart +++ b/lib/features/basket/details/basket_item_details.dart @@ -39,18 +39,12 @@ class BasketItemDetails extends StatelessWidget { ); } - Future _onSubmit(String name, double amount, File? image, int? categoryId, int? unitId, int? basketId) async { + Future _onSubmit(String name, double amount, File? image, String? note, int? categoryId, int? unitId, int? basketId) async { final basketService = di(); final basketStateService = di(); if (basketItem == null) { - await basketService.createBasketItem( - name, - basketId: basketStateService.basketIdSync, - categoryId: categoryId, - image: image, - unitId: unitId, - amount: amount, - ); + await basketService.createBasketItem(name, + basketId: basketStateService.basketIdSync, categoryId: categoryId, image: image, unitId: unitId, amount: amount, note: note); return; } final imageChanged = image?.path != basketItem!.imagePath; @@ -60,6 +54,7 @@ class BasketItemDetails extends StatelessWidget { basketId: basketId, categoryId: categoryId, image: image, + note: note, imageChanged: imageChanged, amount: amount, unitId: unitId, diff --git a/lib/features/basket/details/basket_item_details_form.dart b/lib/features/basket/details/basket_item_details_form.dart index 2ad480e..a495ce0 100644 --- a/lib/features/basket/details/basket_item_details_form.dart +++ b/lib/features/basket/details/basket_item_details_form.dart @@ -23,7 +23,7 @@ import 'package:watch_it/watch_it.dart'; class BasketItemDetailsForm extends StatefulWidget { final BasketItemViewModel? basketItem; final String? tempItemName; - final Function(String name, double amount, File? image, int? categoryId, int? unitId, int? basketId) onSubmit; + final Function(String name, double amount, File? image, String? note, int? categoryId, int? unitId, int? basketId) onSubmit; const BasketItemDetailsForm({super.key, required this.basketItem, required this.onSubmit, this.tempItemName}); @@ -34,6 +34,7 @@ class BasketItemDetailsForm extends StatefulWidget { class _BasketItemDetailsFormState extends State { final _formKey = GlobalKey(); final TextEditingController _nameController = TextEditingController(); + final TextEditingController _noteController = TextEditingController(); final TextEditingController _amountController = TextEditingController(); ShoppingBasketViewModel? _basket; ItemCategoryViewModel? _category; @@ -53,6 +54,7 @@ class _BasketItemDetailsFormState extends State { _category = basketItem.category; _unit = basketItem.unit; _amountController.text = basketItem.amount.toFormattedString(); + _noteController.text = basketItem.note ?? ""; final imagePath = basketItem.imagePath; if (imagePath != null) { @@ -71,10 +73,12 @@ class _BasketItemDetailsFormState extends State { return; } state.save(); + final note = _noteController.text.isEmpty ? null : _noteController.text; widget.onSubmit( _nameController.text, _amountController.text.toDoubleOrZero(), _image, + note, _category?.id, _unit?.id, _basket?.id, @@ -99,8 +103,17 @@ class _BasketItemDetailsFormState extends State { dropdownKey: 'basket-dropdown', selectedBasket: _basket, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createShoppingBasket(searchValue); - _setBasket(ShoppingBasketViewModel(newId, searchValue)); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createShoppingBasket(newName!); + _setBasket(ShoppingBasketViewModel(newId, newName)); + }, + ); }, onChanged: _setBasket, ), @@ -108,6 +121,7 @@ class _BasketItemDetailsFormState extends State { formFieldKey: "basket-item-name-input", labelText: S.of(context).Name, textEditingController: _nameController, + textInputAction: TextInputAction.next, validator: (name) { if (name.isValid()) { return null; @@ -125,27 +139,52 @@ class _BasketItemDetailsFormState extends State { }, selectedCategory: _category, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createItemCategory(searchValue); - setState(() { - _category = ItemCategoryViewModel(newId, searchValue); - }); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createItemCategory(newName!); + setState(() { + _category = ItemCategoryViewModel(newId, newName); + }); + }, + ); }, ), gap, + CoreTextFormField( + labelText: S.of(context).Note, + textEditingController: _noteController, + formFieldKey: "note-input", + textInputAction: TextInputAction.next, + ), + gap, CoreTextFormField( labelText: S.of(context).Amount, textEditingController: _amountController, formFieldKey: "amount-input", keyboardType: const TextInputType.numberWithOptions(decimal: true), - textInputAction: TextInputAction.done, + textInputAction: TextInputAction.next, ), gap, UnitDropdown( dropdownKey: 'unit-dropdown', selectedUnit: _unit, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createItemUnit(searchValue); - _setUnit(ItemUnitViewModel(newId, searchValue)); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createItemUnit(newName!); + _setUnit(ItemUnitViewModel(newId, newName)); + }, + ); }, onChanged: _setUnit, ), diff --git a/lib/features/debug/debug_database_helper.dart b/lib/features/debug/debug_database_helper.dart index 8f5c974..da20e9a 100644 --- a/lib/features/debug/debug_database_helper.dart +++ b/lib/features/debug/debug_database_helper.dart @@ -35,10 +35,6 @@ Map testBaskets = { "Lidl": const ShoppingBasket(id: 2, name: "Lidl"), }; -Map testVariantKeys = { - "Key 1": const VariantKey(id: 1), -}; - Map testSortRules = { "Aldi": const SortRule(id: 1, name: "Aldi"), "Lidl": const SortRule(id: 2, name: "Lidl"), @@ -125,14 +121,12 @@ Map testItemTemplates = { name: "Peas", category: testCategories["Canned Food"]!.id, library: 1, - variantKey: testVariantKeys["Key 1"]!.id, ), "Peas - Frozen": ItemTemplate( id: 15, name: "Peas", category: testCategories["Frozen Food"]!.id, library: 1, - variantKey: testVariantKeys["Key 1"]!.id, ), }; @@ -141,6 +135,7 @@ Map testBasketItemsOne = { id: 1, name: "Coffee", category: testCategories["Hot Drinks"]!.id, + note: "Beans", amount: 0, basket: testBaskets["Aldi"]!.id, isChecked: false, @@ -156,6 +151,7 @@ Map testBasketItemsOne = { "Apple - Aldi": BasketItem( id: 6, name: "Apple", + note: "Braeburn", amount: 0, unit: testUnits["Pieces"]!.id, basket: testBaskets["Aldi"]!.id, @@ -322,7 +318,6 @@ Future seedDatabase(AppDatabase db) async { batch.insertAll(db.itemCategories, testCategories.values); batch.insertAll(db.itemUnits, testUnits.values); batch.insertAll(db.templateLibraries, testLibraries.values); - batch.insertAll(db.variantKeys, testVariantKeys.values); batch.insertAll(db.sortRules, testSortRules.values); batch.insertAll(db.sortOrders, testSortOrdersRuleOne); batch.insertAll(db.sortOrders, testSortOrdersRuleTwo); @@ -338,7 +333,6 @@ Future clearDatabase(AppDatabase db) async { batch.deleteAll(db.itemCategories); batch.deleteAll(db.itemUnits); batch.deleteAll(db.templateLibraries); - batch.deleteAll(db.variantKeys); batch.deleteAll(db.sortRules); batch.deleteAll(db.sortOrders); batch.deleteAll(db.sortOrders); diff --git a/lib/features/debug/debug_database_real_data_sample.dart b/lib/features/debug/debug_database_real_data_sample.dart index 5fe4daa..62c83bc 100644 --- a/lib/features/debug/debug_database_real_data_sample.dart +++ b/lib/features/debug/debug_database_real_data_sample.dart @@ -95,10 +95,6 @@ Map exampleLibraries = { "Library One": const TemplateLibrary(id: 1, name: "Library One"), }; -Map exampleVariantKeys = { - "Key 1": const VariantKey(id: 1), -}; - List exampleItemTemplates = [ ItemTemplate(id: 1, name: "Kartoffelwedges", category: exampleCategories["Tiefkühl"]?.id, library: 1), ItemTemplate(id: 2, name: "Aufschnitt", category: exampleCategories["KühlthekeTeil1"]?.id, library: 1), @@ -354,7 +350,6 @@ Future seedDatabaseWithExampleData(AppDatabase db) async { batch.insertAll(db.itemCategories, exampleCategories.values); batch.insertAll(db.itemUnits, exampleUnits.values); batch.insertAll(db.templateLibraries, exampleLibraries.values); - batch.insertAll(db.variantKeys, exampleVariantKeys.values); batch.insertAll(db.sortRules, exampleSortRules.values); batch.insertAll(db.sortOrders, exampleSortOrdersRuleOne); batch.insertAll(db.itemTemplates, exampleItemTemplates); diff --git a/lib/features/library/add_to_cart_dialog.dart b/lib/features/library/add_to_cart_dialog.dart index 8532543..0768efd 100644 --- a/lib/features/library/add_to_cart_dialog.dart +++ b/lib/features/library/add_to_cart_dialog.dart @@ -8,6 +8,7 @@ import 'package:rabenkorb/services/business/basket_service.dart'; import 'package:rabenkorb/services/business/metadata_service.dart'; import 'package:rabenkorb/services/core/snackbar_service.dart'; import 'package:rabenkorb/shared/extensions.dart'; +import 'package:rabenkorb/shared/helper_functions.dart'; import 'package:rabenkorb/shared/widgets/constant_widgets.dart'; import 'package:rabenkorb/shared/widgets/form/basket_dropdown.dart'; import 'package:rabenkorb/shared/widgets/form/core_text_form_field.dart'; @@ -27,6 +28,7 @@ class AddToCardDialog extends StatefulWidget { class _AddToCardDialogState extends State { final TextEditingController _amountController = TextEditingController(); + final TextEditingController _noteController = TextEditingController(); late ItemTemplateViewModel _item; ItemUnitViewModel? _unit; ShoppingBasketViewModel? _basket; @@ -54,8 +56,17 @@ class _AddToCardDialogState extends State { dropdownKey: 'basket-dropdown', selectedBasket: _basket, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createShoppingBasket(searchValue); - _setBasket(ShoppingBasketViewModel(newId, searchValue)); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createShoppingBasket(newName!); + _setBasket(ShoppingBasketViewModel(newId, newName)); + }, + ); }, onChanged: _setBasket, ), @@ -71,8 +82,17 @@ class _AddToCardDialogState extends State { dropdownKey: 'unit-dropdown', selectedUnit: _unit, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createItemUnit(searchValue); - _setUnit(ItemUnitViewModel(newId, searchValue)); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createItemUnit(newName!); + _setUnit(ItemUnitViewModel(newId, newName)); + }, + ); }, onChanged: _setUnit, ), @@ -87,6 +107,7 @@ class _AddToCardDialogState extends State { basketId: _basket?.id, categoryId: _item.category?.id, imagePath: _item.imagePath, + note: _noteController.text, amount: _amountController.text.toDoubleOrZero(), unitId: _unit?.id, ); diff --git a/lib/features/library/details/item_template_details.dart b/lib/features/library/details/item_template_details.dart index d8b6e6f..da58290 100644 --- a/lib/features/library/details/item_template_details.dart +++ b/lib/features/library/details/item_template_details.dart @@ -39,7 +39,7 @@ class ItemTemplateDetails extends StatelessWidget { ); } - Future _onSubmit(String name, File? image, int? categoryId, int? variantKey) async { + Future _onSubmit(String name, File? image, int? categoryId) async { final libraryService = di(); final libraryStateService = di(); if (itemTemplate == null) { @@ -48,7 +48,6 @@ class ItemTemplateDetails extends StatelessWidget { libraryId: libraryStateService.libraryIdSync, categoryId: categoryId, image: image, - variantKeyId: variantKey, ); return; } @@ -59,7 +58,6 @@ class ItemTemplateDetails extends StatelessWidget { libraryId: libraryStateService.libraryIdSync, categoryId: categoryId, image: image, - variantKeyId: variantKey, imageChanged: imageChanged, ); } diff --git a/lib/features/library/details/item_template_details_form.dart b/lib/features/library/details/item_template_details_form.dart index 8a9d1db..8470d5d 100644 --- a/lib/features/library/details/item_template_details_form.dart +++ b/lib/features/library/details/item_template_details_form.dart @@ -18,7 +18,7 @@ import 'package:watch_it/watch_it.dart'; class ItemTemplateDetailsForm extends StatefulWidget { final ItemTemplateViewModel? itemTemplate; final String? tempItemName; - final Function(String name, File? image, int? categoryId, int? variantKey) onSubmit; + final Function(String name, File? image, int? categoryId) onSubmit; const ItemTemplateDetailsForm({super.key, required this.itemTemplate, required this.onSubmit, this.tempItemName}); @@ -42,7 +42,6 @@ class _ItemTemplateDetailsFormState extends State { _nameController.text = itemTemplate.name; _category = itemTemplate.category; - _variant = itemTemplate.variantKey; final imagePath = itemTemplate.imagePath; if (imagePath != null) { @@ -61,7 +60,7 @@ class _ItemTemplateDetailsFormState extends State { return; } state.save(); - widget.onSubmit(_nameController.text, _image, _category?.id, _variant); + widget.onSubmit(_nameController.text, _image, _category?.id); context.pop("saved"); }); } @@ -99,10 +98,19 @@ class _ItemTemplateDetailsFormState extends State { }, selectedCategory: _category, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createItemCategory(searchValue); - setState(() { - _category = ItemCategoryViewModel(newId, searchValue); - }); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createItemCategory(newName!); + setState(() { + _category = ItemCategoryViewModel(newId, newName); + }); + }, + ); }, ), gap, diff --git a/lib/features/library/library_sort_control.dart b/lib/features/library/library_sort_control.dart index 5fe7154..a857cab 100644 --- a/lib/features/library/library_sort_control.dart +++ b/lib/features/library/library_sort_control.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:rabenkorb/generated/l10n.dart'; import 'package:rabenkorb/models/sort_rule_view_model.dart'; import 'package:rabenkorb/services/business/library_service.dart'; import 'package:rabenkorb/services/state/library_state_service.dart'; import 'package:rabenkorb/shared/default_sort_rules.dart'; +import 'package:rabenkorb/shared/sort_direction.dart'; import 'package:rabenkorb/shared/sort_mode.dart'; -import 'package:rabenkorb/shared/widgets/inputs/core_icon_text_button.dart'; -import 'package:rabenkorb/shared/widgets/sort_rule_dropdown.dart'; +import 'package:rabenkorb/shared/widgets/core_sort_control.dart'; import 'package:watch_it/watch_it.dart'; class LibrarySortControl extends StatelessWidget with WatchItMixin { @@ -20,30 +19,18 @@ class LibrarySortControl extends StatelessWidget with WatchItMixin { final sortMode = watchStream((LibraryStateService p0) => p0.sortMode, initialValue: libraryStateService.sortModeSync); final sortDirection = watchStream((LibraryStateService p0) => p0.sortDirection, initialValue: libraryStateService.sortDirectionSync); - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Expanded( - child: SortRuleDropdown( - sortMode: sortMode.data, - sortRuleId: sortRuleId.data, - availableSortRules: availableSortRules.data ?? [], - updateSortRuleDetails: _updateSortDetails, - onNewSortRule: (int newId) async { - await di().setSortRuleId(newId); - }, - )), - CoreIconTextButton( - icon: const Icon(Icons.sort), - label: Text(S.of(context).SortDirection(sortDirection.data?.name ?? "")), - onPressed: () async { - await libraryStateService.switchSortDirection(); - }, - ), - ], - ), + return CoreSortControl( + sortRuleId: sortRuleId.data, + sortMode: sortMode.data, + sortDirection: sortDirection.data ?? SortDirection.asc, + onNewSortRule: (int newId) async { + await di().setSortRuleId(newId); + }, + updateSortRuleDetails: _updateSortDetails, + availableSortRules: availableSortRules.data ?? [], + onSwitchSortDirection: () async { + await libraryStateService.switchSortDirection(); + }, ); } diff --git a/lib/generated/intl/messages_de_DE.dart b/lib/generated/intl/messages_de_DE.dart index e1645da..54a9dc3 100644 --- a/lib/generated/intl/messages_de_DE.dart +++ b/lib/generated/intl/messages_de_DE.dart @@ -25,6 +25,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m1(direction) => "${Intl.select(direction, { 'asc': 'Aufsteigend', 'desc': 'Absteigend', + 'other': 'Unbekannt', })}"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -36,6 +37,7 @@ class MessageLookup extends MessageLookupByLibrary { "Backup": MessageLookupByLibrary.simpleMessage("Backup"), "BackupCreate": MessageLookupByLibrary.simpleMessage("Erstellen"), "BackupCreated": MessageLookupByLibrary.simpleMessage("Backup erfolgrecih erstellt"), + "BackupCreationFailed": MessageLookupByLibrary.simpleMessage("Backup Erstellung fehlgeschlagen!"), "BackupImport": MessageLookupByLibrary.simpleMessage("Wiederherstellen"), "BackupImportFailed": MessageLookupByLibrary.simpleMessage("Import fehlgeschlagen!"), "BackupImported": MessageLookupByLibrary.simpleMessage("Backup erfolgreich importiert"), @@ -87,6 +89,7 @@ class MessageLookup extends MessageLookupByLibrary { "NoSearchResult": MessageLookupByLibrary.simpleMessage("Keine Ergebnisse"), "NoSelection": MessageLookupByLibrary.simpleMessage("Keine Auswahl"), "NoShoppingBasketSelected": MessageLookupByLibrary.simpleMessage("Keinen Korb ausgewählt"), + "Note": MessageLookupByLibrary.simpleMessage("Notiz"), "PermissionsRequired": MessageLookupByLibrary.simpleMessage("Berechtigungen erforderlich"), "PickImage": MessageLookupByLibrary.simpleMessage("Bild auswählen"), "Rename": MessageLookupByLibrary.simpleMessage("Umbenennen"), diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index a9de35c..04a13c6 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -25,6 +25,7 @@ class MessageLookup extends MessageLookupByLibrary { static String m1(direction) => "${Intl.select(direction, { 'asc': 'Ascending', 'desc': 'Descending', + 'other': 'Unknown', })}"; final messages = _notInlinedMessages(_notInlinedMessages); @@ -36,6 +37,7 @@ class MessageLookup extends MessageLookupByLibrary { "Backup": MessageLookupByLibrary.simpleMessage("Backup"), "BackupCreate": MessageLookupByLibrary.simpleMessage("Create"), "BackupCreated": MessageLookupByLibrary.simpleMessage("Backup created successfully"), + "BackupCreationFailed": MessageLookupByLibrary.simpleMessage("Backup creation failed!"), "BackupImport": MessageLookupByLibrary.simpleMessage("Restore"), "BackupImportFailed": MessageLookupByLibrary.simpleMessage("Import failed!"), "BackupImported": MessageLookupByLibrary.simpleMessage("Backup imported successfully"), @@ -87,6 +89,7 @@ class MessageLookup extends MessageLookupByLibrary { "NoSearchResult": MessageLookupByLibrary.simpleMessage("No results"), "NoSelection": MessageLookupByLibrary.simpleMessage("No Selection"), "NoShoppingBasketSelected": MessageLookupByLibrary.simpleMessage("No basket selected"), + "Note": MessageLookupByLibrary.simpleMessage("Note"), "PermissionsRequired": MessageLookupByLibrary.simpleMessage("Permissions required"), "PickImage": MessageLookupByLibrary.simpleMessage("Pick an image"), "Rename": MessageLookupByLibrary.simpleMessage("Rename"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index 47300bb..a855f7d 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -337,6 +337,16 @@ class S { ); } + /// `Backup creation failed!` + String get BackupCreationFailed { + return Intl.message( + 'Backup creation failed!', + name: 'BackupCreationFailed', + desc: '', + args: [], + ); + } + /// `Backup imported successfully` String get BackupImported { return Intl.message( @@ -397,13 +407,14 @@ class S { ); } - /// `{direction, select, asc{Ascending} desc{Descending}}` + /// `{direction, select, asc{Ascending} desc{Descending} other{Unknown}}` String SortDirection(String direction) { return Intl.select( direction, { 'asc': 'Ascending', 'desc': 'Descending', + 'other': 'Unknown', }, name: 'SortDirection', desc: 'The human readable sort direction', @@ -491,6 +502,16 @@ class S { ); } + /// `Note` + String get Note { + return Intl.message( + 'Note', + name: 'Note', + desc: '', + args: [], + ); + } + /// `Unit` String get Unit { return Intl.message( diff --git a/lib/l10n/intl_de_DE.arb b/lib/l10n/intl_de_DE.arb index f8022a5..ad7f8f6 100644 --- a/lib/l10n/intl_de_DE.arb +++ b/lib/l10n/intl_de_DE.arb @@ -29,13 +29,14 @@ "BackupOverwriteWarning": "Wenn du ein Backup importierst wird dein derzeitiger Stand überschrieben! Wähle oben die Option zum Überschreiben alter Data ab, wenn du die importierten Daten zu deiner Bibliothek hinzufügen willst.", "BackupImportFailed": "Import fehlgeschlagen!", "BackupCreated": "Backup erfolgrecih erstellt", + "BackupCreationFailed": "Backup Erstellung fehlgeschlagen!", "BackupImported": "Backup erfolgreich importiert", "SelectBackup": "Backup-Ort auswählen", "SetPermission": "Berechtigung erteilen", "PermissionsRequired": "Berechtigungen erforderlich", "MessagePermissionRequired": "Um auf Ordner zum Speicher oder Laden von Sicherungen zugreifen zu können, benötigt diese App die Berechtigung auf alle Dateien und Ordner zuzugreifen. Diese wird niemals auf Dateien zugreifen, die nicht zu ihr gehören. \n\nWenn Sie auf \"Berechtigung setzen\" drücken werden Sie zur Berechtigungsverwaltung weitergeleitet. Setzen Sie dort die Berechtigung und kehren zur App zurück, indem Sie auf die Zurück-Taste Ihres Smartphones drücken.", "SearchLabel": "Suchen...", - "SortDirection": "{direction, select, asc{Aufsteigend} desc{Absteigend}}", + "SortDirection": "{direction, select, asc{Aufsteigend} desc{Absteigend} other{Unbekannt}}", "@SortDirection": { "description": "The human readable sort direction", "placeholders": { @@ -52,6 +53,7 @@ "Variant": "Variante", "Image": "Bild", "Amount": "Menge", + "Note": "Notiz", "Unit": "Einheit", "Units": "Einheiten", "SortRule": "Sortierregel", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f19575e..d1b37bd 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -29,13 +29,14 @@ "BackupOverwriteWarning": "By importing a backup your current state will be overwritten! Uncheck the option for overwriting data above, if you want to add the imported data to your library.", "BackupImportFailed": "Import failed!", "BackupCreated": "Backup created successfully", + "BackupCreationFailed": "Backup creation failed!", "BackupImported": "Backup imported successfully", "SelectBackup": "Select backup location", "SetPermission": "Set Permission", "PermissionsRequired": "Permissions required", "MessagePermissionRequired": "To access folders for saving or loading backup this app the permission to access files and folders. This app will never access any files that are not related to it. \n\nIf you click on \"Set Permission\" you will be redirect to the permission screen of your phone. Please set the permission and return to this app by pressing the Back Button of your Smartphone.", "SearchLabel": "Search...", - "SortDirection": "{direction, select, asc{Ascending} desc{Descending}}", + "SortDirection": "{direction, select, asc{Ascending} desc{Descending} other{Unknown}}", "@SortDirection": { "description": "The human readable sort direction", "placeholders": { @@ -52,6 +53,7 @@ "Variant": "Variant", "Image": "Image", "Amount": "Amount", + "Note": "Note", "Unit": "Unit", "Units": "Units", "SortRule": "Sort Rule", diff --git a/lib/mappers/to_view_model.dart b/lib/mappers/to_view_model.dart index 1aa9d06..cc0b468 100644 --- a/lib/mappers/to_view_model.dart +++ b/lib/mappers/to_view_model.dart @@ -12,6 +12,7 @@ BasketItemViewModel toBasketItemViewModel(BasketItem item, ItemCategory? categor id: item.id, name: item.name, imagePath: item.imagePath, + note: item.note, amount: item.amount, category: toItemCategoryViewModel(category), basket: toShoppingBasketViewModel(basket)!, @@ -27,7 +28,6 @@ ItemTemplateViewModel toItemTemplateViewModel(ItemTemplate item, ItemCategory? c imagePath: item.imagePath, category: toItemCategoryViewModel(category), library: toTemplateLibraryViewModel(library)!, - variantKey: item.variantKey, ); } diff --git a/lib/models/basket_item_view_model.dart b/lib/models/basket_item_view_model.dart index e70a5b4..03902ae 100644 --- a/lib/models/basket_item_view_model.dart +++ b/lib/models/basket_item_view_model.dart @@ -8,6 +8,7 @@ class BasketItemViewModel extends DataItem { final int id; final String name; final String? imagePath; + final String? note; final double amount; final ItemCategoryViewModel? category; final ShoppingBasketViewModel basket; @@ -21,6 +22,7 @@ class BasketItemViewModel extends DataItem { required this.id, required this.name, required this.imagePath, + required this.note, required this.amount, required this.category, required this.basket, @@ -34,6 +36,7 @@ class BasketItemViewModel extends DataItem { "id": id, "name": name, "imagePath": imagePath, + "note": note, "amount": amount, "category": category, "basket": basket, diff --git a/lib/models/item_template_view_model.dart b/lib/models/item_template_view_model.dart index 540ebab..2f0f56c 100644 --- a/lib/models/item_template_view_model.dart +++ b/lib/models/item_template_view_model.dart @@ -7,7 +7,6 @@ class ItemTemplateViewModel extends DataItem { final int id; final String name; final String? imagePath; - final int? variantKey; final ItemCategoryViewModel? category; final TemplateLibraryViewModel library; @@ -18,7 +17,6 @@ class ItemTemplateViewModel extends DataItem { required this.id, required this.name, required this.imagePath, - required this.variantKey, required this.category, required this.library, }); @@ -29,7 +27,6 @@ class ItemTemplateViewModel extends DataItem { "id": id, "name": name, "imagePath": imagePath, - "variantKey": variantKey, "category": category?.toJson(), "library": library.toJson(), }; diff --git a/lib/services/business/basket_service.dart b/lib/services/business/basket_service.dart index 36e2ba5..2901a97 100644 --- a/lib/services/business/basket_service.dart +++ b/lib/services/business/basket_service.dart @@ -90,6 +90,7 @@ class BasketService implements Disposable { int? categoryId, required int? basketId, File? image, + String? note, String? imagePath, int? unitId, }) async { @@ -108,6 +109,7 @@ class BasketService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: imagePath, + note: note, unitId: unitId, ); } @@ -131,6 +133,7 @@ class BasketService implements Disposable { categoryId: originalBasketItem.category?.id, basketId: originalBasketItem.basket.id, imagePath: null, + note: originalBasketItem.note, isChecked: originalBasketItem.isChecked, unitId: originalBasketItem.unit?.id, amount: originalBasketItem.amount); @@ -150,6 +153,7 @@ class BasketService implements Disposable { int? categoryId, int? basketId, File? image, + String? note, int? unitId, bool? isChecked, }) async { @@ -170,6 +174,7 @@ class BasketService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: image?.path, + note: note, unitId: unitId, isChecked: isChecked, ); @@ -182,6 +187,7 @@ class BasketService implements Disposable { int? categoryId, int? basketId, File? image, + String? note, int? unitId, bool? isChecked, bool imageChanged = false, @@ -207,6 +213,7 @@ class BasketService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: image?.path, + note: note, unitId: unitId, isChecked: isChecked, ); diff --git a/lib/services/business/library_service.dart b/lib/services/business/library_service.dart index cad2539..474d4b4 100644 --- a/lib/services/business/library_service.dart +++ b/lib/services/business/library_service.dart @@ -49,12 +49,10 @@ class LibraryService { String name, { int? categoryId, int? libraryId, - int? variantKeyId, File? image, }) async { libraryId = await _ensureExistingLibrary(libraryId); await _metadataService.ensureExistingCategory(categoryId); - await _metadataService.ensureExistingVariantKey(variantKeyId); if (image != null) { image = await _imageService.saveImage(image); @@ -64,7 +62,6 @@ class LibraryService { name, libraryId: libraryId, imagePath: image?.path, - variantKeyId: variantKeyId, categoryId: categoryId, ); } @@ -80,36 +77,9 @@ class LibraryService { categoryId: null, libraryId: originalItemTemplate.library.id, imagePath: originalItemTemplate.imagePath, - variantKeyId: originalItemTemplate.variantKey, ); } - Future removeItemTemplateVariant(int templateId) async { - final originalItemTemplate = await _itemTemplateService.getItemTemplateById(templateId); - if (originalItemTemplate == null) { - return; - } - final variantKeyId = originalItemTemplate.variantKey; - if (variantKeyId == null) { - return; - } - await _itemTemplateService.replaceItemTemplate( - templateId, - name: originalItemTemplate.name, - categoryId: originalItemTemplate.category?.id, - libraryId: originalItemTemplate.library.id, - imagePath: originalItemTemplate.imagePath, - variantKeyId: null, - ); - - final remainingItemTemplatesWithVariantKey = await _itemTemplateService.getItemTemplatesByVariantKey(variantKeyId); - if (remainingItemTemplatesWithVariantKey.length > 1) { - return; - } - - await _metadataService.deleteVariantKeyById(variantKeyId); - } - Future removeItemTemplateImage(int templateId) async { final originalItemTemplate = await _itemTemplateService.getItemTemplateById(templateId); if (originalItemTemplate == null) { @@ -125,7 +95,6 @@ class LibraryService { categoryId: originalItemTemplate.category?.id, libraryId: originalItemTemplate.library.id, imagePath: null, - variantKeyId: originalItemTemplate.variantKey, ); // Check if the same image is used by other items; final usageCount = await _itemTemplateService.countImagePathUsages(imagePath); @@ -140,12 +109,10 @@ class LibraryService { String? name, int? categoryId, int? libraryId, - int? variantKeyId, File? image, }) async { libraryId = await _ensureExistingLibrary(libraryId); await _metadataService.ensureExistingCategory(categoryId); - await _metadataService.ensureExistingVariantKey(variantKeyId); // Delete old image if new one was provided if (image != null) { @@ -159,7 +126,6 @@ class LibraryService { name: name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: image?.path, ); } @@ -169,13 +135,11 @@ class LibraryService { required String name, int? categoryId, int? libraryId, - int? variantKeyId, File? image, bool imageChanged = false, }) async { libraryId = await _ensureExistingLibrary(libraryId); await _metadataService.ensureExistingCategory(categoryId); - await _metadataService.ensureExistingVariantKey(variantKeyId); if (imageChanged) { await removeItemTemplateImage(templateId); @@ -190,7 +154,6 @@ class LibraryService { name: name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: image?.path, ); } diff --git a/lib/services/business/metadata_service.dart b/lib/services/business/metadata_service.dart index c94eacc..b0c7d7a 100644 --- a/lib/services/business/metadata_service.dart +++ b/lib/services/business/metadata_service.dart @@ -2,12 +2,10 @@ import 'dart:async'; import 'package:rabenkorb/exceptions/missing_category.dart'; import 'package:rabenkorb/exceptions/missing_unit.dart'; -import 'package:rabenkorb/exceptions/missing_variant.dart'; import 'package:rabenkorb/models/item_category_view_model.dart'; import 'package:rabenkorb/models/item_unit_view_model.dart'; import 'package:rabenkorb/services/data_access/item_category_service.dart'; import 'package:rabenkorb/services/data_access/item_unit_service.dart'; -import 'package:rabenkorb/services/data_access/variant_key_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; import 'package:rabenkorb/services/state/library_state_service.dart'; import 'package:rabenkorb/shared/sort_direction.dart'; @@ -15,12 +13,9 @@ import 'package:rabenkorb/shared/sort_mode.dart'; import 'package:rxdart/rxdart.dart'; import 'package:watch_it/watch_it.dart'; -import '../../database/database.dart'; - class MetadataService implements Disposable { final _itemUnitService = di(); final _itemCategoryService = di(); - final _variantKeyService = di(); final _libraryStateService = di(); final _basketStateService = di(); @@ -93,18 +88,6 @@ class MetadataService implements Disposable { return _itemCategoryService.watchItemCategoriesInOrder(sortMode, sortDirection, sortRuleId: sortRuleId); } - Future createVariantKey(String name) { - return _variantKeyService.createVariantKey(name); - } - - Future getVariantKeyById(int id) { - return _variantKeyService.getVariantKeyById(id); - } - - Future deleteVariantKeyById(int id) { - return _variantKeyService.deleteVariantKeyById(id); - } - Future ensureExistingCategory(int? categoryId) async { if (categoryId == null) { return; @@ -114,15 +97,6 @@ class MetadataService implements Disposable { throwIf(category == null, MissingCategoryException(categoryId)); } - Future ensureExistingVariantKey(int? variantId) async { - if (variantId == null) { - return; - } - final variant = await getVariantKeyById(variantId); - - throwIf(variant == null, MissingVariantException(variantId)); - } - Future ensureExistingUnit(int? unitId) async { if (unitId == null) { return; diff --git a/lib/services/data_access/basket_item_service.dart b/lib/services/data_access/basket_item_service.dart index 082c8ee..944865c 100644 --- a/lib/services/data_access/basket_item_service.dart +++ b/lib/services/data_access/basket_item_service.dart @@ -51,6 +51,7 @@ class BasketItemService implements Disposable { int? categoryId, required int basketId, String? imagePath, + String? note, int? unitId, }) { return _db.basketItemsDao.createBasketItem( @@ -59,6 +60,7 @@ class BasketItemService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: imagePath, + note: note, unitId: unitId, ); } @@ -70,6 +72,7 @@ class BasketItemService implements Disposable { int? categoryId, int? basketId, String? imagePath, + String? note, int? unitId, bool? isChecked, }) { @@ -80,6 +83,7 @@ class BasketItemService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: imagePath, + note: note, unitId: unitId, isChecked: isChecked, ); @@ -92,6 +96,7 @@ class BasketItemService implements Disposable { int? categoryId, required int basketId, String? imagePath, + String? note, int? unitId, bool? isChecked, }) { @@ -102,6 +107,7 @@ class BasketItemService implements Disposable { categoryId: categoryId, basketId: basketId, imagePath: imagePath, + note: note, unitId: unitId, isChecked: isChecked, ); diff --git a/lib/services/data_access/item_template_service.dart b/lib/services/data_access/item_template_service.dart index 6401e0b..c6164d7 100644 --- a/lib/services/data_access/item_template_service.dart +++ b/lib/services/data_access/item_template_service.dart @@ -45,14 +45,12 @@ class ItemTemplateService implements Disposable { String name, { int? categoryId, required int libraryId, - int? variantKeyId, String? imagePath, }) { return _db.itemTemplatesDao.createItemTemplate( name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); } @@ -62,7 +60,6 @@ class ItemTemplateService implements Disposable { String? name, int? categoryId, int? libraryId, - int? variantKeyId, String? imagePath, }) { return _db.itemTemplatesDao.updateItemTemplate( @@ -70,7 +67,6 @@ class ItemTemplateService implements Disposable { name: name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); } @@ -80,7 +76,6 @@ class ItemTemplateService implements Disposable { required String name, int? categoryId, required int libraryId, - int? variantKeyId, String? imagePath, }) { return _db.itemTemplatesDao.replaceItemTemplate( @@ -88,7 +83,6 @@ class ItemTemplateService implements Disposable { name: name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); } @@ -97,10 +91,6 @@ class ItemTemplateService implements Disposable { return _db.itemTemplatesDao.getItemTemplateWithId(id); } - Future> getItemTemplatesByVariantKey(int variantKeyId) { - return _db.itemTemplatesDao.getItemTemplatesByVariantKey(variantKeyId); - } - Future deleteItemTemplateById(int id) { return _db.itemTemplatesDao.deleteItemTemplateWithId(id); } diff --git a/lib/services/data_access/variant_key_service.dart b/lib/services/data_access/variant_key_service.dart deleted file mode 100644 index cc90ab5..0000000 --- a/lib/services/data_access/variant_key_service.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:rabenkorb/database/database.dart'; -import 'package:watch_it/watch_it.dart'; - -class VariantKeyService { - final _db = di(); - - Future createVariantKey(String name) { - return _db.variantKeysDao.createVariantKey(name); - } - - Future getVariantKeyById(int id) { - return _db.variantKeysDao.getVariantKeyWithId(id); - } - - Future deleteVariantKeyById(int id) { - return _db.variantKeysDao.deleteVariantKeyWithId(id); - } -} diff --git a/lib/services/state/data_management_navigation_state_service.dart b/lib/services/state/data_management_navigation_state_service.dart index c48e457..f485113 100644 --- a/lib/services/state/data_management_navigation_state_service.dart +++ b/lib/services/state/data_management_navigation_state_service.dart @@ -15,16 +15,19 @@ class DataManagementNavigationStateService implements Disposable, NavigationStat late StreamSubscription _dataManagementPageDetailsSub; + @override int get currentPageIndexSync => _currentPageIndex.value; Stream get dataManagementPageDetails => _dataManagementPageDetails.stream; + @override void setCurrentPageIndex(int index) { _currentPageIndex.add(index); } final List _destinations = dataManagementDestinations; + @override List get destinations => _destinations.map((e) => e.destination).toList(); DataManagementNavigationStateService() { diff --git a/lib/services/state/main_navigation_state_service.dart b/lib/services/state/main_navigation_state_service.dart index 42874e6..e71c5d7 100644 --- a/lib/services/state/main_navigation_state_service.dart +++ b/lib/services/state/main_navigation_state_service.dart @@ -15,16 +15,19 @@ class MainNavigationStateService implements Disposable, NavigationStateService { late StreamSubscription _mainPageDetailsSub; + @override int get currentPageIndexSync => _currentPageIndex.value; Stream get mainPageDetails => _mainPageDetails.stream; + @override void setCurrentPageIndex(int index) { _currentPageIndex.add(index); } final List _destinations = mainDestinations; + @override List get destinations => _destinations.map((e) => e.destination).toList(); MainNavigationStateService() { diff --git a/lib/services/utility/backup_service.dart b/lib/services/utility/backup_service.dart index 41e1c43..259d2a8 100644 --- a/lib/services/utility/backup_service.dart +++ b/lib/services/utility/backup_service.dart @@ -24,33 +24,43 @@ class BackupService { final List _incompatibleVersions = []; - Future backup(String exportPath) async { - final base64Images = await _encodeImages(); - final backupName = _getBackupName(_exportTime); - final backup = Backup( - appVersion: _versionService.publicAppVersion, - fileName: "$backupName.sqlite", - base64Images: base64Images, - ); - - _saveBackup(exportPath, backup); + Future backup(String exportPath) async { + try { + final base64Images = await _encodeImages(); + final backupName = _getBackupName(_exportTime); + final backup = Backup( + appVersion: _versionService.publicAppVersion, + fileName: "$backupName.sqlite", + base64Images: base64Images, + ); + + _saveBackup(exportPath, backup); + return true; + } catch (e) { + return false; + } } - Future restore(String importPath) async { - final directory = Directory(importPath); - final backupJson = _getBackupJson(directory); - if (backupJson == null) { - return; - } - final backup = Backup.fromJson(backupJson); - String appVersion = backup.appVersion; + Future restore(String importPath) async { + try { + final directory = Directory(importPath); + final backupJson = _getBackupJson(directory); + if (backupJson == null) { + return false; + } + final backup = Backup.fromJson(backupJson); + String appVersion = backup.appVersion; - throwIf(_incompatibleVersions.contains(appVersion), IncompatibleAppVersionException(appVersion)); + throwIf(_incompatibleVersions.contains(appVersion), IncompatibleAppVersionException(appVersion)); - String fileName = backup.fileName; - Map base64Images = backup.base64Images; - await _decodeImages(base64Images); - await _importFrom(importPath, fileName); + String fileName = backup.fileName; + Map base64Images = backup.base64Images; + await _decodeImages(base64Images); + await _importFrom(importPath, fileName); + return true; + } catch (e) { + return false; + } } Map? _getBackupJson(Directory directory) { diff --git a/lib/shared/widgets/core_sort_control.dart b/lib/shared/widgets/core_sort_control.dart new file mode 100644 index 0000000..15e1f53 --- /dev/null +++ b/lib/shared/widgets/core_sort_control.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:rabenkorb/generated/l10n.dart'; +import 'package:rabenkorb/models/sort_rule_view_model.dart'; +import 'package:rabenkorb/shared/sort_direction.dart'; +import 'package:rabenkorb/shared/sort_mode.dart'; +import 'package:rabenkorb/shared/widgets/inputs/core_icon_text_button.dart'; +import 'package:rabenkorb/shared/widgets/sort_rule_dropdown.dart'; + +class CoreSortControl extends StatelessWidget { + final int? sortRuleId; + final SortMode? sortMode; + final SortDirection sortDirection; + final Function(int newId) onNewSortRule; + final Function(SortRuleViewModel? rule) updateSortRuleDetails; + final List availableSortRules; + final bool customRulesOnly; + final Function() onSwitchSortDirection; + + const CoreSortControl({ + super.key, + this.sortRuleId, + this.sortMode, + required this.sortDirection, + required this.onNewSortRule, + required this.updateSortRuleDetails, + required this.availableSortRules, + required this.onSwitchSortDirection, + this.customRulesOnly = false, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: SortRuleDropdown( + sortMode: sortMode, + sortRuleId: sortRuleId, + availableSortRules: availableSortRules, + updateSortRuleDetails: updateSortRuleDetails, + onNewSortRule: onNewSortRule, + )), + CoreIconTextButton( + icon: const Icon(Icons.sort), + label: Text(S.of(context).SortDirection(sortDirection.name)), + onPressed: onSwitchSortDirection, + ), + ], + ), + ); + } +} diff --git a/lib/shared/widgets/sort_rule_dropdown.dart b/lib/shared/widgets/sort_rule_dropdown.dart index 76c7363..08f81bf 100644 --- a/lib/shared/widgets/sort_rule_dropdown.dart +++ b/lib/shared/widgets/sort_rule_dropdown.dart @@ -4,6 +4,7 @@ import 'package:rabenkorb/models/sort_rule_view_model.dart'; import 'package:rabenkorb/services/data_access/sort_rule_service.dart'; import 'package:rabenkorb/shared/default_sort_rules.dart'; import 'package:rabenkorb/shared/extensions.dart'; +import 'package:rabenkorb/shared/helper_functions.dart'; import 'package:rabenkorb/shared/sort_mode.dart'; import 'package:rabenkorb/shared/widgets/form/core_searchable_dropdown.dart'; import 'package:watch_it/watch_it.dart'; @@ -44,8 +45,17 @@ class SortRuleDropdown extends StatelessWidget { ), allowEmptyValue: false, onNoSearchResultAction: (String searchValue) async { - final newId = await di().createSortRule(searchValue); - await onNewSortRule(newId); + await showRenameDialog( + context, + initialName: searchValue, + onConfirm: (newName, nameChanged) async { + if (!newName.isValid()) { + return; + } + final newId = await di().createSortRule(newName!); + await onNewSortRule(newId); + }, + ); }, ); } diff --git a/test/business/basket_service_test.dart b/test/business/basket_service_test.dart index bf13ae3..3a753b4 100644 --- a/test/business/basket_service_test.dart +++ b/test/business/basket_service_test.dart @@ -13,7 +13,6 @@ import 'package:rabenkorb/services/data_access/item_category_service.dart'; import 'package:rabenkorb/services/data_access/item_unit_service.dart'; import 'package:rabenkorb/services/data_access/shopping_basket_service.dart'; import 'package:rabenkorb/services/data_access/sort_rule_service.dart'; -import 'package:rabenkorb/services/data_access/variant_key_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; import 'package:rabenkorb/services/state/library_state_service.dart'; import 'package:watch_it/watch_it.dart'; @@ -37,7 +36,6 @@ void main() { di.registerSingleton(BasketItemService()); di.registerSingleton(ItemUnitService()); di.registerSingleton(ItemCategoryService()); - di.registerSingleton(VariantKeyService()); di.registerSingleton(MetadataService()); di.registerSingleton(ShoppingBasketService()); diff --git a/test/business/library_service_test.dart b/test/business/library_service_test.dart index c3f4569..26e0638 100644 --- a/test/business/library_service_test.dart +++ b/test/business/library_service_test.dart @@ -4,7 +4,6 @@ import 'package:rabenkorb/abstracts/image_service.dart'; import 'package:rabenkorb/abstracts/preference_service.dart'; import 'package:rabenkorb/database/database.dart'; import 'package:rabenkorb/exceptions/missing_category.dart'; -import 'package:rabenkorb/exceptions/missing_variant.dart'; import 'package:rabenkorb/features/debug/debug_database_helper.dart'; import 'package:rabenkorb/services/business/library_service.dart'; import 'package:rabenkorb/services/business/metadata_service.dart'; @@ -13,7 +12,6 @@ import 'package:rabenkorb/services/data_access/item_template_service.dart'; import 'package:rabenkorb/services/data_access/item_unit_service.dart'; import 'package:rabenkorb/services/data_access/sort_rule_service.dart'; import 'package:rabenkorb/services/data_access/template_library_service.dart'; -import 'package:rabenkorb/services/data_access/variant_key_service.dart'; import 'package:rabenkorb/services/state/basket_state_service.dart'; import 'package:rabenkorb/services/state/library_state_service.dart'; import 'package:watch_it/watch_it.dart'; @@ -23,7 +21,6 @@ import '../mock_preferences_service.dart'; void main() { late LibraryService sut; - late MetadataService metadataService; late AppDatabase database; setUp(() async { @@ -38,10 +35,8 @@ void main() { di.registerSingleton(ItemTemplateService()); di.registerSingleton(ItemUnitService()); di.registerSingleton(ItemCategoryService()); - di.registerSingleton(VariantKeyService()); di.registerSingleton(MetadataService()); - metadataService = di(); di.registerSingleton(TemplateLibraryService()); await seedDatabase(database); @@ -70,25 +65,6 @@ void main() { ); }); - test("throw an exception if the variant key doesn't exist", () { - expectLater( - sut.createItemTemplate("Test Item", libraryId: 1, variantKeyId: 99), - throwsA(isA()), - ); - }); - - test("remove no longer needed variant keys after removing it for one template", () async { - final itemTemplateId = testItemTemplates["Peas - Frozen"]!.id; - final connectedItemTemplateId = testItemTemplates["Peas - Canned"]!.id; - await sut.removeItemTemplateVariant(itemTemplateId); - - final previouslyConnectedItem = await sut.getItemTemplateById(connectedItemTemplateId); - expect(previouslyConnectedItem!.variantKey, null); - - final variant = await metadataService.getVariantKeyById(testVariantKeys["Key 1"]!.id); - expect(variant, null); - }); - tearDown(() async { await database.close(); await di.reset(dispose: true); diff --git a/test/data_access/item_category_service_test.dart b/test/data_access/item_category_service_test.dart index 20091f3..01caad4 100644 --- a/test/data_access/item_category_service_test.dart +++ b/test/data_access/item_category_service_test.dart @@ -47,19 +47,19 @@ void main() { }); test('item categories can be watched', () async { + const categoryFour = "Baked Goods"; const categoryOne = "Dairy"; const categoryTwo = "Fresh Products"; const categoryThree = "Pasta"; const categoryThreeModified = "Spaghetti"; - const categoryFour = "Baked Goods"; const expectedValues = [ [], [categoryOne], [categoryOne, categoryTwo], [categoryOne, categoryTwo, categoryThree], - [categoryOne, categoryTwo, categoryThree, categoryFour], - [categoryOne, categoryTwo, categoryThreeModified, categoryFour], + [categoryFour, categoryOne, categoryTwo, categoryThree], + [categoryFour, categoryOne, categoryTwo, categoryThreeModified], ]; expectLater( diff --git a/test/data_access/item_template_service_test.dart b/test/data_access/item_template_service_test.dart index eadc977..608dde7 100644 --- a/test/data_access/item_template_service_test.dart +++ b/test/data_access/item_template_service_test.dart @@ -47,14 +47,12 @@ void main() { const name = "Milk"; const categoryId = 1; const libraryId = 1; - const variantKeyId = 1; const imagePath = "/img.png"; final id = await sut.createItemTemplate( name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); @@ -62,7 +60,6 @@ void main() { expect(itemTemplate?.name, name); expect(itemTemplate?.category?.id, categoryId); expect(itemTemplate?.library.id, libraryId); - expect(itemTemplate?.variantKey, variantKeyId); expect(itemTemplate?.imagePath, imagePath); }); @@ -84,7 +81,6 @@ void main() { const nameOne = "Milk"; const categoryId = 1; const libraryId = 1; - const variantKeyId = 1; const imagePath = "/img.png"; final id = await sut.createItemTemplate(nameOne, libraryId: libraryId); @@ -95,7 +91,6 @@ void main() { await sut.updateItemTemplate( id, categoryId: categoryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); @@ -103,7 +98,6 @@ void main() { expect(itemTemplate?.name, nameOne); expect(itemTemplate?.category?.id, categoryId); expect(itemTemplate?.library.id, libraryId); - expect(itemTemplate?.variantKey, variantKeyId); expect(itemTemplate?.imagePath, imagePath); const modifiedCategory = 2; @@ -116,7 +110,6 @@ void main() { expect(itemTemplate?.name, nameOne); expect(itemTemplate?.category?.id, modifiedCategory); expect(itemTemplate?.library.id, libraryId); - expect(itemTemplate?.variantKey, variantKeyId); expect(itemTemplate?.imagePath, imagePath); }); @@ -124,14 +117,12 @@ void main() { const name = "Milk"; const categoryId = 1; const libraryId = 1; - const variantKeyId = 1; const imagePath = "/img.png"; final id = await sut.createItemTemplate( name, categoryId: categoryId, libraryId: libraryId, - variantKeyId: variantKeyId, imagePath: imagePath, ); @@ -139,7 +130,6 @@ void main() { expect(itemTemplate?.name, name); expect(itemTemplate?.category?.id, categoryId); expect(itemTemplate?.library.id, libraryId); - expect(itemTemplate?.variantKey, variantKeyId); expect(itemTemplate?.imagePath, imagePath); await sut.replaceItemTemplate( @@ -152,7 +142,6 @@ void main() { expect(itemTemplate?.name, name); expect(itemTemplate?.category?.id, null); expect(itemTemplate?.library.id, libraryId); - expect(itemTemplate?.variantKey, null); expect(itemTemplate?.imagePath, null); }); diff --git a/test/data_access/item_unit_service_test.dart b/test/data_access/item_unit_service_test.dart index 9417b1a..639472d 100644 --- a/test/data_access/item_unit_service_test.dart +++ b/test/data_access/item_unit_service_test.dart @@ -47,19 +47,19 @@ void main() { }); test('item units can be watched', () async { - const unitOne = "Liter"; - const unitTwo = "Packages"; const unitThree = "Gram"; const unitThreeModified = "Kilogram"; + const unitOne = "Liter"; + const unitTwo = "Packages"; const unitFour = "Pieces"; const expectedValues = [ [], [unitOne], [unitOne, unitTwo], - [unitOne, unitTwo, unitThree], - [unitOne, unitTwo, unitThree, unitFour], - [unitOne, unitTwo, unitThreeModified, unitFour], + [unitThree, unitOne, unitTwo], + [unitThree, unitOne, unitTwo, unitFour], + [unitThreeModified, unitOne, unitTwo, unitFour], ]; expectLater( diff --git a/test/matcher/item_template_matcher.dart b/test/matcher/item_template_matcher.dart index 54433da..69cb9ec 100644 --- a/test/matcher/item_template_matcher.dart +++ b/test/matcher/item_template_matcher.dart @@ -19,10 +19,9 @@ class IsEqualToItemTemplate extends Matcher { final nameMatches = actualItem.name == expectedItem.name; final categoryMatches = actualItem.category?.id == expectedItem.category?.id; - final variantMatches = actualItem.variantKey == expectedItem.variantKey; final imagePathMatches = actualItem.imagePath == expectedItem.imagePath; - final matches = nameMatches && categoryMatches && variantMatches && imagePathMatches; + final matches = nameMatches && categoryMatches && imagePathMatches; if (!matches) { print("Expected Item: ${expectedItem.toJson()}");