import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../services/reader_direction.dart'; import '../sources/source.dart'; import '../sources/source_flags.dart'; import '../ui/catalog/source_picker_page.dart'; import '../ui/catalog_page.dart'; import '../ui/downloads_page.dart'; import '../ui/history_page.dart'; import '../ui/library_page.dart'; import '../ui/reader_page.dart'; import '../ui/settings_page.dart'; import '../ui/shell.dart'; import '../ui/title_page.dart'; final _rootKey = GlobalKey(); SourceId? _parseSourceId(String? raw) { if (raw == null) return null; return SourceId.tryParse(raw); } CatalogMenuKind? _parseMenu(String? raw) { if (raw == null) return null; for (final k in CatalogMenuKind.values) { if (k.pathSegment == raw) return k; } return null; } final routerProvider = Provider((ref) { return GoRouter( navigatorKey: _rootKey, initialLocation: '/catalog', routes: [ StatefulShellRoute.indexedStack( builder: (context, state, navigationShell) { return AppShell(navigationShell: navigationShell); }, branches: [ StatefulShellBranch( routes: [ // Sibling routes (not nested under picker) so back stack is clean. GoRoute( path: '/catalog', redirect: (context, state) { final enabled = enabledSourceIds(); if (enabled.length == 1) { return '/catalog/${enabled.first.name}'; } return null; }, builder: (context, state) => const SourcePickerPage(), ), GoRoute( path: '/catalog/:sourceId', builder: (context, state) { final id = _parseSourceId(state.pathParameters['sourceId']); if (id == null) { return const Scaffold( body: Center(child: Text('Unknown source')), ); } final single = enabledSourceIds().length == 1; return SourceHomePage( sourceId: id, embeddedAsRoot: single, ); }, routes: [ GoRoute( path: ':menu', builder: (context, state) { final id = _parseSourceId(state.pathParameters['sourceId']); final menu = _parseMenu(state.pathParameters['menu']); if (id == null || menu == null) { return const Scaffold( body: Center(child: Text('Unknown catalog feed')), ); } return CatalogFeedPage(sourceId: id, menuKind: menu); }, ), ], ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/library', builder: (context, state) => const LibraryPage(), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/history', builder: (context, state) => const HistoryPage(), ), ], ), StatefulShellBranch( routes: [ GoRoute( path: '/downloads', builder: (context, state) => const DownloadsPage(), routes: [ GoRoute( path: 'queue', builder: (context, state) => const DownloadsQueuePage(), ), ], ), ], ), ], ), GoRoute( path: '/settings', builder: (context, state) => const SettingsPage(), ), GoRoute( path: '/title/:id', builder: (context, state) { final id = int.parse(state.pathParameters['id']!); return TitlePage(titleId: id); }, ), GoRoute( path: '/read/:titleId/:chapterId', builder: (context, state) { final titleId = int.parse(state.pathParameters['titleId']!); final chapterId = int.parse(state.pathParameters['chapterId']!); final modeParam = state.uri.queryParameters['mode']; ReaderMode? initialMode; if (modeParam == 'paged') { initialMode = ReaderMode.paged; } else if (modeParam == 'webtoon') { initialMode = ReaderMode.webtoon; } return ReaderPage( titleId: titleId, chapterId: chapterId, initialMode: initialMode, ); }, ), ], ); });