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> {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
+1 -4
View File
@@ -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<AppBootstrap> createState() => _AppBootstrapState();
+1 -4
View File
@@ -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(
+14 -10
View File
@@ -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 {
+4 -5
View File
@@ -55,9 +55,9 @@ Future<void> main() async {
DriftSettingsService(database: context.read<AppDatabase>()),
),
ChangeNotifierProvider<InventoryViewModel>(
create: (context) => InventoryViewModel(
productService: context.read<ProductService>(),
)..load(),
create: (context) =>
InventoryViewModel(productService: context.read<ProductService>())
..load(),
),
ChangeNotifierProvider<ProductListViewModel>(
create: (context) => ProductListViewModel(
@@ -66,8 +66,7 @@ Future<void> main() async {
),
),
ChangeNotifierProvider<BarScreenViewModel>(
create: (context) =>
BarScreenViewModel(
create: (context) => BarScreenViewModel(
barTabService: context.read<BarTabService>(),
inventory: context.read<InventoryViewModel>(),
),
+2 -8
View File
@@ -18,17 +18,11 @@ class BarTab {
});
int get totalInCents {
return items.fold<int>(
0,
(total, item) => total + item.lineTotalInCents,
);
return items.fold<int>(0, (total, item) => total + item.lineTotalInCents);
}
int get itemCount {
return items.fold<int>(
0,
(total, item) => total + item.quantity,
);
return items.fold<int>(0, (total, item) => total + item.quantity);
}
String get formattedTotal {
+2 -8
View File
@@ -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,
+26 -38
View File
@@ -13,9 +13,7 @@ abstract class BarTabService {
Future<BarTab?> getTabById(String id);
Future<BarTab> createTab({
required String customerName,
});
Future<BarTab> createTab({required String customerName});
Future<void> 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<TabItem> items,
) {
BarTab _mapTabRow(BarTabRow row, List<TabItem> items) {
return BarTab(
id: row.id,
customerName: row.customerName,
@@ -81,9 +74,7 @@ class DriftBarTabService implements BarTabService {
Future<List<TabItem>> _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<List<BarTab>> 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,12 +117,12 @@ class DriftBarTabService implements BarTabService {
}
@override
Future<BarTab> createTab({
required String customerName,
}) async {
Future<BarTab> createTab({required String customerName}) async {
final id = _uuid.v4();
await database.into(database.barTabs).insert(
await database
.into(database.barTabs)
.insert(
BarTabsCompanion.insert(
id: id,
customerName: customerName,
@@ -160,8 +149,7 @@ class DriftBarTabService implements BarTabService {
final existingItemQuery = database.select(database.tabItems)
..where(
(item) =>
item.tabId.equals(tabId) &
item.productId.equals(product.id),
item.tabId.equals(tabId) & item.productId.equals(product.id),
);
final existingItem = await existingItemQuery.getSingleOrNull();
@@ -171,15 +159,15 @@ 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(
await database
.into(database.tabItems)
.insert(
TabItemsCompanion.insert(
id: _uuid.v4(),
tabId: tabId,
@@ -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,7 +220,9 @@ class DriftBarTabService implements BarTabService {
final closedTabId = _uuid.v4();
await database.into(database.closedTabs).insert(
await database
.into(database.closedTabs)
.insert(
ClosedTabsCompanion.insert(
id: closedTabId,
originalTabId: tabId,
@@ -246,7 +232,9 @@ class DriftBarTabService implements BarTabService {
);
for (final item in items) {
await database.into(database.closedTabItems).insert(
await database
.into(database.closedTabItems)
.insert(
ClosedTabItemsCompanion.insert(
id: _uuid.v4(),
closedTabId: closedTabId,
@@ -268,9 +256,7 @@ class DriftBarTabService implements BarTabService {
@override
Future<List<ClosedTab>> 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,13 +268,15 @@ class DriftBarTabService implements BarTabService {
final itemRows = await itemsQuery.get();
closedTabs.add(ClosedTab(
closedTabs.add(
ClosedTab(
id: row.id,
originalTabId: row.originalTabId,
customerName: row.customerName,
closedAt: row.closedAt,
items: itemRows.map<ClosedTabItem>(_mapClosedItemRow).toList(),
));
),
);
}
return closedTabs;
+8 -14
View File
@@ -23,6 +23,7 @@ abstract class ProductService {
Future<void> deleteProduct(String id);
Future<void> decreaseStock(String productId, int amount);
Future<void> 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<List<Product>> 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,7 +80,9 @@ class DriftProductService implements ProductService {
required int priceInCents,
required String? imagePath,
}) async {
await database.into(database.products).insert(
await database
.into(database.products)
.insert(
ProductsCompanion.insert(
id: _uuid.v4(),
name: name,
@@ -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),
);
}
}
+3 -1
View File
@@ -39,7 +39,9 @@ class DriftSettingsService implements SettingsService {
@override
Future<void> saveSettings(AppSettings settings) async {
await database.into(database.appSettingsTable).insertOnConflictUpdate(
await database
.into(database.appSettingsTable)
.insertOnConflictUpdate(
AppSettingsTableCompanion.insert(
id: _settingsId,
pinRequired: Value(settings.pinRequired),
+33 -15
View File
@@ -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,10 +694,7 @@ 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),
+12 -41
View File
@@ -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,
@@ -84,60 +79,36 @@ Future<void> _downloadAndInstall(UpdateInfo update) async {
destinationFilename: "update.apk",
sha256checksum: update.sha256,
)
.listen(
(OtaEvent event) {
.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;
final progress = double.tryParse(event.value ?? "0") ?? 0;
debugPrint(
"Downloading ${progress.toStringAsFixed(0)}%",
);
debugPrint("Downloading ${progress.toStringAsFixed(0)}%");
break;
case OtaStatus.INSTALLING:
debugPrint(
"Installing update",
);
debugPrint("Installing update");
break;
case OtaStatus.INSTALLATION_ERROR:
debugPrint(
"Installation error: ${event.value}",
);
debugPrint("Installation error: ${event.value}");
break;
case OtaStatus.DOWNLOAD_ERROR:
debugPrint(
"Download error: ${event.value}",
);
debugPrint("Download error: ${event.value}");
break;
default:
break;
}
},
);
});
} catch (e) {
debugPrint(
"OTA update failed: $e",
);
debugPrint("OTA update failed: $e");
}
}
+2 -8
View File
@@ -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<BarTab> _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);
+6 -5
View File
@@ -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<ClosedTab> _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();
}
+7 -21
View File
@@ -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<Product> _products = [];
@@ -19,40 +17,28 @@ class InventoryViewModel extends ChangeNotifier {
notifyListeners();
}
Future<void> decreaseStock(
String productId,
int amount,
) async {
Future<void> 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<void> increaseStock(
String productId,
int amount,
) async {
Future<void> 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,
);
}
+1 -4
View File
@@ -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<String> _defaultCategories = [
'Bier',
+7 -13
View File
@@ -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<void> ensureLoaded() async {
@@ -69,7 +72,6 @@ class SettingsViewModel extends ChangeNotifier {
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}");
}
}
}
-1
View File
@@ -22,7 +22,6 @@ class BarScreenView extends StatefulWidget {
}
class _BarScreenViewState extends State<BarScreenView> {
@override
void 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:provider/provider.dart';
Future<void> showNewTabDialog(BuildContext context) async {
final controller = TextEditingController();
@@ -14,9 +13,7 @@ Future<void> 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);
},
+5 -2
View File
@@ -52,9 +52,12 @@ class _HistoryScreenViewState extends State<HistoryScreenView> with RouteAware {
appBar: AppBar(
title: Row(
children: [
IconButton(onPressed: (){
IconButton(
onPressed: () {
context.go('/bar');
}, icon: const Icon(Icons.arrow_back)),
},
icon: const Icon(Icons.arrow_back),
),
const SizedBox(width: 5),
const Text('Tab History'),
],
+4 -6
View File
@@ -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<PinEntryView> createState() => _PinEntryViewState();
@@ -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,
),
),
+13 -28
View File
@@ -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<ProductFormView> {
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<ProductFormView> {
}
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<ProductFormView> {
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,19 +231,14 @@ class _ProductFormViewState extends State<ProductFormView> {
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,
),
Image.file(File(_imagePath!), fit: BoxFit.fitHeight),
Positioned(
right: 12,
bottom: 12,
@@ -301,9 +288,7 @@ class _ProductFormViewState extends State<ProductFormView> {
),
resizeToAvoidBottomInset: false,
body: _isLoading
? const Center(
child: CircularProgressIndicator(),
)
? const Center(child: CircularProgressIndicator())
: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 720),
+39 -23
View File
@@ -87,7 +87,9 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
void _showError(String message) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(message)));
}
Future<void> _enablePin() async {
@@ -168,8 +170,10 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
),
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<SettingsScreenView> {
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<SettingsScreenView> {
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<SettingsScreenView> {
} 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<SettingsScreenView> {
} 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),
+14 -6
View File
@@ -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,7 +153,10 @@ 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,
),
),
),
],
+3 -11
View File
@@ -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;
@@ -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)
-1
View File
@@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
class SlideConfirm extends StatefulWidget {
final VoidCallback onConfirmed;