130 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'package:flutter/material.dart';
 | 
						|
import 'package:go_router/go_router.dart';
 | 
						|
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
						|
import 'package:moneymgr_mobile/providers/auth_state.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/login/login_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/login/manual_auth_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/login/qr_auth_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/profile/profile_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/scan/scan_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/scan_details/scan_details.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/scans_list/scans_list_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/routes/settings/settings_screen.dart';
 | 
						|
import 'package:moneymgr_mobile/services/router/routes_list.dart';
 | 
						|
import 'package:moneymgr_mobile/services/storage/prefs.dart';
 | 
						|
import 'package:moneymgr_mobile/widgets/load_startup_data.dart';
 | 
						|
import 'package:moneymgr_mobile/widgets/scaffold_with_navigation.dart';
 | 
						|
import 'package:riverpod_annotation/riverpod_annotation.dart';
 | 
						|
 | 
						|
part 'router.g.dart';
 | 
						|
 | 
						|
/// The router config for the app.
 | 
						|
@riverpod
 | 
						|
GoRouter router(Ref ref) {
 | 
						|
  // Local notifier for the current auth state. The purpose of this notifier is
 | 
						|
  // to provide a [Listenable] to the [GoRouter] exposed by this provider.
 | 
						|
  final authStateNotifier = ValueNotifier(AuthState.unknown);
 | 
						|
  ref
 | 
						|
    ..onDispose(authStateNotifier.dispose)
 | 
						|
    ..listen(currentAuthStateProvider, (_, value) {
 | 
						|
      authStateNotifier.value = value;
 | 
						|
    });
 | 
						|
 | 
						|
  final prefs = ref.read(prefsProvider).requireValue;
 | 
						|
 | 
						|
  // This is the only place you need to define your navigation items. The items
 | 
						|
  // will be propagated automatically to the router and the navigation bar/rail
 | 
						|
  // of the scaffold.
 | 
						|
  //
 | 
						|
  // To configure the authentication state needed to access a particular item,
 | 
						|
  // see [AuthState] enum.
 | 
						|
  final navigationItems = [
 | 
						|
    NavigationItem(
 | 
						|
      path: capturePage,
 | 
						|
      body: (_) => ScanScreen(),
 | 
						|
      icon: Icons.camera_alt_outlined,
 | 
						|
      selectedIcon: Icons.camera_alt,
 | 
						|
      label: "Scan",
 | 
						|
    ),
 | 
						|
    NavigationItem(
 | 
						|
      path: scansPage,
 | 
						|
      body: (_) => ScansListScreen(),
 | 
						|
      icon: Icons.list,
 | 
						|
      selectedIcon: Icons.list_alt,
 | 
						|
      label: "List",
 | 
						|
      routes: [
 | 
						|
        GoRoute(
 | 
						|
          path: ":id",
 | 
						|
          builder: (_, state) {
 | 
						|
            final id = int.parse(state.pathParameters["id"]!);
 | 
						|
            return ScanDetailScreen(id: id);
 | 
						|
          },
 | 
						|
        ),
 | 
						|
      ],
 | 
						|
    ),
 | 
						|
    NavigationItem(
 | 
						|
      path: profilePage,
 | 
						|
      body: (_) => ProfileScreen(),
 | 
						|
      icon: Icons.person_outline,
 | 
						|
      selectedIcon: Icons.person,
 | 
						|
      label: 'Profile',
 | 
						|
    ),
 | 
						|
  ];
 | 
						|
 | 
						|
  final router = GoRouter(
 | 
						|
    debugLogDiagnostics: true,
 | 
						|
    initialLocation: prefs.startOnScansListScreen() ? scansPage : capturePage,
 | 
						|
    routes: [
 | 
						|
      GoRoute(path: homePage, builder: (_, _) => const Scaffold()),
 | 
						|
      GoRoute(path: authPage, builder: (_, _) => const LoginScreen()),
 | 
						|
      GoRoute(path: qrAuthPath, builder: (_, _) => const QrAuthScreen()),
 | 
						|
      GoRoute(
 | 
						|
        path: manualAuthPage,
 | 
						|
        builder: (_, _) => const ManualAuthScreen(),
 | 
						|
      ),
 | 
						|
      GoRoute(path: settingsPage, builder: (_, _) => const SettingsScreen()),
 | 
						|
 | 
						|
      // Configuration for the bottom navigation bar routes. The routes themselves
 | 
						|
      // should be defined in [navigationItems]. Modification to this [ShellRoute]
 | 
						|
      // config is rarely needed.
 | 
						|
      ShellRoute(
 | 
						|
        builder: (_, _, child) => child,
 | 
						|
        routes: [
 | 
						|
          for (final (index, item) in navigationItems.indexed)
 | 
						|
            GoRoute(
 | 
						|
              path: item.path,
 | 
						|
              pageBuilder: (context, _) => NoTransitionPage(
 | 
						|
                child: LoadStartupData(
 | 
						|
                  child: ScaffoldWithNavigation(
 | 
						|
                    selectedIndex: index,
 | 
						|
                    navigationItems: navigationItems,
 | 
						|
                    child: item.body(context),
 | 
						|
                  ),
 | 
						|
                ),
 | 
						|
              ),
 | 
						|
              routes: item.routes,
 | 
						|
            ),
 | 
						|
        ],
 | 
						|
      ),
 | 
						|
    ],
 | 
						|
    refreshListenable: authStateNotifier,
 | 
						|
    redirect: (_, state) {
 | 
						|
      // Get the current auth state.
 | 
						|
      final authState = ref.read(currentAuthStateProvider);
 | 
						|
 | 
						|
      // Check if the current path is allowed for the current auth state. If not,
 | 
						|
      // redirect to the redirect target of the current auth state.
 | 
						|
      if (authState.allowedPaths?.contains(state.fullPath) == false ||
 | 
						|
          authState.forbiddenPaths?.contains(state.fullPath) == true) {
 | 
						|
        return authState.redirectPath;
 | 
						|
      }
 | 
						|
 | 
						|
      // If the current path is allowed for the current auth state, don't redirect.
 | 
						|
      return null;
 | 
						|
    },
 | 
						|
  );
 | 
						|
  ref.onDispose(router.dispose);
 | 
						|
 | 
						|
  return router;
 | 
						|
}
 |