fix: alot
This commit is contained in:
@@ -8,6 +8,7 @@ import '../database/app_database.dart';
|
||||
import '../services/bar_tab_service.dart';
|
||||
import '../services/default_product_seeder.dart';
|
||||
import '../services/export_service.dart';
|
||||
import '../services/remote_sync_service.dart';
|
||||
import '../viewmodels/bar_screen_view_model.dart';
|
||||
import '../viewmodels/product_list_view_model.dart';
|
||||
|
||||
@@ -38,9 +39,11 @@ class _AppBootstrapState extends State<AppBootstrap> {
|
||||
context.read<ProductListViewModel>().ensureLoaded();
|
||||
context.read<BarScreenViewModel>().ensureLoaded();
|
||||
|
||||
final syncService = context.read<RemoteSyncService>();
|
||||
unawaited(
|
||||
DefaultExportService(
|
||||
barTabService: context.read<BarTabService>(),
|
||||
authToken: () => syncService.authToken,
|
||||
).uploadToServer(),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,28 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Locks once the app returns after being in the background for at least
|
||||
/// [gracePeriod], so a quick trip to the image picker or installer doesn't.
|
||||
class AppLifecycleLockObserver extends WidgetsBindingObserver {
|
||||
final VoidCallback onLock;
|
||||
final VoidCallback? onBackground;
|
||||
final VoidCallback? onForeground;
|
||||
final bool Function()? shouldLock;
|
||||
final Duration gracePeriod;
|
||||
final DateTime Function() _clock;
|
||||
|
||||
DateTime? _backgroundedAt;
|
||||
|
||||
AppLifecycleLockObserver({
|
||||
required this.onLock,
|
||||
this.onBackground,
|
||||
this.onForeground,
|
||||
this.shouldLock,
|
||||
});
|
||||
this.gracePeriod = const Duration(seconds: 30),
|
||||
DateTime Function()? clock,
|
||||
}) : _clock = clock ?? DateTime.now;
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
switch (state) {
|
||||
case AppLifecycleState.inactive:
|
||||
break;
|
||||
case AppLifecycleState.hidden:
|
||||
case AppLifecycleState.paused:
|
||||
case AppLifecycleState.detached:
|
||||
if (shouldLock?.call() ?? true) onLock();
|
||||
if (_backgroundedAt != null) return;
|
||||
_backgroundedAt = _clock();
|
||||
onBackground?.call();
|
||||
case AppLifecycleState.resumed:
|
||||
final backgroundedAt = _backgroundedAt;
|
||||
if (backgroundedAt == null) return;
|
||||
_backgroundedAt = null;
|
||||
|
||||
final away = _clock().difference(backgroundedAt);
|
||||
if (away >= gracePeriod && (shouldLock?.call() ?? true)) onLock();
|
||||
onForeground?.call();
|
||||
}
|
||||
}
|
||||
|
||||
+32
-24
@@ -12,7 +12,6 @@ import '../views/bar/bar_screen_view.dart';
|
||||
import '../views/dev_menu_view.dart';
|
||||
import '../views/error_screen_view.dart';
|
||||
import '../views/history_screen_view.dart';
|
||||
import '../views/import_names_view.dart';
|
||||
import '../views/pin_lock_view.dart';
|
||||
import '../views/product_form_view.dart';
|
||||
import '../views/product_list_view.dart';
|
||||
@@ -35,24 +34,18 @@ String? _redirectApp({
|
||||
}
|
||||
|
||||
final location = state.uri.path;
|
||||
final isConfigured = remoteSyncViewModel.isConfigured;
|
||||
final returnTo = _returnLocation(state);
|
||||
|
||||
if (!isConfigured && location != '/register') {
|
||||
return '/register';
|
||||
if (remoteSyncViewModel.isConfigured && location == '/register') {
|
||||
return '/admin';
|
||||
}
|
||||
|
||||
if (isConfigured && location == '/register') {
|
||||
return '/bar';
|
||||
}
|
||||
|
||||
if (!isConfigured) return null;
|
||||
|
||||
final goingToLock = location == '/lock';
|
||||
final goingToAdminLock = location == '/admin/lock';
|
||||
final mustBeOnLock = _mustBeOnLock(pinLockViewModel);
|
||||
|
||||
if (mustBeOnLock && !goingToLock) return '/lock';
|
||||
if (!mustBeOnLock && goingToLock) return '/bar';
|
||||
if (mustBeOnLock && !goingToLock) return _lockLocation('/lock', state);
|
||||
if (!mustBeOnLock && goingToLock) return returnTo ?? '/bar';
|
||||
|
||||
final isAdminArea = _isAdminArea(location);
|
||||
final isDebugShortcutArea = _isDebugShortcutArea(location);
|
||||
@@ -61,14 +54,34 @@ String? _redirectApp({
|
||||
!isDebugShortcutArea &&
|
||||
!goingToAdminLock &&
|
||||
!adminPinViewModel.isUnlocked) {
|
||||
return '/admin/lock';
|
||||
return _lockLocation('/admin/lock', state);
|
||||
}
|
||||
|
||||
if (goingToAdminLock && adminPinViewModel.isUnlocked) return '/admin';
|
||||
if (goingToAdminLock && adminPinViewModel.isUnlocked) {
|
||||
return returnTo ?? '/admin';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Sends the user back where they were headed once the PIN is entered.
|
||||
String _lockLocation(String lockPath, GoRouterState state) {
|
||||
return Uri(
|
||||
path: lockPath,
|
||||
queryParameters: {'from': state.uri.toString()},
|
||||
).toString();
|
||||
}
|
||||
|
||||
String? _returnLocation(GoRouterState state) {
|
||||
final from = state.uri.queryParameters['from'];
|
||||
if (from == null || !from.startsWith('/')) return null;
|
||||
|
||||
final path = Uri.parse(from).path;
|
||||
if (path == '/lock' || path == '/admin/lock') return null;
|
||||
|
||||
return from;
|
||||
}
|
||||
|
||||
bool _mustBeOnLock(PinLockViewModel pinLockViewModel) {
|
||||
final needsPinSetup =
|
||||
!pinLockViewModel.isPinSet && pinLockViewModel.pinRequired;
|
||||
@@ -83,6 +96,9 @@ bool _mustBeOnLock(PinLockViewModel pinLockViewModel) {
|
||||
bool _isAdminArea(String location) {
|
||||
return location == '/admin' ||
|
||||
location.startsWith('/admin/') ||
|
||||
location == '/settings' ||
|
||||
location == '/dev' ||
|
||||
location == '/register' ||
|
||||
location == '/products' ||
|
||||
location.startsWith('/products/') ||
|
||||
location == '/history' ||
|
||||
@@ -135,9 +151,7 @@ GoRouter createAppRouter({
|
||||
mode: pinLockViewModel.isPinSet
|
||||
? PinEntryMode.unlock
|
||||
: PinEntryMode.create,
|
||||
onSuccess: () {
|
||||
context.go('/bar');
|
||||
},
|
||||
onSuccess: () => context.go(_returnLocation(state) ?? '/bar'),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -153,19 +167,13 @@ GoRouter createAppRouter({
|
||||
onVerify: adminPinViewModel.verify,
|
||||
onSet: adminPinViewModel.setPin,
|
||||
error: () => adminPinViewModel.error,
|
||||
onSuccess: () => context.go('/admin'),
|
||||
onSuccess: () => context.go(_returnLocation(state) ?? '/admin'),
|
||||
),
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
path: '/admin',
|
||||
builder: (context, state) => const AdminScreenView(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'import',
|
||||
builder: (context, state) => const ImportNamesView(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
GoRoute(
|
||||
|
||||
Reference in New Issue
Block a user