import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'core/auth/auth_controller.dart'; import 'features/accounts/accounts_page.dart'; import 'features/cashflow/cashflow_page.dart'; import 'features/categories/categories_page.dart'; import 'features/events/events_page.dart'; import 'features/goals/goals_page.dart'; import 'features/health/health_page.dart'; import 'features/home/home_page.dart'; import 'features/income/income_page.dart'; import 'features/imports/import_preview_page.dart'; import 'features/imports/imports_page.dart'; import 'features/login/login_page.dart'; import 'features/pending/pending_page.dart'; import 'features/portfolio/instrument_page.dart'; import 'features/portfolio/portfolio_page.dart'; import 'features/portfolios/portfolios_page.dart'; import 'features/rebalance/rebalance_page.dart'; import 'features/rules/rules_page.dart'; import 'features/settings/settings_page.dart'; import 'features/shell/analytics_page.dart'; import 'features/shell/app_shell.dart'; import 'features/tax/tax_page.dart'; import 'features/transactions/transactions_page.dart'; /// Where to go after signing in: the page the user was on, if `from` is an in-app path. String _returnTo(String? from) { final inApp = from != null && from.startsWith('/') && !from.startsWith('//'); return inApp && !from.startsWith('/login') ? from : '/'; } final routerProvider = Provider((ref) { final auth = ValueNotifier(ref.read(authControllerProvider)); ref.listen(authControllerProvider, (_, next) => auth.value = next); ref.onDispose(auth.dispose); return GoRouter( initialLocation: '/', refreshListenable: auth, redirect: (context, state) { final status = auth.value.status; final atLogin = state.matchedLocation == '/login'; return switch (status) { // A reload starts here while the stored session is still being restored: the address // is kept in `from` so signing back in lands on it instead of on the home page. A // deliberate sign-out is `signedOut` from the start and carries no `from`. AuthStatus.unknown => atLogin ? null : Uri( path: '/login', queryParameters: {'from': state.uri.toString()}, ).toString(), AuthStatus.signedOut => atLogin ? null : '/login', AuthStatus.signedIn => atLogin ? _returnTo(state.uri.queryParameters['from']) : null, }; }, routes: [ GoRoute(path: '/login', builder: (_, _) => const LoginPage()), ShellRoute( builder: (context, state, child) => AppShell(location: state.matchedLocation, child: child), routes: [ GoRoute(path: '/', builder: (_, _) => const HomePage()), GoRoute(path: '/accounts', builder: (_, _) => const AccountsPage()), GoRoute(path: '/portfolio', builder: (_, _) => const PortfolioPage()), GoRoute( path: '/portfolio/instrument/:id', builder: (_, state) => InstrumentPage( instrumentId: int.parse(state.pathParameters['id']!), ), ), // Аналитика: one navigation destination, four contract routes. The hub is what // the shell points at; each screen below keeps its own top-level path and stays // deep-linkable (see `alsoMatches` in `app_shell.dart`). GoRoute( path: '/analytics', builder: (_, _) => const AnalyticsHubPage(), ), GoRoute(path: '/income', builder: (_, _) => const IncomePage()), GoRoute( path: '/portfolios', builder: (_, _) => const PortfoliosPage(), ), GoRoute(path: '/rebalance', builder: (_, _) => const RebalancePage()), GoRoute(path: '/goals', builder: (_, _) => const GoalsPage()), GoRoute(path: '/tax', builder: (_, _) => const TaxPage()), GoRoute(path: '/events', builder: (_, _) => const EventsPage()), GoRoute(path: '/imports', builder: (_, _) => const ImportsPage()), GoRoute( path: '/imports/:id', builder: (_, state) => ImportPreviewPage( importId: int.parse(state.pathParameters['id']!), ), ), GoRoute( path: '/instruments/pending', builder: (_, _) => const PendingInstrumentsPage(), ), GoRoute(path: '/cashflow', builder: (_, _) => const CashflowPage()), GoRoute( path: '/categories', builder: (_, state) => CategoriesPage( initialMonth: state.uri.queryParameters['month'], ), ), GoRoute( path: '/transactions', builder: (_, _) => const TransactionsPage(), ), GoRoute(path: '/rules', builder: (_, _) => const RulesPage()), GoRoute( path: '/health', builder: (_, state) => HealthPage( initialTab: state.uri.queryParameters['tab'] == 'quality' ? 1 : 0, ), ), GoRoute(path: '/settings', builder: (_, _) => const SettingsPage()), ], ), ], ); });