Files
kooltab/lib/app/router.dart
T

191 lines
5.6 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import '../viewmodels/admin_pin_view_model.dart';
import '../viewmodels/pin_lock_view_model.dart';
import '../views/admin_screen_view.dart';
import '../views/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';
import '../views/settings_view.dart';
import '../views/update_progress_view.dart';
import '../utils/app_update_util.dart';
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
String? _redirectApp({
required PinLockViewModel pinLockViewModel,
required AdminPinViewModel adminPinViewModel,
required GoRouterState state,
}) {
if (!pinLockViewModel.hasLoaded || !adminPinViewModel.hasLoaded) {
return null;
}
final location = state.uri.path;
final goingToLock = location == '/lock';
final goingToAdminLock = location == '/admin/lock';
final mustBeOnLock = _mustBeOnLock(pinLockViewModel);
if (mustBeOnLock && !goingToLock) return '/lock';
if (!mustBeOnLock && goingToLock) return '/bar';
final isAdminArea = _isAdminArea(location);
final isDebugShortcutArea = _isDebugShortcutArea(location);
if (isAdminArea &&
!isDebugShortcutArea &&
!goingToAdminLock &&
!adminPinViewModel.isUnlocked) {
return '/admin/lock';
}
if (goingToAdminLock && adminPinViewModel.isUnlocked) return '/admin';
return null;
}
bool _mustBeOnLock(PinLockViewModel pinLockViewModel) {
final needsPinSetup =
!pinLockViewModel.isPinSet && pinLockViewModel.pinRequired;
final isLocked =
pinLockViewModel.isPinSet &&
!pinLockViewModel.isUnlocked &&
pinLockViewModel.pinRequired;
return needsPinSetup || isLocked;
}
bool _isAdminArea(String location) {
return location == '/admin' ||
location.startsWith('/admin/') ||
location == '/products' ||
location.startsWith('/products/') ||
location == '/history' ||
location.startsWith('/history/');
}
bool _isDebugShortcutArea(String location) {
if (!kDebugMode) return false;
return location == '/products' ||
location.startsWith('/products/') ||
location == '/history' ||
location.startsWith('/history/');
}
GoRouter createAppRouter(PinLockViewModel pinLockViewModel, {
required AdminPinViewModel adminPinViewModel,
}) {
return GoRouter(
initialLocation: '/bar',
observers: [routeObserver, SentryNavigatorObserver()],
refreshListenable: Listenable.merge([pinLockViewModel, adminPinViewModel]),
redirect: (_, state) =>
_redirectApp(
pinLockViewModel: pinLockViewModel,
adminPinViewModel: adminPinViewModel,
state: state,
),
routes: [
GoRoute(path: '/', redirect: (context, state) => '/bar'),
GoRoute(
path: '/lock',
builder: (context, state) =>
PinEntryView(
mode: pinLockViewModel.isPinSet
? PinEntryMode.unlock
: PinEntryMode.create,
onSuccess: () {
context.go("/bar");
},
),
),
GoRoute(path: '/bar', builder: (context, state) => const BarScreenView()),
GoRoute(
path: '/admin/lock',
builder: (context, state) =>
PinEntryView(
mode: adminPinViewModel.isPinSet
? PinEntryMode.unlock
: PinEntryMode.create,
isAdmin: true,
onVerify: adminPinViewModel.verify,
onSet: adminPinViewModel.setPin,
errorMessage: () => adminPinViewModel.errorMessage,
onSuccess: () => context.go('/admin'),
),
),
GoRoute(
path: '/admin',
builder: (context, state) => const AdminScreenView(),
routes: [
GoRoute(
path: 'import',
builder: (context, state) => const ImportNamesView(),
),
],
),
GoRoute(
path: '/products',
builder: (context, state) => const ProductListView(),
routes: [
GoRoute(
path: 'new',
builder: (context, state) => const ProductFormView(),
),
GoRoute(
path: ':id/edit',
builder: (context, state) {
final productId = state.pathParameters['id']!;
return ProductFormView(productId: productId);
},
),
],
),
GoRoute(
path: '/history',
builder: (context, state) => const HistoryScreenView(),
),
GoRoute(
path: '/settings',
builder: (context, state) => const SettingsScreenView(),
),
GoRoute(
path: '/update-progress',
builder: (context, state) {
final update = state.extra as UpdateInfo;
final simulate = state.uri.queryParameters['simulate'] == 'true';
final simulateError =
state.uri.queryParameters['simulateError'] == 'true';
return UpdateProgressView(
update: update,
simulate: simulate,
simulateError: simulateError,
);
},
),
GoRoute(path: '/dev', builder: (context, state) => const DevMenuView()),
GoRoute(
path: '/error',
builder: (context, state) => const ErrorScreenView(),
),
],
);
}