diff --git a/lib/app/app.dart b/lib/app/app.dart index e52b776..2254103 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -13,7 +13,6 @@ class KoolTabApp extends StatefulWidget { } class _KoolTabAppState extends State { - @override Widget build(BuildContext context) { return MaterialApp.router( diff --git a/lib/app/app_bootstrap.dart b/lib/app/app_bootstrap.dart index a12213f..6eaebdd 100644 --- a/lib/app/app_bootstrap.dart +++ b/lib/app/app_bootstrap.dart @@ -7,10 +7,7 @@ import '../viewmodels/product_list_view_model.dart'; class AppBootstrap extends StatefulWidget { final Widget child; - const AppBootstrap({ - super.key, - required this.child, - }); + const AppBootstrap({super.key, required this.child}); @override State createState() => _AppBootstrapState(); @@ -33,4 +30,4 @@ class _AppBootstrapState extends State { Widget build(BuildContext context) { return widget.child; } -} \ No newline at end of file +} diff --git a/lib/app/router.dart b/lib/app/router.dart index f520e61..e6276b1 100644 --- a/lib/app/router.dart +++ b/lib/app/router.dart @@ -32,10 +32,7 @@ GoRouter createAppRouter(PinLockViewModel pinLockViewModel) { return null; }, routes: [ - GoRoute( - path: '/', - redirect: (context, state) => '/bar' - ), + GoRoute(path: '/', redirect: (context, state) => '/bar'), GoRoute( path: '/lock', builder: (context, state) => PinEntryView( diff --git a/lib/database/app_database.dart b/lib/database/app_database.dart index 7f0f9a1..a733848 100644 --- a/lib/database/app_database.dart +++ b/lib/database/app_database.dart @@ -46,16 +46,10 @@ class BarTabs extends Table { class TabItems extends Table { TextColumn get id => text()(); - TextColumn get tabId => text().references( - BarTabs, - #id, - onDelete: KeyAction.cascade, - )(); + TextColumn get tabId => + text().references(BarTabs, #id, onDelete: KeyAction.cascade)(); - TextColumn get productId => text().references( - Products, - #id, - )(); + TextColumn get productId => text().references(Products, #id)(); TextColumn get productName => text()(); @@ -72,8 +66,11 @@ class TabItems extends Table { @DataClassName('ClosedTabsRow') class ClosedTabs extends Table { TextColumn get id => text()(); + TextColumn get originalTabId => text()(); + TextColumn get customerName => text()(); + DateTimeColumn get closedAt => dateTime()(); @override @@ -83,10 +80,15 @@ class ClosedTabs extends Table { @DataClassName('ClosedTabItemRow') class ClosedTabItems extends Table { TextColumn get id => text()(); + TextColumn get closedTabId => text()(); + TextColumn get productId => text()(); + TextColumn get productName => text()(); + IntColumn get quantity => integer()(); + IntColumn get unitPriceInCents => integer()(); @override @@ -99,7 +101,9 @@ class AppSettingsTable extends Table { String get tableName => 'app_settings'; TextColumn get id => text()(); + BoolColumn get pinRequired => boolean().withDefault(const Constant(false))(); + TextColumn get themeMode => text().withDefault(const Constant('system'))(); @override @@ -115,7 +119,7 @@ class AppSettingsTable extends Table { ClosedTabs, ClosedTabItems, - AppSettingsTable + AppSettingsTable, ], ) class AppDatabase extends _$AppDatabase { @@ -140,12 +144,12 @@ class AppDatabase extends _$AppDatabase { await migrator.addColumn(products, products.imagePath); } - if (from < 4){ + if (from < 4) { await migrator.createTable(closedTabs); await migrator.createTable(closedTabItems); } - if (from < 5){ + if (from < 5) { await migrator.createTable(appSettingsTable); } }, @@ -160,4 +164,4 @@ class AppDatabase extends _$AppDatabase { ), ); } -} \ No newline at end of file +} diff --git a/lib/main.dart b/lib/main.dart index c5ec8e4..d2e185b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -55,9 +55,9 @@ Future main() async { DriftSettingsService(database: context.read()), ), ChangeNotifierProvider( - create: (context) => InventoryViewModel( - productService: context.read(), - )..load(), + create: (context) => + InventoryViewModel(productService: context.read()) + ..load(), ), ChangeNotifierProvider( create: (context) => ProductListViewModel( @@ -66,11 +66,10 @@ Future main() async { ), ), ChangeNotifierProvider( - create: (context) => - BarScreenViewModel( - barTabService: context.read(), - inventory: context.read(), - ), + create: (context) => BarScreenViewModel( + barTabService: context.read(), + inventory: context.read(), + ), ), ChangeNotifierProvider( create: (context) => diff --git a/lib/models/bar_tab.dart b/lib/models/bar_tab.dart index c2ed317..56cec0e 100644 --- a/lib/models/bar_tab.dart +++ b/lib/models/bar_tab.dart @@ -18,17 +18,11 @@ class BarTab { }); int get totalInCents { - return items.fold( - 0, - (total, item) => total + item.lineTotalInCents, - ); + return items.fold(0, (total, item) => total + item.lineTotalInCents); } int get itemCount { - return items.fold( - 0, - (total, item) => total + item.quantity, - ); + return items.fold(0, (total, item) => total + item.quantity); } String get formattedTotal { @@ -36,4 +30,4 @@ class BarTab { } bool get isOpen => status == 'open'; -} \ No newline at end of file +} diff --git a/lib/models/closed_tab.dart b/lib/models/closed_tab.dart index 1b8c405..07ce2dd 100644 --- a/lib/models/closed_tab.dart +++ b/lib/models/closed_tab.dart @@ -24,4 +24,4 @@ class ClosedTab { String get formattedTotal => NumberFormat.simpleCurrency().format(totalInCents / 100); -} \ No newline at end of file +} diff --git a/lib/models/closed_tab_item.dart b/lib/models/closed_tab_item.dart index 18fe7fb..86b8851 100644 --- a/lib/models/closed_tab_item.dart +++ b/lib/models/closed_tab_item.dart @@ -16,4 +16,4 @@ class ClosedTabItem { }); int get lineTotalInCents => quantity * unitPriceInCents; -} \ No newline at end of file +} diff --git a/lib/models/product.dart b/lib/models/product.dart index 2e00110..7e09b5d 100644 --- a/lib/models/product.dart +++ b/lib/models/product.dart @@ -48,4 +48,4 @@ class Product { active: active ?? this.active, ); } -} \ No newline at end of file +} diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 5c12b29..e70b85d 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -4,15 +4,9 @@ class AppSettings { final bool pinRequired; final AppThemeMode themeMode; - const AppSettings({ - required this.pinRequired, - required this.themeMode, - }); + const AppSettings({required this.pinRequired, required this.themeMode}); - AppSettings copyWith({ - bool? pinRequired, - AppThemeMode? themeMode, - }) { + AppSettings copyWith({bool? pinRequired, AppThemeMode? themeMode}) { return AppSettings( pinRequired: pinRequired ?? this.pinRequired, themeMode: themeMode ?? this.themeMode, @@ -23,4 +17,4 @@ class AppSettings { pinRequired: false, themeMode: AppThemeMode.system, ); -} \ No newline at end of file +} diff --git a/lib/models/tab_item.dart b/lib/models/tab_item.dart index adf9869..5bc194b 100644 --- a/lib/models/tab_item.dart +++ b/lib/models/tab_item.dart @@ -24,4 +24,4 @@ class TabItem { String get formattedUnitPrice { return '€${(unitPriceInCents / 100).toStringAsFixed(2)}'; } -} \ No newline at end of file +} diff --git a/lib/services/bar_tab_service.dart b/lib/services/bar_tab_service.dart index e010098..78aedb1 100644 --- a/lib/services/bar_tab_service.dart +++ b/lib/services/bar_tab_service.dart @@ -13,9 +13,7 @@ abstract class BarTabService { Future getTabById(String id); - Future createTab({ - required String customerName, - }); + Future createTab({required String customerName}); Future addProductToTab({ required String tabId, @@ -38,9 +36,7 @@ class DriftBarTabService implements BarTabService { final AppDatabase database; final _uuid = const Uuid(); - DriftBarTabService({ - required this.database, - }); + DriftBarTabService({required this.database}); TabItem _mapItemRow(TabItemRow row) { return TabItem( @@ -53,10 +49,7 @@ class DriftBarTabService implements BarTabService { ); } - BarTab _mapTabRow( - BarTabRow row, - List items, - ) { + BarTab _mapTabRow(BarTabRow row, List items) { return BarTab( id: row.id, customerName: row.customerName, @@ -81,9 +74,7 @@ class DriftBarTabService implements BarTabService { Future> _getItemsForTab(String tabId) async { final query = database.select(database.tabItems) ..where((item) => item.tabId.equals(tabId)) - ..orderBy([ - (item) => OrderingTerm.asc(item.createdAt), - ]); + ..orderBy([(item) => OrderingTerm.asc(item.createdAt)]); final rows = await query.get(); @@ -94,9 +85,7 @@ class DriftBarTabService implements BarTabService { Future> getOpenTabs() async { final query = database.select(database.barTabs) ..where((tab) => tab.status.equals('open')) - ..orderBy([ - (tab) => OrderingTerm.desc(tab.openedAt), - ]); + ..orderBy([(tab) => OrderingTerm.desc(tab.openedAt)]); final tabRows = await query.get(); @@ -128,19 +117,19 @@ class DriftBarTabService implements BarTabService { } @override - Future createTab({ - required String customerName, - }) async { + Future createTab({required String customerName}) async { final id = _uuid.v4(); - await database.into(database.barTabs).insert( - BarTabsCompanion.insert( - id: id, - customerName: customerName, - status: const Value('open'), - openedAt: DateTime.now(), - ), - ); + await database + .into(database.barTabs) + .insert( + BarTabsCompanion.insert( + id: id, + customerName: customerName, + status: const Value('open'), + openedAt: DateTime.now(), + ), + ); final tab = await getTabById(id); @@ -159,9 +148,8 @@ class DriftBarTabService implements BarTabService { await database.transaction(() async { final existingItemQuery = database.select(database.tabItems) ..where( - (item) => - item.tabId.equals(tabId) & - item.productId.equals(product.id), + (item) => + item.tabId.equals(tabId) & item.productId.equals(product.id), ); final existingItem = await existingItemQuery.getSingleOrNull(); @@ -171,25 +159,25 @@ class DriftBarTabService implements BarTabService { ..where((item) => item.id.equals(existingItem.id)); await updateQuery.write( - TabItemsCompanion( - quantity: Value(existingItem.quantity + 1), - ), + TabItemsCompanion(quantity: Value(existingItem.quantity + 1)), ); return; } - await database.into(database.tabItems).insert( - TabItemsCompanion.insert( - id: _uuid.v4(), - tabId: tabId, - productId: product.id, - productName: product.name, - quantity: 1, - unitPriceInCents: product.priceInCents, - createdAt: DateTime.now(), - ), - ); + await database + .into(database.tabItems) + .insert( + TabItemsCompanion.insert( + id: _uuid.v4(), + tabId: tabId, + productId: product.id, + productName: product.name, + quantity: 1, + unitPriceInCents: product.priceInCents, + createdAt: DateTime.now(), + ), + ); }); } @@ -209,11 +197,7 @@ class DriftBarTabService implements BarTabService { final updateQuery = database.update(database.tabItems) ..where((item) => item.id.equals(tabItemId)); - await updateQuery.write( - TabItemsCompanion( - quantity: Value(quantity), - ), - ); + await updateQuery.write(TabItemsCompanion(quantity: Value(quantity))); } @override @@ -236,26 +220,30 @@ class DriftBarTabService implements BarTabService { final closedTabId = _uuid.v4(); - await database.into(database.closedTabs).insert( - ClosedTabsCompanion.insert( - id: closedTabId, - originalTabId: tabId, - customerName: tabRow.customerName, - closedAt: DateTime.now(), - ), - ); + await database + .into(database.closedTabs) + .insert( + ClosedTabsCompanion.insert( + id: closedTabId, + originalTabId: tabId, + customerName: tabRow.customerName, + closedAt: DateTime.now(), + ), + ); for (final item in items) { - await database.into(database.closedTabItems).insert( - ClosedTabItemsCompanion.insert( - id: _uuid.v4(), - closedTabId: closedTabId, - productId: item.productId, - productName: item.productName, - quantity: item.quantity, - unitPriceInCents: item.unitPriceInCents, - ), - ); + await database + .into(database.closedTabItems) + .insert( + ClosedTabItemsCompanion.insert( + id: _uuid.v4(), + closedTabId: closedTabId, + productId: item.productId, + productName: item.productName, + quantity: item.quantity, + unitPriceInCents: item.unitPriceInCents, + ), + ); } final deleteQuery = database.delete(database.tabItems) @@ -268,9 +256,7 @@ class DriftBarTabService implements BarTabService { @override Future> getClosedTabs() async { final query = database.select(database.closedTabs) - ..orderBy([ - (tab) => OrderingTerm.desc(tab.closedAt), - ]); + ..orderBy([(tab) => OrderingTerm.desc(tab.closedAt)]); final closedTabRows = await query.get(); @@ -282,15 +268,17 @@ class DriftBarTabService implements BarTabService { final itemRows = await itemsQuery.get(); - closedTabs.add(ClosedTab( - id: row.id, - originalTabId: row.originalTabId, - customerName: row.customerName, - closedAt: row.closedAt, - items: itemRows.map(_mapClosedItemRow).toList(), - )); + closedTabs.add( + ClosedTab( + id: row.id, + originalTabId: row.originalTabId, + customerName: row.customerName, + closedAt: row.closedAt, + items: itemRows.map(_mapClosedItemRow).toList(), + ), + ); } return closedTabs; } -} \ No newline at end of file +} diff --git a/lib/services/product_service.dart b/lib/services/product_service.dart index 58ab766..87dcb67 100644 --- a/lib/services/product_service.dart +++ b/lib/services/product_service.dart @@ -23,6 +23,7 @@ abstract class ProductService { Future deleteProduct(String id); Future decreaseStock(String productId, int amount); + Future increaseStock(String productId, int amount); } @@ -30,9 +31,7 @@ class DriftProductService implements ProductService { final AppDatabase database; final _uuid = const Uuid(); - DriftProductService({ - required this.database, - }); + DriftProductService({required this.database}); Product _mapRowToProduct(ProductRow row) { return Product( @@ -51,9 +50,7 @@ class DriftProductService implements ProductService { Future> getProducts() async { final query = database.select(database.products) ..where((product) => product.active.equals(true)) - ..orderBy([ - (product) => OrderingTerm.asc(product.name), - ]); + ..orderBy([(product) => OrderingTerm.asc(product.name)]); final rows = await query.get(); @@ -83,17 +80,19 @@ class DriftProductService implements ProductService { required int priceInCents, required String? imagePath, }) async { - await database.into(database.products).insert( - ProductsCompanion.insert( - id: _uuid.v4(), - name: name, - category: category, - stockQuantity: stockQuantity, - lowStockThreshold: lowStockThreshold, - priceInCents: priceInCents, - imagePath: Value(imagePath), - ), - ); + await database + .into(database.products) + .insert( + ProductsCompanion.insert( + id: _uuid.v4(), + name: name, + category: category, + stockQuantity: stockQuantity, + lowStockThreshold: lowStockThreshold, + priceInCents: priceInCents, + imagePath: Value(imagePath), + ), + ); } @override @@ -135,9 +134,7 @@ class DriftProductService implements ProductService { } await updateProduct( - product.copyWith( - stockQuantity: product.stockQuantity - amount, - ), + product.copyWith(stockQuantity: product.stockQuantity - amount), ); } @@ -150,10 +147,7 @@ class DriftProductService implements ProductService { } await updateProduct( - product.copyWith( - stockQuantity: product.stockQuantity + amount, - ), + product.copyWith(stockQuantity: product.stockQuantity + amount), ); } - -} \ No newline at end of file +} diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index 5fe3963..ffa2041 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -19,7 +19,7 @@ class DriftSettingsService implements SettingsService { return AppSettings( pinRequired: row.pinRequired, themeMode: AppThemeMode.values.firstWhere( - (mode) => mode.name == row.themeMode, + (mode) => mode.name == row.themeMode, orElse: () => AppThemeMode.system, ), ); @@ -39,12 +39,14 @@ class DriftSettingsService implements SettingsService { @override Future saveSettings(AppSettings settings) async { - await database.into(database.appSettingsTable).insertOnConflictUpdate( - AppSettingsTableCompanion.insert( - id: _settingsId, - pinRequired: Value(settings.pinRequired), - themeMode: Value(settings.themeMode.name), - ), - ); + await database + .into(database.appSettingsTable) + .insertOnConflictUpdate( + AppSettingsTableCompanion.insert( + id: _settingsId, + pinRequired: Value(settings.pinRequired), + themeMode: Value(settings.themeMode.name), + ), + ); } -} \ No newline at end of file +} diff --git a/lib/theme.dart b/lib/theme.dart index a237364..ec430dd 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -253,10 +253,7 @@ final ThemeData darkTheme = ThemeData( fontWeight: FontWeight.w800, letterSpacing: -0.2, ), - titleMedium: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w700, - ), + titleMedium: TextStyle(color: Colors.white, fontWeight: FontWeight.w700), bodyLarge: TextStyle(color: Colors.white70, fontSize: 16, height: 1.5), bodyMedium: TextStyle(color: Colors.white60, height: 1.4), bodySmall: TextStyle(color: Colors.white38, height: 1.3), @@ -311,9 +308,17 @@ final ThemeData neoBrutalDarkTheme = ThemeData( fontWeight: FontWeight.w800, color: Colors.white, ), - bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + bodyLarge: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white, + ), bodyMedium: TextStyle(fontSize: 14, color: Colors.white70), - bodySmall: TextStyle(fontSize: 12, color: Colors.white54, fontWeight: FontWeight.w600), + bodySmall: TextStyle( + fontSize: 12, + color: Colors.white54, + fontWeight: FontWeight.w600, + ), ), appBarTheme: const AppBarTheme( @@ -331,7 +336,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData( cardTheme: CardThemeData( color: _nbSurface, elevation: 0, - margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: AppSpacing.sm), + margin: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + vertical: AppSpacing.sm, + ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: const BorderSide(color: Colors.white, width: 3), @@ -380,7 +388,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData( inputDecorationTheme: InputDecorationTheme( filled: true, fillColor: _nbSurface, - hintStyle: const TextStyle(color: Colors.white38, fontWeight: FontWeight.w600), + hintStyle: const TextStyle( + color: Colors.white38, + fontWeight: FontWeight.w600, + ), contentPadding: const EdgeInsets.all(18), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), @@ -408,7 +419,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData( fontSize: 20, fontWeight: FontWeight.w900, ), - contentTextStyle: const TextStyle(color: Colors.white70, fontWeight: FontWeight.w600), + contentTextStyle: const TextStyle( + color: Colors.white70, + fontWeight: FontWeight.w600, + ), ), floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -428,7 +442,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData( side: const BorderSide(color: Colors.white, width: 3), ), behavior: SnackBarBehavior.floating, - contentTextStyle: const TextStyle(color: Colors.white, fontWeight: FontWeight.w600), + contentTextStyle: const TextStyle( + color: Colors.white, + fontWeight: FontWeight.w600, + ), ), dividerTheme: const DividerThemeData(color: Colors.white, thickness: 3), @@ -645,7 +662,11 @@ final ThemeData lightTheme = ThemeData( contentTextStyle: const TextStyle(color: Colors.white), ), - dividerTheme: const DividerThemeData(color: _outlineL, thickness: 1, space: 1), + dividerTheme: const DividerThemeData( + color: _outlineL, + thickness: 1, + space: 1, + ), chipTheme: ChipThemeData( backgroundColor: _surfaceRaisedL, @@ -673,13 +694,10 @@ final ThemeData lightTheme = ThemeData( fontWeight: FontWeight.w800, letterSpacing: -0.2, ), - titleMedium: TextStyle( - color: Colors.black87, - fontWeight: FontWeight.w700, - ), + titleMedium: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700), bodyLarge: TextStyle(color: Colors.black54, fontSize: 16, height: 1.5), bodyMedium: TextStyle(color: Colors.black45, height: 1.4), bodySmall: TextStyle(color: Colors.black38, height: 1.3), labelLarge: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700), ), -); \ No newline at end of file +); diff --git a/lib/utils/app_updater.dart b/lib/utils/app_updater.dart index 2e26be5..38ae91c 100644 --- a/lib/utils/app_updater.dart +++ b/lib/utils/app_updater.dart @@ -13,9 +13,7 @@ class UpdateChecker { _hasChecked = true; - final updater = AppUpdateUtil( - serverUrl: "https://updater.brammie15.dev", - ); + final updater = AppUpdateUtil(serverUrl: "https://updater.brammie15.dev"); try { final update = await updater.checkForUpdate(); @@ -35,10 +33,7 @@ class UpdateChecker { } } - static void _showUpdateDialog( - BuildContext context, - UpdateInfo update, - ) { + static void _showUpdateDialog(BuildContext context, UpdateInfo update) { showDialog( context: context, barrierDismissible: !update.mandatory, @@ -80,64 +75,40 @@ Future _downloadAndInstall(UpdateInfo update) async { : "https://updater.brammie15.dev${update.download}"; OtaUpdate() .execute( - url, - destinationFilename: "update.apk", - sha256checksum: update.sha256, - ) - .listen( - (OtaEvent event) { + url, + destinationFilename: "update.apk", + sha256checksum: update.sha256, + ) + .listen((OtaEvent event) { + debugPrint("OTA status: ${event.status}"); - debugPrint( - "OTA status: ${event.status}", - ); + debugPrint("OTA value: ${event.value}"); - debugPrint( - "OTA value: ${event.value}", - ); + switch (event.status) { + case OtaStatus.DOWNLOADING: + final progress = double.tryParse(event.value ?? "0") ?? 0; - switch(event.status) { + debugPrint("Downloading ${progress.toStringAsFixed(0)}%"); - case OtaStatus.DOWNLOADING: - final progress = - double.tryParse(event.value ?? "0") ?? 0; + break; - debugPrint( - "Downloading ${progress.toStringAsFixed(0)}%", - ); + case OtaStatus.INSTALLING: + debugPrint("Installing update"); + break; - break; + case OtaStatus.INSTALLATION_ERROR: + debugPrint("Installation error: ${event.value}"); + break; + case OtaStatus.DOWNLOAD_ERROR: + debugPrint("Download error: ${event.value}"); + break; - case OtaStatus.INSTALLING: - debugPrint( - "Installing update", - ); - break; - - - case OtaStatus.INSTALLATION_ERROR: - debugPrint( - "Installation error: ${event.value}", - ); - break; - - - case OtaStatus.DOWNLOAD_ERROR: - debugPrint( - "Download error: ${event.value}", - ); - break; - - - default: - break; - } - }, - ); - + default: + break; + } + }); } catch (e) { - debugPrint( - "OTA update failed: $e", - ); + debugPrint("OTA update failed: $e"); } -} \ No newline at end of file +} diff --git a/lib/viewmodels/bar_screen_view_model.dart b/lib/viewmodels/bar_screen_view_model.dart index 32eb4cd..3d05758 100644 --- a/lib/viewmodels/bar_screen_view_model.dart +++ b/lib/viewmodels/bar_screen_view_model.dart @@ -10,10 +10,7 @@ class BarScreenViewModel extends ChangeNotifier { final BarTabService barTabService; final InventoryViewModel inventory; - BarScreenViewModel({ - required this.barTabService, - required this.inventory, - }); + BarScreenViewModel({required this.barTabService, required this.inventory}); List _tabs = []; String? _selectedTabId; @@ -91,10 +88,7 @@ class BarScreenViewModel extends ChangeNotifier { throw Exception('Product is out of stock.'); } - await barTabService.addProductToTab( - tabId: tab.id, - product: product, - ); + await barTabService.addProductToTab(tabId: tab.id, product: product); await inventory.decreaseStock(product.id, 1); diff --git a/lib/viewmodels/history_view_model.dart b/lib/viewmodels/history_view_model.dart index fccd861..39f8d28 100644 --- a/lib/viewmodels/history_view_model.dart +++ b/lib/viewmodels/history_view_model.dart @@ -6,9 +6,7 @@ import '../services/bar_tab_service.dart'; class HistoryViewModel extends ChangeNotifier { final BarTabService barTabService; - HistoryViewModel({ - required this.barTabService, - }); + HistoryViewModel({required this.barTabService}); List _closedTabs = []; bool _isLoading = false; @@ -20,8 +18,11 @@ class HistoryViewModel extends ChangeNotifier { if (_searchQuery.isEmpty) return _closedTabs; return _closedTabs - .where((tab) => - tab.customerName.toLowerCase().contains(_searchQuery.toLowerCase())) + .where( + (tab) => tab.customerName.toLowerCase().contains( + _searchQuery.toLowerCase(), + ), + ) .toList(); } @@ -59,4 +60,4 @@ class HistoryViewModel extends ChangeNotifier { _searchQuery = query; notifyListeners(); } -} \ No newline at end of file +} diff --git a/lib/viewmodels/inventory_view_model.dart b/lib/viewmodels/inventory_view_model.dart index 4834d67..803a180 100644 --- a/lib/viewmodels/inventory_view_model.dart +++ b/lib/viewmodels/inventory_view_model.dart @@ -6,9 +6,7 @@ import '../services/product_service.dart'; class InventoryViewModel extends ChangeNotifier { final ProductService productService; - InventoryViewModel({ - required this.productService, - }); + InventoryViewModel({required this.productService}); List _products = []; @@ -19,43 +17,31 @@ class InventoryViewModel extends ChangeNotifier { notifyListeners(); } - Future decreaseStock( - String productId, - int amount, - ) async { + Future decreaseStock(String productId, int amount) async { await productService.decreaseStock(productId, amount); - final index = _products.indexWhere( - (product) => product.id == productId, - ); + final index = _products.indexWhere((product) => product.id == productId); if (index != -1) { _products[index] = _products[index].copyWith( - stockQuantity: - _products[index].stockQuantity - amount, + stockQuantity: _products[index].stockQuantity - amount, ); } notifyListeners(); } - Future increaseStock( - String productId, - int amount, - ) async { + Future increaseStock(String productId, int amount) async { await productService.increaseStock(productId, amount); - final index = _products.indexWhere( - (product) => product.id == productId, - ); + final index = _products.indexWhere((product) => product.id == productId); if (index != -1) { _products[index] = _products[index].copyWith( - stockQuantity: - _products[index].stockQuantity + amount, + stockQuantity: _products[index].stockQuantity + amount, ); } notifyListeners(); } -} \ No newline at end of file +} diff --git a/lib/viewmodels/pin_lock_view_model.dart b/lib/viewmodels/pin_lock_view_model.dart index 67aa0ef..2a7163e 100644 --- a/lib/viewmodels/pin_lock_view_model.dart +++ b/lib/viewmodels/pin_lock_view_model.dart @@ -131,4 +131,4 @@ class PinLockViewModel extends ChangeNotifier { _isUnlocked = false; notifyListeners(); } -} \ No newline at end of file +} diff --git a/lib/viewmodels/product_list_view_model.dart b/lib/viewmodels/product_list_view_model.dart index 242c8d1..febecfb 100644 --- a/lib/viewmodels/product_list_view_model.dart +++ b/lib/viewmodels/product_list_view_model.dart @@ -8,10 +8,7 @@ class ProductListViewModel extends ChangeNotifier { final ProductService productService; final InventoryViewModel inventory; - ProductListViewModel({ - required this.productService, - required this.inventory, - }); + ProductListViewModel({required this.productService, required this.inventory}); static const List _defaultCategories = [ 'Bier', @@ -120,4 +117,4 @@ class ProductListViewModel extends ChangeNotifier { return categories; } -} \ No newline at end of file +} diff --git a/lib/viewmodels/settings_view_model.dart b/lib/viewmodels/settings_view_model.dart index 4a8a7bc..6d3598a 100644 --- a/lib/viewmodels/settings_view_model.dart +++ b/lib/viewmodels/settings_view_model.dart @@ -24,8 +24,11 @@ class SettingsViewModel extends ChangeNotifier { bool get checkingForUpdates => _checkingForUpdates; AppSettings get settings => _settings; + bool get isLoading => _isLoading; + bool get hasLoaded => _hasLoaded; + String? get errorMessage => _errorMessage; Future ensureLoaded() async { @@ -66,10 +69,9 @@ class SettingsViewModel extends ChangeNotifier { } Future installUpdate( - UpdateInfo update, { - void Function(double progress)? onProgress, - }) async { - + UpdateInfo update, { + void Function(double progress)? onProgress, + }) async { final url = update.download.startsWith("http") ? update.download : "https://updater.brammie15.dev${update.download}"; @@ -83,28 +85,20 @@ class SettingsViewModel extends ChangeNotifier { ); await for (final event in stream) { - - debugPrint( - "OTA: ${event.status} ${event.value}", - ); + debugPrint("OTA: ${event.status} ${event.value}"); if (event.status == OtaStatus.DOWNLOADING) { - final progress = - double.tryParse(event.value ?? "0") ?? 0; + final progress = double.tryParse(event.value ?? "0") ?? 0; onProgress?.call(progress / 100); } if (event.status == OtaStatus.DOWNLOAD_ERROR) { - throw Exception( - "Download failed: ${event.value}", - ); + throw Exception("Download failed: ${event.value}"); } if (event.status == OtaStatus.INSTALLATION_ERROR) { - throw Exception( - "Installation failed: ${event.value}", - ); + throw Exception("Installation failed: ${event.value}"); } } } @@ -131,4 +125,4 @@ class SettingsViewModel extends ChangeNotifier { notifyListeners(); } } -} \ No newline at end of file +} diff --git a/lib/views/bar_screen_view.dart b/lib/views/bar_screen_view.dart index 61257aa..e0d001a 100644 --- a/lib/views/bar_screen_view.dart +++ b/lib/views/bar_screen_view.dart @@ -22,7 +22,6 @@ class BarScreenView extends StatefulWidget { } class _BarScreenViewState extends State { - @override void initState() { super.initState(); diff --git a/lib/views/dialogs/close_tab_dialog.dart b/lib/views/dialogs/close_tab_dialog.dart index b446092..c3c1302 100644 --- a/lib/views/dialogs/close_tab_dialog.dart +++ b/lib/views/dialogs/close_tab_dialog.dart @@ -44,4 +44,4 @@ Future confirmCloseTab(BuildContext context) async { if (confirmed != true) return; await viewModel.closeSelectedTab(); -} \ No newline at end of file +} diff --git a/lib/views/dialogs/new_tab_dialog.dart b/lib/views/dialogs/new_tab_dialog.dart index 692fe71..20371ce 100644 --- a/lib/views/dialogs/new_tab_dialog.dart +++ b/lib/views/dialogs/new_tab_dialog.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:kooltab2/viewmodels/bar_screen_view_model.dart'; import 'package:provider/provider.dart'; - Future showNewTabDialog(BuildContext context) async { final controller = TextEditingController(); @@ -14,9 +13,7 @@ Future showNewTabDialog(BuildContext context) async { content: TextField( controller: controller, autofocus: true, - decoration: const InputDecoration( - labelText: 'Customer / group name', - ), + decoration: const InputDecoration(labelText: 'Customer / group name'), onSubmitted: (value) { Navigator.of(dialogContext).pop(value); }, @@ -43,4 +40,4 @@ Future showNewTabDialog(BuildContext context) async { if (!context.mounted) return; await context.read().createTab(name.trim()); -} \ No newline at end of file +} diff --git a/lib/views/history_screen_view.dart b/lib/views/history_screen_view.dart index 0133ebd..39323ca 100644 --- a/lib/views/history_screen_view.dart +++ b/lib/views/history_screen_view.dart @@ -52,9 +52,12 @@ class _HistoryScreenViewState extends State with RouteAware { appBar: AppBar( title: Row( children: [ - IconButton(onPressed: (){ - context.go('/bar'); - }, icon: const Icon(Icons.arrow_back)), + IconButton( + onPressed: () { + context.go('/bar'); + }, + icon: const Icon(Icons.arrow_back), + ), const SizedBox(width: 5), const Text('Tab History'), ], @@ -118,15 +121,15 @@ class _HistoryScreenViewState extends State with RouteAware { child: viewModel.closedTabs.isEmpty ? _EmptyState() : ListView.separated( - padding: const EdgeInsets.fromLTRB(20, 8, 20, 20), - itemCount: viewModel.closedTabs.length, - separatorBuilder: (_, _) => const SizedBox(height: 10), - itemBuilder: (context, index) { - final closedTab = viewModel.closedTabs[index]; + padding: const EdgeInsets.fromLTRB(20, 8, 20, 20), + itemCount: viewModel.closedTabs.length, + separatorBuilder: (_, _) => const SizedBox(height: 10), + itemBuilder: (context, index) { + final closedTab = viewModel.closedTabs[index]; - return ClosedTabCard(closedTab: closedTab); - }, - ), + return ClosedTabCard(closedTab: closedTab); + }, + ), ), ], ); diff --git a/lib/views/pin_lock_view.dart b/lib/views/pin_lock_view.dart index 30a9afb..17b5e9a 100644 --- a/lib/views/pin_lock_view.dart +++ b/lib/views/pin_lock_view.dart @@ -14,11 +14,7 @@ class PinEntryView extends StatefulWidget { final PinEntryMode mode; final VoidCallback? onSuccess; - const PinEntryView({ - super.key, - required this.mode, - this.onSuccess, - }); + const PinEntryView({super.key, required this.mode, this.onSuccess}); @override State createState() => _PinEntryViewState(); @@ -167,9 +163,9 @@ class _PinEntryViewState extends State { height: 20, child: _localError != null ? Text( - _localError!, - style: TextStyle(color: scheme.error, fontSize: 13), - ) + _localError!, + style: TextStyle(color: scheme.error, fontSize: 13), + ) : const SizedBox.shrink(), ), const Spacer(flex: 2), @@ -210,7 +206,9 @@ class _PinDots extends StatelessWidget { shape: BoxShape.circle, color: isFilled ? scheme.primary : Colors.transparent, border: Border.all( - color: isFilled ? scheme.primary : scheme.onSurface.withValues(alpha: 0.3), + color: isFilled + ? scheme.primary + : scheme.onSurface.withValues(alpha: 0.3), width: 1.4, ), ), @@ -314,18 +312,18 @@ class _KeypadButton extends StatelessWidget { child: icon != null ? Icon(icon, color: scheme.onSurface.withValues(alpha: 0.8)) : Text( - label!, - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.w600, - color: onTap == null - ? scheme.onSurface.withValues(alpha: 0.3) - : scheme.onSurface, - ), - ), + label!, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w600, + color: onTap == null + ? scheme.onSurface.withValues(alpha: 0.3) + : scheme.onSurface, + ), + ), ), ), ), ); } -} \ No newline at end of file +} diff --git a/lib/views/product_form_view.dart b/lib/views/product_form_view.dart index 7238635..9095d6a 100644 --- a/lib/views/product_form_view.dart +++ b/lib/views/product_form_view.dart @@ -13,10 +13,7 @@ import '../viewmodels/product_list_view_model.dart'; class ProductFormView extends StatefulWidget { final String? productId; - const ProductFormView({ - super.key, - this.productId, - }); + const ProductFormView({super.key, this.productId}); bool get isEditing => productId != null; @@ -60,11 +57,9 @@ class _ProductFormViewState extends State { if (!mounted) return; if (product == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Product not found.'), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Product not found.'))); context.go('/products'); return; @@ -102,7 +97,8 @@ class _ProductFormViewState extends State { } final extension = path.extension(pickedFile.path); - final fileName = 'product_${DateTime.now().millisecondsSinceEpoch}$extension'; + final fileName = + 'product_${DateTime.now().millisecondsSinceEpoch}$extension'; final newPath = path.join(imagesDirectory.path, fileName); final copiedFile = await File(pickedFile.path).copy(newPath); @@ -139,19 +135,15 @@ class _ProductFormViewState extends State { if (!_formKey.currentState!.validate()) return; if (_imagePath == null || _imagePath!.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Choose a product image.'), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Choose a product image.'))); return; } if (_selectedCategory == null) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Please select a category.'), - ), + const SnackBar(content: Text('Please select a category.')), ); return; } @@ -239,43 +231,38 @@ class _ProductFormViewState extends State { height: 220, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), - border: Border.all( - color: Theme.of(context).colorScheme.outline, - ), + border: Border.all(color: Theme.of(context).colorScheme.outline), ), clipBehavior: Clip.antiAlias, child: hasImage ? Stack( - fit: StackFit.expand, - children: [ - Image.file( - File(_imagePath!), - fit: BoxFit.fitHeight, - ), - Positioned( - right: 12, - bottom: 12, - child: FilledButton.icon( - onPressed: _pickImage, - icon: const Icon(Icons.image), - label: const Text('Change image'), - ), - ), - ], - ) + fit: StackFit.expand, + children: [ + Image.file(File(_imagePath!), fit: BoxFit.fitHeight), + Positioned( + right: 12, + bottom: 12, + child: FilledButton.icon( + onPressed: _pickImage, + icon: const Icon(Icons.image), + label: const Text('Change image'), + ), + ), + ], + ) : Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.add_photo_alternate_outlined, size: 48), - const SizedBox(height: 12), - Text( - 'Choose product image', - style: Theme.of(context).textTheme.titleMedium, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.add_photo_alternate_outlined, size: 48), + const SizedBox(height: 12), + Text( + 'Choose product image', + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ), ), - ], - ), - ), ), ); } @@ -301,151 +288,149 @@ class _ProductFormViewState extends State { ), resizeToAvoidBottomInset: false, body: _isLoading - ? const Center( - child: CircularProgressIndicator(), - ) + ? const Center(child: CircularProgressIndicator()) : Center( - child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 720), - child: Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.all(24), - children: [ - _buildImagePicker(context), - const SizedBox(height: 24), - TextFormField( - controller: _nameController, - decoration: const InputDecoration( - labelText: 'Product name', - border: OutlineInputBorder(), - ), - textInputAction: TextInputAction.next, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return 'Enter a product name.'; - } + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 720), + child: Form( + key: _formKey, + child: ListView( + padding: const EdgeInsets.all(24), + children: [ + _buildImagePicker(context), + const SizedBox(height: 24), + TextFormField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Product name', + border: OutlineInputBorder(), + ), + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Enter a product name.'; + } - return null; - }, - ), - const SizedBox(height: 16), - Consumer( - builder: (context, viewModel, child) { - return LayoutBuilder( - builder: (context, constraints) { - return DropdownMenu( - width: constraints.maxWidth, - initialSelection: _selectedCategory, - enableFilter: true, - enableSearch: true, - controller: _categoryController, - requestFocusOnTap: true, - label: const Text('Category'), - hintText: 'Select a category', - dropdownMenuEntries: viewModel.categories - .map( - (category) => DropdownMenuEntry( - value: category, - label: category, - ), - ) - .toList(), - onSelected: (value) { - setState(() { - _selectedCategory = value; - }); - }, - ); - }, - ); - }, - ), - const SizedBox(height: 16), - TextFormField( - controller: _priceController, - decoration: const InputDecoration( - labelText: 'Price', - prefixText: '€ ', - border: OutlineInputBorder(), - ), - keyboardType: const TextInputType.numberWithOptions( - decimal: true, - ), - textInputAction: TextInputAction.next, - validator: (value) { - if (value == null || value.trim().isEmpty) { - return 'Enter a price.'; - } + return null; + }, + ), + const SizedBox(height: 16), + Consumer( + builder: (context, viewModel, child) { + return LayoutBuilder( + builder: (context, constraints) { + return DropdownMenu( + width: constraints.maxWidth, + initialSelection: _selectedCategory, + enableFilter: true, + enableSearch: true, + controller: _categoryController, + requestFocusOnTap: true, + label: const Text('Category'), + hintText: 'Select a category', + dropdownMenuEntries: viewModel.categories + .map( + (category) => DropdownMenuEntry( + value: category, + label: category, + ), + ) + .toList(), + onSelected: (value) { + setState(() { + _selectedCategory = value; + }); + }, + ); + }, + ); + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _priceController, + decoration: const InputDecoration( + labelText: 'Price', + prefixText: '€ ', + border: OutlineInputBorder(), + ), + keyboardType: const TextInputType.numberWithOptions( + decimal: true, + ), + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null || value.trim().isEmpty) { + return 'Enter a price.'; + } - final normalized = value.replaceAll(',', '.'); - final price = double.tryParse(normalized); + final normalized = value.replaceAll(',', '.'); + final price = double.tryParse(normalized); - if (price == null || price < 0) { - return 'Enter a valid price.'; - } + if (price == null || price < 0) { + return 'Enter a valid price.'; + } - return null; - }, - ), - const SizedBox(height: 16), - TextFormField( - controller: _stockController, - decoration: const InputDecoration( - labelText: 'Current stock', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - textInputAction: TextInputAction.next, - validator: (value) { - final number = int.tryParse(value ?? ''); + return null; + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _stockController, + decoration: const InputDecoration( + labelText: 'Current stock', + border: OutlineInputBorder(), + ), + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + validator: (value) { + final number = int.tryParse(value ?? ''); - if (number == null || number < 0) { - return 'Enter a valid stock amount.'; - } + if (number == null || number < 0) { + return 'Enter a valid stock amount.'; + } - return null; - }, - ), - const SizedBox(height: 16), - TextFormField( - controller: _lowStockController, - decoration: const InputDecoration( - labelText: 'Low stock warning threshold', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.number, - validator: (value) { - final number = int.tryParse(value ?? ''); + return null; + }, + ), + const SizedBox(height: 16), + TextFormField( + controller: _lowStockController, + decoration: const InputDecoration( + labelText: 'Low stock warning threshold', + border: OutlineInputBorder(), + ), + keyboardType: TextInputType.number, + validator: (value) { + final number = int.tryParse(value ?? ''); - if (number == null || number < 0) { - return 'Enter a valid threshold.'; - } + if (number == null || number < 0) { + return 'Enter a valid threshold.'; + } - return null; - }, - ), - const SizedBox(height: 24), - FilledButton.icon( - onPressed: _isSaving ? null : _save, - icon: _isSaving - ? const SizedBox( - width: 18, - height: 18, - child: CircularProgressIndicator( - strokeWidth: 2, - ), - ) - : const Icon(Icons.save), - label: Text( - widget.isEditing ? 'Save changes' : 'Add product', + return null; + }, + ), + const SizedBox(height: 24), + FilledButton.icon( + onPressed: _isSaving ? null : _save, + icon: _isSaving + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + : const Icon(Icons.save), + label: Text( + widget.isEditing ? 'Save changes' : 'Add product', + ), + ), + ], ), ), - ], + ), ), - ), - ), - ), ); } -} \ No newline at end of file +} diff --git a/lib/views/settings_view.dart b/lib/views/settings_view.dart index 42eb7ee..09718d2 100644 --- a/lib/views/settings_view.dart +++ b/lib/views/settings_view.dart @@ -46,7 +46,7 @@ class _SettingsScreenViewState extends State { } Future _loadVersion() async { - final version = await currentVersion(); + final version = await currentVersion(); if (!mounted) return; @@ -87,7 +87,9 @@ class _SettingsScreenViewState extends State { void _showError(String message) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message))); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); } Future _enablePin() async { @@ -168,8 +170,10 @@ class _SettingsScreenViewState extends State { ), body: Builder( builder: (context) { - final isLoading = settingsViewModel.isLoading || pinLockViewModel.isLoading; - final hasLoaded = settingsViewModel.hasLoaded && pinLockViewModel.hasLoaded; + final isLoading = + settingsViewModel.isLoading || pinLockViewModel.isLoading; + final hasLoaded = + settingsViewModel.hasLoaded && pinLockViewModel.hasLoaded; if (isLoading && !hasLoaded) { return const Center( @@ -231,7 +235,8 @@ class _SettingsScreenViewState extends State { AppThemeMode.light => 'Light', AppThemeMode.dark => 'Dark', }), - onChanged: (value) => Navigator.pop(context, value), + onChanged: (value) => + Navigator.pop(context, value), ); }).toList(), ), @@ -265,14 +270,10 @@ class _SettingsScreenViewState extends State { child: Center( child: Text( 'Version $_appVersion', - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith( - color: Theme.of(context) - .colorScheme - .onSurface - .withValues(alpha: 0.5), + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurface.withValues(alpha: 0.5), ), ), ), @@ -306,9 +307,9 @@ class _SettingsScreenViewState extends State { } catch (e) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Update check failed: $e')), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Update check failed: $e'))); } } @@ -349,9 +350,9 @@ class _SettingsScreenViewState extends State { } catch (e) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Update failed: $e")), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text("Update failed: $e"))); } }, child: const Text("Update"), @@ -391,7 +392,9 @@ class _SettingsSection extends StatelessWidget { decoration: BoxDecoration( color: scheme.onSurface.withValues(alpha: 0.04), borderRadius: BorderRadius.circular(14), - border: Border.all(color: scheme.onSurface.withValues(alpha: 0.06)), + border: Border.all( + color: scheme.onSurface.withValues(alpha: 0.06), + ), ), clipBehavior: Clip.antiAlias, child: Column(children: children), @@ -427,12 +430,19 @@ class _SettingsTile extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ - Icon(icon, size: 22, color: scheme.onSurface.withValues(alpha: 0.7)), + Icon( + icon, + size: 22, + color: scheme.onSurface.withValues(alpha: 0.7), + ), const SizedBox(width: 14), Expanded( child: Text( title, - style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), + style: TextStyle( + fontWeight: FontWeight.w600, + color: scheme.onSurface, + ), ), ), if (subtitle != null) ...[ @@ -440,7 +450,10 @@ class _SettingsTile extends StatelessWidget { const SizedBox(width: 4), ], if (onTap != null) - Icon(Icons.chevron_right_rounded, color: scheme.onSurface.withValues(alpha: 0.3)), + Icon( + Icons.chevron_right_rounded, + color: scheme.onSurface.withValues(alpha: 0.3), + ), ], ), ), @@ -475,7 +488,10 @@ class _SettingsSwitchTile extends StatelessWidget { Expanded( child: Text( title, - style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), + style: TextStyle( + fontWeight: FontWeight.w600, + color: scheme.onSurface, + ), ), ), Switch(value: value, onChanged: onChanged), @@ -483,4 +499,4 @@ class _SettingsSwitchTile extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/views/widgets/closed_tab_card.dart b/lib/views/widgets/closed_tab_card.dart index 4c61e96..ec09841 100644 --- a/lib/views/widgets/closed_tab_card.dart +++ b/lib/views/widgets/closed_tab_card.dart @@ -98,7 +98,7 @@ class _ClosedTabCardState extends State { const Divider(height: 1), const SizedBox(height: 8), ...closedTab.items.map( - (item) => _ClosedTabItemRow(item: item), + (item) => _ClosedTabItemRow(item: item), ), ], ), @@ -120,10 +120,12 @@ class _ClosedTabItemRow extends StatelessWidget { @override Widget build(BuildContext context) { - final unitPrice = - NumberFormat.simpleCurrency().format(item.unitPriceInCents / 100); - final lineTotal = - NumberFormat.simpleCurrency().format(item.lineTotalInCents / 100); + final unitPrice = NumberFormat.simpleCurrency().format( + item.unitPriceInCents / 100, + ); + final lineTotal = NumberFormat.simpleCurrency().format( + item.lineTotalInCents / 100, + ); final scheme = Theme.of(context).colorScheme; return Padding( @@ -135,7 +137,10 @@ class _ClosedTabItemRow extends StatelessWidget { item.productName, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), + style: TextStyle( + fontWeight: FontWeight.w600, + color: scheme.onSurface, + ), ), ), Text( @@ -148,11 +153,14 @@ class _ClosedTabItemRow extends StatelessWidget { child: Text( lineTotal, textAlign: TextAlign.end, - style: TextStyle(fontWeight: FontWeight.w700, color: scheme.onSurface), + style: TextStyle( + fontWeight: FontWeight.w700, + color: scheme.onSurface, + ), ), ), ], ), ); } -} \ No newline at end of file +} diff --git a/lib/views/widgets/product_tile.dart b/lib/views/widgets/product_tile.dart index e70b2dd..19f3f41 100644 --- a/lib/views/widgets/product_tile.dart +++ b/lib/views/widgets/product_tile.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:kooltab2/models/product.dart'; - class ProductTile extends StatelessWidget { final Product product; final bool enabled; @@ -33,7 +32,7 @@ class ProductTile extends StatelessWidget { final outOfStock = product.stockQuantity <= 0; final lowStock = product.stockQuantity > 0 && - product.stockQuantity <= product.lowStockThreshold; // adjust name + product.stockQuantity <= product.lowStockThreshold; // adjust name final borderColor = outOfStock ? scheme.error.withValues(alpha: 0.7) @@ -62,16 +61,16 @@ class ProductTile extends StatelessWidget { opacity: outOfStock ? 0.35 : (enabled ? 1 : 0.4), child: _hasImage ? Image.file( - File(product.imagePath!), - fit: BoxFit.scaleDown, - ) + File(product.imagePath!), + fit: BoxFit.scaleDown, + ) : Center( - child: Icon( - Icons.image_not_supported_outlined, - size: 34, - color: scheme.onSurface.withValues(alpha: 0.3), - ), - ), + child: Icon( + Icons.image_not_supported_outlined, + size: 34, + color: scheme.onSurface.withValues(alpha: 0.3), + ), + ), ), if (_hasImage) @@ -95,9 +94,7 @@ class ProductTile extends StatelessWidget { Positioned( top: 10, right: 10, - child: _StockBadge( - product: product, - ), + child: _StockBadge(product: product), ), // Out of stock overlay @@ -134,9 +131,7 @@ class ProductTile extends StatelessWidget { class _StockBadge extends StatelessWidget { final Product product; - const _StockBadge({ - required this.product, - }); + const _StockBadge({required this.product}); @override Widget build(BuildContext context) { @@ -150,10 +145,7 @@ class _StockBadge extends StatelessWidget { product.stockQuantity <= product.lowStockThreshold; // adjust name return Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: low ? Colors.amber.withValues(alpha: 0.9) @@ -170,4 +162,4 @@ class _StockBadge extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/views/widgets/slide_confirm.dart b/lib/views/widgets/slide_confirm.dart index 7d7729b..1175a96 100644 --- a/lib/views/widgets/slide_confirm.dart +++ b/lib/views/widgets/slide_confirm.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; - class SlideConfirm extends StatefulWidget { final VoidCallback onConfirmed; @@ -95,4 +94,4 @@ class _SlideConfirmState extends State { ), ); } -} \ No newline at end of file +}