feat: add rows count (broken), fix: bug with low stock items
This commit is contained in:
@@ -12,8 +12,10 @@ import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import '../models/bar_tab.dart';
|
||||
import '../models/product.dart';
|
||||
import '../models/tab_item.dart';
|
||||
import '../services/product_service.dart';
|
||||
import '../utils/app_updater.dart';
|
||||
import '../viewmodels/bar_screen_view_model.dart';
|
||||
import '../viewmodels/settings_view_model.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
import '../l10n/app_localizations_helpers.dart';
|
||||
|
||||
@@ -38,6 +40,11 @@ class _BarScreenViewState extends State<BarScreenView> {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final viewModel = context.watch<BarScreenViewModel>();
|
||||
final productsViewModel = context.watch<ProductListViewModel>();
|
||||
final settings = context.watch<SettingsViewModel>().settings;
|
||||
final stockByProductId = {
|
||||
for (final product in productsViewModel.products)
|
||||
product.id: product.stockQuantity,
|
||||
};
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
@@ -118,6 +125,7 @@ class _BarScreenViewState extends State<BarScreenView> {
|
||||
flex: 2,
|
||||
child: _ProductGrid(
|
||||
products: productsViewModel.products,
|
||||
rows: settings.barGridRows,
|
||||
hasSelectedTab: viewModel.selectedTab != null,
|
||||
onProductTap: (product) async {
|
||||
if (viewModel.selectedTab == null) {
|
||||
@@ -130,10 +138,18 @@ class _BarScreenViewState extends State<BarScreenView> {
|
||||
try {
|
||||
await viewModel.addProductToSelectedTab(product);
|
||||
} catch (e, stack) {
|
||||
Sentry.captureException(e, stackTrace: stack);
|
||||
if (e is! InsufficientStockException) {
|
||||
Sentry.captureException(e, stackTrace: stack);
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.couldNotAddProductToTab)),
|
||||
SnackBar(
|
||||
content: Text(
|
||||
e is InsufficientStockException
|
||||
? l10n.productOutOfStock
|
||||
: l10n.couldNotAddProductToTab,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -146,6 +162,7 @@ class _BarScreenViewState extends State<BarScreenView> {
|
||||
tabs: viewModel.tabs,
|
||||
selectedTab: viewModel.selectedTab,
|
||||
selectedTabId: viewModel.selectedTabId,
|
||||
stockByProductId: stockByProductId,
|
||||
onNewTabPressed: () => showNewTabDialog(context),
|
||||
onTabSelected: viewModel.selectTab,
|
||||
onItemQuantityChanged: viewModel.changeItemQuantity,
|
||||
@@ -166,11 +183,13 @@ class _BarScreenViewState extends State<BarScreenView> {
|
||||
// ---------------------------------------------------------------------------
|
||||
class _ProductGrid extends StatelessWidget {
|
||||
final List<Product> products;
|
||||
final int rows;
|
||||
final bool hasSelectedTab;
|
||||
final ValueChanged<Product> onProductTap;
|
||||
|
||||
const _ProductGrid({
|
||||
required this.products,
|
||||
required this.rows,
|
||||
required this.hasSelectedTab,
|
||||
required this.onProductTap,
|
||||
});
|
||||
@@ -267,11 +286,26 @@ class _ProductGrid extends StatelessWidget {
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final columns = ((constraints.maxWidth / 170).floor())
|
||||
.clamp(3, 5)
|
||||
.toInt();
|
||||
const horizontalPadding = 32.0;
|
||||
const verticalPadding = 28.0;
|
||||
const spacing = 12.0;
|
||||
final rowCount = rows.clamp(2, 6).toInt();
|
||||
final rowHeight =
|
||||
((constraints.maxHeight -
|
||||
verticalPadding -
|
||||
(rowCount - 1) * spacing) /
|
||||
rowCount)
|
||||
.clamp(96.0, 320.0)
|
||||
.toDouble();
|
||||
final columns =
|
||||
(((constraints.maxWidth - horizontalPadding + spacing) /
|
||||
(rowHeight + spacing))
|
||||
.ceil())
|
||||
.clamp(2, 8)
|
||||
.toInt();
|
||||
|
||||
return GridView.builder(
|
||||
key: ValueKey('product-grid-$rows'),
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 16),
|
||||
itemCount: products.length,
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
@@ -306,6 +340,7 @@ class _TabPanel extends StatefulWidget {
|
||||
final List<BarTab> tabs;
|
||||
final BarTab? selectedTab;
|
||||
final String? selectedTabId;
|
||||
final Map<String, int> stockByProductId;
|
||||
final VoidCallback onNewTabPressed;
|
||||
final ValueChanged<String> onTabSelected;
|
||||
final Future<void> Function(TabItem item, int quantity) onItemQuantityChanged;
|
||||
@@ -316,6 +351,7 @@ class _TabPanel extends StatefulWidget {
|
||||
required this.tabs,
|
||||
required this.selectedTab,
|
||||
required this.selectedTabId,
|
||||
required this.stockByProductId,
|
||||
required this.onNewTabPressed,
|
||||
required this.onTabSelected,
|
||||
required this.onItemQuantityChanged,
|
||||
@@ -452,6 +488,7 @@ class _TabPanelState extends State<_TabPanel> {
|
||||
)
|
||||
: _SelectedTabDetails(
|
||||
tab: widget.selectedTab!,
|
||||
stockByProductId: widget.stockByProductId,
|
||||
onItemQuantityChanged: widget.onItemQuantityChanged,
|
||||
onCloseTabPressed: widget.onCloseTabPressed,
|
||||
),
|
||||
@@ -596,11 +633,13 @@ class _OpenTabsList extends StatelessWidget {
|
||||
|
||||
class _SelectedTabDetails extends StatelessWidget {
|
||||
final BarTab tab;
|
||||
final Map<String, int> stockByProductId;
|
||||
final Future<void> Function(TabItem item, int quantity) onItemQuantityChanged;
|
||||
final VoidCallback onCloseTabPressed;
|
||||
|
||||
const _SelectedTabDetails({
|
||||
required this.tab,
|
||||
required this.stockByProductId,
|
||||
required this.onItemQuantityChanged,
|
||||
required this.onCloseTabPressed,
|
||||
});
|
||||
@@ -654,6 +693,7 @@ class _SelectedTabDetails extends StatelessWidget {
|
||||
|
||||
return _TabItemRow(
|
||||
item: item,
|
||||
stockByProductId: stockByProductId,
|
||||
onQuantityChanged: onItemQuantityChanged,
|
||||
);
|
||||
},
|
||||
@@ -706,14 +746,21 @@ class _SelectedTabDetails extends StatelessWidget {
|
||||
|
||||
class _TabItemRow extends StatelessWidget {
|
||||
final TabItem item;
|
||||
final Map<String, int> stockByProductId;
|
||||
final Future<void> Function(TabItem item, int quantity) onQuantityChanged;
|
||||
|
||||
const _TabItemRow({required this.item, required this.onQuantityChanged});
|
||||
const _TabItemRow({
|
||||
required this.item,
|
||||
required this.stockByProductId,
|
||||
required this.onQuantityChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
final l10n = AppLocalizations.of(context);
|
||||
final availableStock = stockByProductId[item.productId];
|
||||
final canIncrease = availableStock == null || availableStock > 0;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
@@ -771,18 +818,28 @@ class _TabItemRow extends StatelessWidget {
|
||||
),
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () async {
|
||||
try {
|
||||
await onQuantityChanged(item, item.quantity + 1);
|
||||
} catch (e, stack) {
|
||||
Sentry.captureException(e, stackTrace: stack);
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.couldNotUpdateQuantity)),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
onPressed: canIncrease
|
||||
? () async {
|
||||
try {
|
||||
await onQuantityChanged(item, item.quantity + 1);
|
||||
} catch (e, stack) {
|
||||
if (e is! InsufficientStockException) {
|
||||
Sentry.captureException(e, stackTrace: stack);
|
||||
}
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
e is InsufficientStockException
|
||||
? l10n.productOutOfStock
|
||||
: l10n.couldNotUpdateQuantity,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.add_rounded, size: 18),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -22,7 +23,7 @@ class SettingsScreenView extends StatefulWidget {
|
||||
|
||||
class _SettingsScreenViewState extends State<SettingsScreenView> {
|
||||
String _appVersion = '';
|
||||
int _versionTaps = 0;
|
||||
Timer? _versionHoldTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -41,13 +42,23 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
|
||||
return info.version;
|
||||
}
|
||||
|
||||
void _onVersionTap() {
|
||||
_versionTaps++;
|
||||
void _startVersionHold() {
|
||||
_versionHoldTimer?.cancel();
|
||||
_versionHoldTimer = Timer(const Duration(seconds: 3), () {
|
||||
_versionHoldTimer = null;
|
||||
if (mounted) context.push('/dev');
|
||||
});
|
||||
}
|
||||
|
||||
if (_versionTaps >= 7) {
|
||||
_versionTaps = 0;
|
||||
context.push('/dev');
|
||||
}
|
||||
void _cancelVersionHold() {
|
||||
_versionHoldTimer?.cancel();
|
||||
_versionHoldTimer = null;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cancelVersionHold();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _loadVersion() async {
|
||||
@@ -277,6 +288,35 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
|
||||
}
|
||||
},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.grid_view_rounded,
|
||||
title: l10n.productGridRows,
|
||||
subtitle: l10n.rowsCount(settings.barGridRows),
|
||||
onTap: () async {
|
||||
final selected = await showModalBottomSheet<int>(
|
||||
context: context,
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (final rows in [2, 3, 4, 5, 6])
|
||||
RadioListTile<int>(
|
||||
value: rows,
|
||||
groupValue: settings.barGridRows,
|
||||
title: Text(l10n.rowsCount(rows)),
|
||||
onChanged: (value) =>
|
||||
Navigator.pop(context, value),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (selected != null) {
|
||||
await settingsViewModel.updateBarGridRows(selected);
|
||||
}
|
||||
},
|
||||
),
|
||||
_SettingsTile(
|
||||
icon: Icons.brightness_6_rounded,
|
||||
title: l10n.theme,
|
||||
@@ -334,7 +374,9 @@ class _SettingsScreenViewState extends State<SettingsScreenView> {
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
GestureDetector(
|
||||
onTap: _onVersionTap,
|
||||
onTapDown: (_) => _startVersionHold(),
|
||||
onTapUp: (_) => _cancelVersionHold(),
|
||||
onTapCancel: _cancelVersionHold,
|
||||
child: Center(
|
||||
child: Text(
|
||||
l10n.version(_appVersion),
|
||||
|
||||
Reference in New Issue
Block a user