fix: formatting

This commit is contained in:
2026-07-29 01:42:34 +02:00
parent 521c8f8c4e
commit 50e6fca9d1
32 changed files with 501 additions and 575 deletions
-1
View File
@@ -13,7 +13,6 @@ class KoolTabApp extends StatefulWidget {
} }
class _KoolTabAppState extends State<KoolTabApp> { class _KoolTabAppState extends State<KoolTabApp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp.router( return MaterialApp.router(
+1 -4
View File
@@ -7,10 +7,7 @@ import '../viewmodels/product_list_view_model.dart';
class AppBootstrap extends StatefulWidget { class AppBootstrap extends StatefulWidget {
final Widget child; final Widget child;
const AppBootstrap({ const AppBootstrap({super.key, required this.child});
super.key,
required this.child,
});
@override @override
State<AppBootstrap> createState() => _AppBootstrapState(); State<AppBootstrap> createState() => _AppBootstrapState();
+1 -4
View File
@@ -32,10 +32,7 @@ GoRouter createAppRouter(PinLockViewModel pinLockViewModel) {
return null; return null;
}, },
routes: [ routes: [
GoRoute( GoRoute(path: '/', redirect: (context, state) => '/bar'),
path: '/',
redirect: (context, state) => '/bar'
),
GoRoute( GoRoute(
path: '/lock', path: '/lock',
builder: (context, state) => PinEntryView( builder: (context, state) => PinEntryView(
+14 -10
View File
@@ -46,16 +46,10 @@ class BarTabs extends Table {
class TabItems extends Table { class TabItems extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get tabId => text().references( TextColumn get tabId =>
BarTabs, text().references(BarTabs, #id, onDelete: KeyAction.cascade)();
#id,
onDelete: KeyAction.cascade,
)();
TextColumn get productId => text().references( TextColumn get productId => text().references(Products, #id)();
Products,
#id,
)();
TextColumn get productName => text()(); TextColumn get productName => text()();
@@ -72,8 +66,11 @@ class TabItems extends Table {
@DataClassName('ClosedTabsRow') @DataClassName('ClosedTabsRow')
class ClosedTabs extends Table { class ClosedTabs extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get originalTabId => text()(); TextColumn get originalTabId => text()();
TextColumn get customerName => text()(); TextColumn get customerName => text()();
DateTimeColumn get closedAt => dateTime()(); DateTimeColumn get closedAt => dateTime()();
@override @override
@@ -83,10 +80,15 @@ class ClosedTabs extends Table {
@DataClassName('ClosedTabItemRow') @DataClassName('ClosedTabItemRow')
class ClosedTabItems extends Table { class ClosedTabItems extends Table {
TextColumn get id => text()(); TextColumn get id => text()();
TextColumn get closedTabId => text()(); TextColumn get closedTabId => text()();
TextColumn get productId => text()(); TextColumn get productId => text()();
TextColumn get productName => text()(); TextColumn get productName => text()();
IntColumn get quantity => integer()(); IntColumn get quantity => integer()();
IntColumn get unitPriceInCents => integer()(); IntColumn get unitPriceInCents => integer()();
@override @override
@@ -99,7 +101,9 @@ class AppSettingsTable extends Table {
String get tableName => 'app_settings'; String get tableName => 'app_settings';
TextColumn get id => text()(); TextColumn get id => text()();
BoolColumn get pinRequired => boolean().withDefault(const Constant(false))(); BoolColumn get pinRequired => boolean().withDefault(const Constant(false))();
TextColumn get themeMode => text().withDefault(const Constant('system'))(); TextColumn get themeMode => text().withDefault(const Constant('system'))();
@override @override
@@ -115,7 +119,7 @@ class AppSettingsTable extends Table {
ClosedTabs, ClosedTabs,
ClosedTabItems, ClosedTabItems,
AppSettingsTable AppSettingsTable,
], ],
) )
class AppDatabase extends _$AppDatabase { class AppDatabase extends _$AppDatabase {
+4 -5
View File
@@ -55,9 +55,9 @@ Future<void> main() async {
DriftSettingsService(database: context.read<AppDatabase>()), DriftSettingsService(database: context.read<AppDatabase>()),
), ),
ChangeNotifierProvider<InventoryViewModel>( ChangeNotifierProvider<InventoryViewModel>(
create: (context) => InventoryViewModel( create: (context) =>
productService: context.read<ProductService>(), InventoryViewModel(productService: context.read<ProductService>())
)..load(), ..load(),
), ),
ChangeNotifierProvider<ProductListViewModel>( ChangeNotifierProvider<ProductListViewModel>(
create: (context) => ProductListViewModel( create: (context) => ProductListViewModel(
@@ -66,8 +66,7 @@ Future<void> main() async {
), ),
), ),
ChangeNotifierProvider<BarScreenViewModel>( ChangeNotifierProvider<BarScreenViewModel>(
create: (context) => create: (context) => BarScreenViewModel(
BarScreenViewModel(
barTabService: context.read<BarTabService>(), barTabService: context.read<BarTabService>(),
inventory: context.read<InventoryViewModel>(), inventory: context.read<InventoryViewModel>(),
), ),
+2 -8
View File
@@ -18,17 +18,11 @@ class BarTab {
}); });
int get totalInCents { int get totalInCents {
return items.fold<int>( return items.fold<int>(0, (total, item) => total + item.lineTotalInCents);
0,
(total, item) => total + item.lineTotalInCents,
);
} }
int get itemCount { int get itemCount {
return items.fold<int>( return items.fold<int>(0, (total, item) => total + item.quantity);
0,
(total, item) => total + item.quantity,
);
} }
String get formattedTotal { String get formattedTotal {
+2 -8
View File
@@ -4,15 +4,9 @@ class AppSettings {
final bool pinRequired; final bool pinRequired;
final AppThemeMode themeMode; final AppThemeMode themeMode;
const AppSettings({ const AppSettings({required this.pinRequired, required this.themeMode});
required this.pinRequired,
required this.themeMode,
});
AppSettings copyWith({ AppSettings copyWith({bool? pinRequired, AppThemeMode? themeMode}) {
bool? pinRequired,
AppThemeMode? themeMode,
}) {
return AppSettings( return AppSettings(
pinRequired: pinRequired ?? this.pinRequired, pinRequired: pinRequired ?? this.pinRequired,
themeMode: themeMode ?? this.themeMode, themeMode: themeMode ?? this.themeMode,
+26 -38
View File
@@ -13,9 +13,7 @@ abstract class BarTabService {
Future<BarTab?> getTabById(String id); Future<BarTab?> getTabById(String id);
Future<BarTab> createTab({ Future<BarTab> createTab({required String customerName});
required String customerName,
});
Future<void> addProductToTab({ Future<void> addProductToTab({
required String tabId, required String tabId,
@@ -38,9 +36,7 @@ class DriftBarTabService implements BarTabService {
final AppDatabase database; final AppDatabase database;
final _uuid = const Uuid(); final _uuid = const Uuid();
DriftBarTabService({ DriftBarTabService({required this.database});
required this.database,
});
TabItem _mapItemRow(TabItemRow row) { TabItem _mapItemRow(TabItemRow row) {
return TabItem( return TabItem(
@@ -53,10 +49,7 @@ class DriftBarTabService implements BarTabService {
); );
} }
BarTab _mapTabRow( BarTab _mapTabRow(BarTabRow row, List<TabItem> items) {
BarTabRow row,
List<TabItem> items,
) {
return BarTab( return BarTab(
id: row.id, id: row.id,
customerName: row.customerName, customerName: row.customerName,
@@ -81,9 +74,7 @@ class DriftBarTabService implements BarTabService {
Future<List<TabItem>> _getItemsForTab(String tabId) async { Future<List<TabItem>> _getItemsForTab(String tabId) async {
final query = database.select(database.tabItems) final query = database.select(database.tabItems)
..where((item) => item.tabId.equals(tabId)) ..where((item) => item.tabId.equals(tabId))
..orderBy([ ..orderBy([(item) => OrderingTerm.asc(item.createdAt)]);
(item) => OrderingTerm.asc(item.createdAt),
]);
final rows = await query.get(); final rows = await query.get();
@@ -94,9 +85,7 @@ class DriftBarTabService implements BarTabService {
Future<List<BarTab>> getOpenTabs() async { Future<List<BarTab>> getOpenTabs() async {
final query = database.select(database.barTabs) final query = database.select(database.barTabs)
..where((tab) => tab.status.equals('open')) ..where((tab) => tab.status.equals('open'))
..orderBy([ ..orderBy([(tab) => OrderingTerm.desc(tab.openedAt)]);
(tab) => OrderingTerm.desc(tab.openedAt),
]);
final tabRows = await query.get(); final tabRows = await query.get();
@@ -128,12 +117,12 @@ class DriftBarTabService implements BarTabService {
} }
@override @override
Future<BarTab> createTab({ Future<BarTab> createTab({required String customerName}) async {
required String customerName,
}) async {
final id = _uuid.v4(); final id = _uuid.v4();
await database.into(database.barTabs).insert( await database
.into(database.barTabs)
.insert(
BarTabsCompanion.insert( BarTabsCompanion.insert(
id: id, id: id,
customerName: customerName, customerName: customerName,
@@ -160,8 +149,7 @@ class DriftBarTabService implements BarTabService {
final existingItemQuery = database.select(database.tabItems) final existingItemQuery = database.select(database.tabItems)
..where( ..where(
(item) => (item) =>
item.tabId.equals(tabId) & item.tabId.equals(tabId) & item.productId.equals(product.id),
item.productId.equals(product.id),
); );
final existingItem = await existingItemQuery.getSingleOrNull(); final existingItem = await existingItemQuery.getSingleOrNull();
@@ -171,15 +159,15 @@ class DriftBarTabService implements BarTabService {
..where((item) => item.id.equals(existingItem.id)); ..where((item) => item.id.equals(existingItem.id));
await updateQuery.write( await updateQuery.write(
TabItemsCompanion( TabItemsCompanion(quantity: Value(existingItem.quantity + 1)),
quantity: Value(existingItem.quantity + 1),
),
); );
return; return;
} }
await database.into(database.tabItems).insert( await database
.into(database.tabItems)
.insert(
TabItemsCompanion.insert( TabItemsCompanion.insert(
id: _uuid.v4(), id: _uuid.v4(),
tabId: tabId, tabId: tabId,
@@ -209,11 +197,7 @@ class DriftBarTabService implements BarTabService {
final updateQuery = database.update(database.tabItems) final updateQuery = database.update(database.tabItems)
..where((item) => item.id.equals(tabItemId)); ..where((item) => item.id.equals(tabItemId));
await updateQuery.write( await updateQuery.write(TabItemsCompanion(quantity: Value(quantity)));
TabItemsCompanion(
quantity: Value(quantity),
),
);
} }
@override @override
@@ -236,7 +220,9 @@ class DriftBarTabService implements BarTabService {
final closedTabId = _uuid.v4(); final closedTabId = _uuid.v4();
await database.into(database.closedTabs).insert( await database
.into(database.closedTabs)
.insert(
ClosedTabsCompanion.insert( ClosedTabsCompanion.insert(
id: closedTabId, id: closedTabId,
originalTabId: tabId, originalTabId: tabId,
@@ -246,7 +232,9 @@ class DriftBarTabService implements BarTabService {
); );
for (final item in items) { for (final item in items) {
await database.into(database.closedTabItems).insert( await database
.into(database.closedTabItems)
.insert(
ClosedTabItemsCompanion.insert( ClosedTabItemsCompanion.insert(
id: _uuid.v4(), id: _uuid.v4(),
closedTabId: closedTabId, closedTabId: closedTabId,
@@ -268,9 +256,7 @@ class DriftBarTabService implements BarTabService {
@override @override
Future<List<ClosedTab>> getClosedTabs() async { Future<List<ClosedTab>> getClosedTabs() async {
final query = database.select(database.closedTabs) final query = database.select(database.closedTabs)
..orderBy([ ..orderBy([(tab) => OrderingTerm.desc(tab.closedAt)]);
(tab) => OrderingTerm.desc(tab.closedAt),
]);
final closedTabRows = await query.get(); final closedTabRows = await query.get();
@@ -282,13 +268,15 @@ class DriftBarTabService implements BarTabService {
final itemRows = await itemsQuery.get(); final itemRows = await itemsQuery.get();
closedTabs.add(ClosedTab( closedTabs.add(
ClosedTab(
id: row.id, id: row.id,
originalTabId: row.originalTabId, originalTabId: row.originalTabId,
customerName: row.customerName, customerName: row.customerName,
closedAt: row.closedAt, closedAt: row.closedAt,
items: itemRows.map<ClosedTabItem>(_mapClosedItemRow).toList(), items: itemRows.map<ClosedTabItem>(_mapClosedItemRow).toList(),
)); ),
);
} }
return closedTabs; return closedTabs;
+8 -14
View File
@@ -23,6 +23,7 @@ abstract class ProductService {
Future<void> deleteProduct(String id); Future<void> deleteProduct(String id);
Future<void> decreaseStock(String productId, int amount); Future<void> decreaseStock(String productId, int amount);
Future<void> increaseStock(String productId, int amount); Future<void> increaseStock(String productId, int amount);
} }
@@ -30,9 +31,7 @@ class DriftProductService implements ProductService {
final AppDatabase database; final AppDatabase database;
final _uuid = const Uuid(); final _uuid = const Uuid();
DriftProductService({ DriftProductService({required this.database});
required this.database,
});
Product _mapRowToProduct(ProductRow row) { Product _mapRowToProduct(ProductRow row) {
return Product( return Product(
@@ -51,9 +50,7 @@ class DriftProductService implements ProductService {
Future<List<Product>> getProducts() async { Future<List<Product>> getProducts() async {
final query = database.select(database.products) final query = database.select(database.products)
..where((product) => product.active.equals(true)) ..where((product) => product.active.equals(true))
..orderBy([ ..orderBy([(product) => OrderingTerm.asc(product.name)]);
(product) => OrderingTerm.asc(product.name),
]);
final rows = await query.get(); final rows = await query.get();
@@ -83,7 +80,9 @@ class DriftProductService implements ProductService {
required int priceInCents, required int priceInCents,
required String? imagePath, required String? imagePath,
}) async { }) async {
await database.into(database.products).insert( await database
.into(database.products)
.insert(
ProductsCompanion.insert( ProductsCompanion.insert(
id: _uuid.v4(), id: _uuid.v4(),
name: name, name: name,
@@ -135,9 +134,7 @@ class DriftProductService implements ProductService {
} }
await updateProduct( await updateProduct(
product.copyWith( product.copyWith(stockQuantity: product.stockQuantity - amount),
stockQuantity: product.stockQuantity - amount,
),
); );
} }
@@ -150,10 +147,7 @@ class DriftProductService implements ProductService {
} }
await updateProduct( await updateProduct(
product.copyWith( product.copyWith(stockQuantity: product.stockQuantity + amount),
stockQuantity: product.stockQuantity + amount,
),
); );
} }
} }
+3 -1
View File
@@ -39,7 +39,9 @@ class DriftSettingsService implements SettingsService {
@override @override
Future<void> saveSettings(AppSettings settings) async { Future<void> saveSettings(AppSettings settings) async {
await database.into(database.appSettingsTable).insertOnConflictUpdate( await database
.into(database.appSettingsTable)
.insertOnConflictUpdate(
AppSettingsTableCompanion.insert( AppSettingsTableCompanion.insert(
id: _settingsId, id: _settingsId,
pinRequired: Value(settings.pinRequired), pinRequired: Value(settings.pinRequired),
+33 -15
View File
@@ -253,10 +253,7 @@ final ThemeData darkTheme = ThemeData(
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
letterSpacing: -0.2, letterSpacing: -0.2,
), ),
titleMedium: TextStyle( titleMedium: TextStyle(color: Colors.white, fontWeight: FontWeight.w700),
color: Colors.white,
fontWeight: FontWeight.w700,
),
bodyLarge: TextStyle(color: Colors.white70, fontSize: 16, height: 1.5), bodyLarge: TextStyle(color: Colors.white70, fontSize: 16, height: 1.5),
bodyMedium: TextStyle(color: Colors.white60, height: 1.4), bodyMedium: TextStyle(color: Colors.white60, height: 1.4),
bodySmall: TextStyle(color: Colors.white38, height: 1.3), bodySmall: TextStyle(color: Colors.white38, height: 1.3),
@@ -311,9 +308,17 @@ final ThemeData neoBrutalDarkTheme = ThemeData(
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
color: Colors.white, 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), 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( appBarTheme: const AppBarTheme(
@@ -331,7 +336,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData(
cardTheme: CardThemeData( cardTheme: CardThemeData(
color: _nbSurface, color: _nbSurface,
elevation: 0, elevation: 0,
margin: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: AppSpacing.sm), margin: const EdgeInsets.symmetric(
horizontal: AppSpacing.md,
vertical: AppSpacing.sm,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.white, width: 3), side: const BorderSide(color: Colors.white, width: 3),
@@ -380,7 +388,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData(
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
filled: true, filled: true,
fillColor: _nbSurface, 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), contentPadding: const EdgeInsets.all(18),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
@@ -408,7 +419,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
), ),
contentTextStyle: const TextStyle(color: Colors.white70, fontWeight: FontWeight.w600), contentTextStyle: const TextStyle(
color: Colors.white70,
fontWeight: FontWeight.w600,
),
), ),
floatingActionButtonTheme: const FloatingActionButtonThemeData( floatingActionButtonTheme: const FloatingActionButtonThemeData(
@@ -428,7 +442,10 @@ final ThemeData neoBrutalDarkTheme = ThemeData(
side: const BorderSide(color: Colors.white, width: 3), side: const BorderSide(color: Colors.white, width: 3),
), ),
behavior: SnackBarBehavior.floating, 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), dividerTheme: const DividerThemeData(color: Colors.white, thickness: 3),
@@ -645,7 +662,11 @@ final ThemeData lightTheme = ThemeData(
contentTextStyle: const TextStyle(color: Colors.white), 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( chipTheme: ChipThemeData(
backgroundColor: _surfaceRaisedL, backgroundColor: _surfaceRaisedL,
@@ -673,10 +694,7 @@ final ThemeData lightTheme = ThemeData(
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
letterSpacing: -0.2, letterSpacing: -0.2,
), ),
titleMedium: TextStyle( titleMedium: TextStyle(color: Colors.black87, fontWeight: FontWeight.w700),
color: Colors.black87,
fontWeight: FontWeight.w700,
),
bodyLarge: TextStyle(color: Colors.black54, fontSize: 16, height: 1.5), bodyLarge: TextStyle(color: Colors.black54, fontSize: 16, height: 1.5),
bodyMedium: TextStyle(color: Colors.black45, height: 1.4), bodyMedium: TextStyle(color: Colors.black45, height: 1.4),
bodySmall: TextStyle(color: Colors.black38, height: 1.3), bodySmall: TextStyle(color: Colors.black38, height: 1.3),
+12 -41
View File
@@ -13,9 +13,7 @@ class UpdateChecker {
_hasChecked = true; _hasChecked = true;
final updater = AppUpdateUtil( final updater = AppUpdateUtil(serverUrl: "https://updater.brammie15.dev");
serverUrl: "https://updater.brammie15.dev",
);
try { try {
final update = await updater.checkForUpdate(); final update = await updater.checkForUpdate();
@@ -35,10 +33,7 @@ class UpdateChecker {
} }
} }
static void _showUpdateDialog( static void _showUpdateDialog(BuildContext context, UpdateInfo update) {
BuildContext context,
UpdateInfo update,
) {
showDialog( showDialog(
context: context, context: context,
barrierDismissible: !update.mandatory, barrierDismissible: !update.mandatory,
@@ -84,60 +79,36 @@ Future<void> _downloadAndInstall(UpdateInfo update) async {
destinationFilename: "update.apk", destinationFilename: "update.apk",
sha256checksum: update.sha256, sha256checksum: update.sha256,
) )
.listen( .listen((OtaEvent event) {
(OtaEvent event) { debugPrint("OTA status: ${event.status}");
debugPrint( debugPrint("OTA value: ${event.value}");
"OTA status: ${event.status}",
);
debugPrint(
"OTA value: ${event.value}",
);
switch (event.status) { switch (event.status) {
case OtaStatus.DOWNLOADING: case OtaStatus.DOWNLOADING:
final progress = final progress = double.tryParse(event.value ?? "0") ?? 0;
double.tryParse(event.value ?? "0") ?? 0;
debugPrint( debugPrint("Downloading ${progress.toStringAsFixed(0)}%");
"Downloading ${progress.toStringAsFixed(0)}%",
);
break; break;
case OtaStatus.INSTALLING: case OtaStatus.INSTALLING:
debugPrint( debugPrint("Installing update");
"Installing update",
);
break; break;
case OtaStatus.INSTALLATION_ERROR: case OtaStatus.INSTALLATION_ERROR:
debugPrint( debugPrint("Installation error: ${event.value}");
"Installation error: ${event.value}",
);
break; break;
case OtaStatus.DOWNLOAD_ERROR: case OtaStatus.DOWNLOAD_ERROR:
debugPrint( debugPrint("Download error: ${event.value}");
"Download error: ${event.value}",
);
break; break;
default: default:
break; break;
} }
}, });
);
} catch (e) { } catch (e) {
debugPrint( debugPrint("OTA update failed: $e");
"OTA update failed: $e",
);
} }
} }
+2 -8
View File
@@ -10,10 +10,7 @@ class BarScreenViewModel extends ChangeNotifier {
final BarTabService barTabService; final BarTabService barTabService;
final InventoryViewModel inventory; final InventoryViewModel inventory;
BarScreenViewModel({ BarScreenViewModel({required this.barTabService, required this.inventory});
required this.barTabService,
required this.inventory,
});
List<BarTab> _tabs = []; List<BarTab> _tabs = [];
String? _selectedTabId; String? _selectedTabId;
@@ -91,10 +88,7 @@ class BarScreenViewModel extends ChangeNotifier {
throw Exception('Product is out of stock.'); throw Exception('Product is out of stock.');
} }
await barTabService.addProductToTab( await barTabService.addProductToTab(tabId: tab.id, product: product);
tabId: tab.id,
product: product,
);
await inventory.decreaseStock(product.id, 1); await inventory.decreaseStock(product.id, 1);
+6 -5
View File
@@ -6,9 +6,7 @@ import '../services/bar_tab_service.dart';
class HistoryViewModel extends ChangeNotifier { class HistoryViewModel extends ChangeNotifier {
final BarTabService barTabService; final BarTabService barTabService;
HistoryViewModel({ HistoryViewModel({required this.barTabService});
required this.barTabService,
});
List<ClosedTab> _closedTabs = []; List<ClosedTab> _closedTabs = [];
bool _isLoading = false; bool _isLoading = false;
@@ -20,8 +18,11 @@ class HistoryViewModel extends ChangeNotifier {
if (_searchQuery.isEmpty) return _closedTabs; if (_searchQuery.isEmpty) return _closedTabs;
return _closedTabs return _closedTabs
.where((tab) => .where(
tab.customerName.toLowerCase().contains(_searchQuery.toLowerCase())) (tab) => tab.customerName.toLowerCase().contains(
_searchQuery.toLowerCase(),
),
)
.toList(); .toList();
} }
+7 -21
View File
@@ -6,9 +6,7 @@ import '../services/product_service.dart';
class InventoryViewModel extends ChangeNotifier { class InventoryViewModel extends ChangeNotifier {
final ProductService productService; final ProductService productService;
InventoryViewModel({ InventoryViewModel({required this.productService});
required this.productService,
});
List<Product> _products = []; List<Product> _products = [];
@@ -19,40 +17,28 @@ class InventoryViewModel extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
Future<void> decreaseStock( Future<void> decreaseStock(String productId, int amount) async {
String productId,
int amount,
) async {
await productService.decreaseStock(productId, amount); await productService.decreaseStock(productId, amount);
final index = _products.indexWhere( final index = _products.indexWhere((product) => product.id == productId);
(product) => product.id == productId,
);
if (index != -1) { if (index != -1) {
_products[index] = _products[index].copyWith( _products[index] = _products[index].copyWith(
stockQuantity: stockQuantity: _products[index].stockQuantity - amount,
_products[index].stockQuantity - amount,
); );
} }
notifyListeners(); notifyListeners();
} }
Future<void> increaseStock( Future<void> increaseStock(String productId, int amount) async {
String productId,
int amount,
) async {
await productService.increaseStock(productId, amount); await productService.increaseStock(productId, amount);
final index = _products.indexWhere( final index = _products.indexWhere((product) => product.id == productId);
(product) => product.id == productId,
);
if (index != -1) { if (index != -1) {
_products[index] = _products[index].copyWith( _products[index] = _products[index].copyWith(
stockQuantity: stockQuantity: _products[index].stockQuantity + amount,
_products[index].stockQuantity + amount,
); );
} }
+1 -4
View File
@@ -8,10 +8,7 @@ class ProductListViewModel extends ChangeNotifier {
final ProductService productService; final ProductService productService;
final InventoryViewModel inventory; final InventoryViewModel inventory;
ProductListViewModel({ ProductListViewModel({required this.productService, required this.inventory});
required this.productService,
required this.inventory,
});
static const List<String> _defaultCategories = [ static const List<String> _defaultCategories = [
'Bier', 'Bier',
+7 -13
View File
@@ -24,8 +24,11 @@ class SettingsViewModel extends ChangeNotifier {
bool get checkingForUpdates => _checkingForUpdates; bool get checkingForUpdates => _checkingForUpdates;
AppSettings get settings => _settings; AppSettings get settings => _settings;
bool get isLoading => _isLoading; bool get isLoading => _isLoading;
bool get hasLoaded => _hasLoaded; bool get hasLoaded => _hasLoaded;
String? get errorMessage => _errorMessage; String? get errorMessage => _errorMessage;
Future<void> ensureLoaded() async { Future<void> ensureLoaded() async {
@@ -69,7 +72,6 @@ class SettingsViewModel extends ChangeNotifier {
UpdateInfo update, { UpdateInfo update, {
void Function(double progress)? onProgress, void Function(double progress)? onProgress,
}) async { }) async {
final url = update.download.startsWith("http") final url = update.download.startsWith("http")
? update.download ? update.download
: "https://updater.brammie15.dev${update.download}"; : "https://updater.brammie15.dev${update.download}";
@@ -83,28 +85,20 @@ class SettingsViewModel extends ChangeNotifier {
); );
await for (final event in stream) { await for (final event in stream) {
debugPrint("OTA: ${event.status} ${event.value}");
debugPrint(
"OTA: ${event.status} ${event.value}",
);
if (event.status == OtaStatus.DOWNLOADING) { if (event.status == OtaStatus.DOWNLOADING) {
final progress = final progress = double.tryParse(event.value ?? "0") ?? 0;
double.tryParse(event.value ?? "0") ?? 0;
onProgress?.call(progress / 100); onProgress?.call(progress / 100);
} }
if (event.status == OtaStatus.DOWNLOAD_ERROR) { if (event.status == OtaStatus.DOWNLOAD_ERROR) {
throw Exception( throw Exception("Download failed: ${event.value}");
"Download failed: ${event.value}",
);
} }
if (event.status == OtaStatus.INSTALLATION_ERROR) { if (event.status == OtaStatus.INSTALLATION_ERROR) {
throw Exception( throw Exception("Installation failed: ${event.value}");
"Installation failed: ${event.value}",
);
} }
} }
} }
-1
View File
@@ -22,7 +22,6 @@ class BarScreenView extends StatefulWidget {
} }
class _BarScreenViewState extends State<BarScreenView> { class _BarScreenViewState extends State<BarScreenView> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
+1 -4
View File
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:kooltab2/viewmodels/bar_screen_view_model.dart'; import 'package:kooltab2/viewmodels/bar_screen_view_model.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
Future<void> showNewTabDialog(BuildContext context) async { Future<void> showNewTabDialog(BuildContext context) async {
final controller = TextEditingController(); final controller = TextEditingController();
@@ -14,9 +13,7 @@ Future<void> showNewTabDialog(BuildContext context) async {
content: TextField( content: TextField(
controller: controller, controller: controller,
autofocus: true, autofocus: true,
decoration: const InputDecoration( decoration: const InputDecoration(labelText: 'Customer / group name'),
labelText: 'Customer / group name',
),
onSubmitted: (value) { onSubmitted: (value) {
Navigator.of(dialogContext).pop(value); Navigator.of(dialogContext).pop(value);
}, },
+5 -2
View File
@@ -52,9 +52,12 @@ class _HistoryScreenViewState extends State<HistoryScreenView> with RouteAware {
appBar: AppBar( appBar: AppBar(
title: Row( title: Row(
children: [ children: [
IconButton(onPressed: (){ IconButton(
onPressed: () {
context.go('/bar'); context.go('/bar');
}, icon: const Icon(Icons.arrow_back)), },
icon: const Icon(Icons.arrow_back),
),
const SizedBox(width: 5), const SizedBox(width: 5),
const Text('Tab History'), const Text('Tab History'),
], ],
+4 -6
View File
@@ -14,11 +14,7 @@ class PinEntryView extends StatefulWidget {
final PinEntryMode mode; final PinEntryMode mode;
final VoidCallback? onSuccess; final VoidCallback? onSuccess;
const PinEntryView({ const PinEntryView({super.key, required this.mode, this.onSuccess});
super.key,
required this.mode,
this.onSuccess,
});
@override @override
State<PinEntryView> createState() => _PinEntryViewState(); State<PinEntryView> createState() => _PinEntryViewState();
@@ -210,7 +206,9 @@ class _PinDots extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
color: isFilled ? scheme.primary : Colors.transparent, color: isFilled ? scheme.primary : Colors.transparent,
border: Border.all( 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, width: 1.4,
), ),
), ),
+13 -28
View File
@@ -13,10 +13,7 @@ import '../viewmodels/product_list_view_model.dart';
class ProductFormView extends StatefulWidget { class ProductFormView extends StatefulWidget {
final String? productId; final String? productId;
const ProductFormView({ const ProductFormView({super.key, this.productId});
super.key,
this.productId,
});
bool get isEditing => productId != null; bool get isEditing => productId != null;
@@ -60,11 +57,9 @@ class _ProductFormViewState extends State<ProductFormView> {
if (!mounted) return; if (!mounted) return;
if (product == null) { if (product == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
const SnackBar( context,
content: Text('Product not found.'), ).showSnackBar(const SnackBar(content: Text('Product not found.')));
),
);
context.go('/products'); context.go('/products');
return; return;
@@ -102,7 +97,8 @@ class _ProductFormViewState extends State<ProductFormView> {
} }
final extension = path.extension(pickedFile.path); 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 newPath = path.join(imagesDirectory.path, fileName);
final copiedFile = await File(pickedFile.path).copy(newPath); final copiedFile = await File(pickedFile.path).copy(newPath);
@@ -139,19 +135,15 @@ class _ProductFormViewState extends State<ProductFormView> {
if (!_formKey.currentState!.validate()) return; if (!_formKey.currentState!.validate()) return;
if (_imagePath == null || _imagePath!.isEmpty) { if (_imagePath == null || _imagePath!.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
const SnackBar( context,
content: Text('Choose a product image.'), ).showSnackBar(const SnackBar(content: Text('Choose a product image.')));
),
);
return; return;
} }
if (_selectedCategory == null) { if (_selectedCategory == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(content: Text('Please select a category.')),
content: Text('Please select a category.'),
),
); );
return; return;
} }
@@ -239,19 +231,14 @@ class _ProductFormViewState extends State<ProductFormView> {
height: 220, height: 220,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(color: Theme.of(context).colorScheme.outline),
color: Theme.of(context).colorScheme.outline,
),
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: hasImage child: hasImage
? Stack( ? Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
Image.file( Image.file(File(_imagePath!), fit: BoxFit.fitHeight),
File(_imagePath!),
fit: BoxFit.fitHeight,
),
Positioned( Positioned(
right: 12, right: 12,
bottom: 12, bottom: 12,
@@ -301,9 +288,7 @@ class _ProductFormViewState extends State<ProductFormView> {
), ),
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
body: _isLoading body: _isLoading
? const Center( ? const Center(child: CircularProgressIndicator())
child: CircularProgressIndicator(),
)
: Center( : Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 720), constraints: const BoxConstraints(maxWidth: 720),
+39 -23
View File
@@ -87,7 +87,9 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
void _showError(String message) { void _showError(String message) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message))); ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(message)));
} }
Future<void> _enablePin() async { Future<void> _enablePin() async {
@@ -168,8 +170,10 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
), ),
body: Builder( body: Builder(
builder: (context) { builder: (context) {
final isLoading = settingsViewModel.isLoading || pinLockViewModel.isLoading; final isLoading =
final hasLoaded = settingsViewModel.hasLoaded && pinLockViewModel.hasLoaded; settingsViewModel.isLoading || pinLockViewModel.isLoading;
final hasLoaded =
settingsViewModel.hasLoaded && pinLockViewModel.hasLoaded;
if (isLoading && !hasLoaded) { if (isLoading && !hasLoaded) {
return const Center( return const Center(
@@ -231,7 +235,8 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
AppThemeMode.light => 'Light', AppThemeMode.light => 'Light',
AppThemeMode.dark => 'Dark', AppThemeMode.dark => 'Dark',
}), }),
onChanged: (value) => Navigator.pop(context, value), onChanged: (value) =>
Navigator.pop(context, value),
); );
}).toList(), }).toList(),
), ),
@@ -265,14 +270,10 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
child: Center( child: Center(
child: Text( child: Text(
'Version $_appVersion', 'Version $_appVersion',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall?.copyWith(
.textTheme color: Theme.of(
.bodySmall context,
?.copyWith( ).colorScheme.onSurface.withValues(alpha: 0.5),
color: Theme.of(context)
.colorScheme
.onSurface
.withValues(alpha: 0.5),
), ),
), ),
), ),
@@ -306,9 +307,9 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
} catch (e) { } catch (e) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
SnackBar(content: Text('Update check failed: $e')), context,
); ).showSnackBar(SnackBar(content: Text('Update check failed: $e')));
} }
} }
@@ -349,9 +350,9 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
} catch (e) { } catch (e) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(
SnackBar(content: Text("Update failed: $e")), context,
); ).showSnackBar(SnackBar(content: Text("Update failed: $e")));
} }
}, },
child: const Text("Update"), child: const Text("Update"),
@@ -391,7 +392,9 @@ class _SettingsSection extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: scheme.onSurface.withValues(alpha: 0.04), color: scheme.onSurface.withValues(alpha: 0.04),
borderRadius: BorderRadius.circular(14), 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, clipBehavior: Clip.antiAlias,
child: Column(children: children), child: Column(children: children),
@@ -427,12 +430,19 @@ class _SettingsTile extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row( child: Row(
children: [ 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), const SizedBox(width: 14),
Expanded( Expanded(
child: Text( child: Text(
title, title,
style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), style: TextStyle(
fontWeight: FontWeight.w600,
color: scheme.onSurface,
),
), ),
), ),
if (subtitle != null) ...[ if (subtitle != null) ...[
@@ -440,7 +450,10 @@ class _SettingsTile extends StatelessWidget {
const SizedBox(width: 4), const SizedBox(width: 4),
], ],
if (onTap != null) 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( Expanded(
child: Text( child: Text(
title, title,
style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), style: TextStyle(
fontWeight: FontWeight.w600,
color: scheme.onSurface,
),
), ),
), ),
Switch(value: value, onChanged: onChanged), Switch(value: value, onChanged: onChanged),
+14 -6
View File
@@ -120,10 +120,12 @@ class _ClosedTabItemRow extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final unitPrice = final unitPrice = NumberFormat.simpleCurrency().format(
NumberFormat.simpleCurrency().format(item.unitPriceInCents / 100); item.unitPriceInCents / 100,
final lineTotal = );
NumberFormat.simpleCurrency().format(item.lineTotalInCents / 100); final lineTotal = NumberFormat.simpleCurrency().format(
item.lineTotalInCents / 100,
);
final scheme = Theme.of(context).colorScheme; final scheme = Theme.of(context).colorScheme;
return Padding( return Padding(
@@ -135,7 +137,10 @@ class _ClosedTabItemRow extends StatelessWidget {
item.productName, item.productName,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.w600, color: scheme.onSurface), style: TextStyle(
fontWeight: FontWeight.w600,
color: scheme.onSurface,
),
), ),
), ),
Text( Text(
@@ -148,7 +153,10 @@ class _ClosedTabItemRow extends StatelessWidget {
child: Text( child: Text(
lineTotal, lineTotal,
textAlign: TextAlign.end, textAlign: TextAlign.end,
style: TextStyle(fontWeight: FontWeight.w700, color: scheme.onSurface), style: TextStyle(
fontWeight: FontWeight.w700,
color: scheme.onSurface,
),
), ),
), ),
], ],
+3 -11
View File
@@ -3,7 +3,6 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kooltab2/models/product.dart'; import 'package:kooltab2/models/product.dart';
class ProductTile extends StatelessWidget { class ProductTile extends StatelessWidget {
final Product product; final Product product;
final bool enabled; final bool enabled;
@@ -95,9 +94,7 @@ class ProductTile extends StatelessWidget {
Positioned( Positioned(
top: 10, top: 10,
right: 10, right: 10,
child: _StockBadge( child: _StockBadge(product: product),
product: product,
),
), ),
// Out of stock overlay // Out of stock overlay
@@ -134,9 +131,7 @@ class ProductTile extends StatelessWidget {
class _StockBadge extends StatelessWidget { class _StockBadge extends StatelessWidget {
final Product product; final Product product;
const _StockBadge({ const _StockBadge({required this.product});
required this.product,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -150,10 +145,7 @@ class _StockBadge extends StatelessWidget {
product.stockQuantity <= product.lowStockThreshold; // adjust name product.stockQuantity <= product.lowStockThreshold; // adjust name
return Container( return Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: low color: low
? Colors.amber.withValues(alpha: 0.9) ? Colors.amber.withValues(alpha: 0.9)
-1
View File
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SlideConfirm extends StatefulWidget { class SlideConfirm extends StatefulWidget {
final VoidCallback onConfirmed; final VoidCallback onConfirmed;