worldhopper/lib/config/router.dart

166 lines
6.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:worldhopper/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:worldhopper/config/constants.dart';
import 'package:worldhopper/screens/servers/server_list_screen.dart';
import 'package:worldhopper/screens/servers/add_server_screen.dart';
import 'package:worldhopper/screens/servers/edit_server_screen.dart';
import 'package:worldhopper/screens/browse/library_browser_screen.dart';
import 'package:worldhopper/screens/browse/feed_screen.dart';
import 'package:worldhopper/screens/publication/publication_detail_screen.dart';
import 'package:worldhopper/screens/reader/reader_screen.dart';
import 'package:worldhopper/screens/reader/epub_reader_screen.dart';
import 'package:worldhopper/screens/library/library_screen.dart';
import 'package:worldhopper/screens/settings/settings_screen.dart';
import 'package:worldhopper/screens/shell/main_shell_screen.dart';
import 'package:worldhopper/models/opds_entry.dart';
/// Application router configuration using GoRouter
class AppRouter {
AppRouter._();
static final GlobalKey<NavigatorState> _libraryNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'library');
static final GlobalKey<NavigatorState> _serversNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'servers');
static final GlobalKey<NavigatorState> _settingsNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'settings');
/// Navigator keys for each bottom navigation branch, indexed by tab position.
static final List<GlobalKey<NavigatorState>> branchNavigatorKeys = [
_libraryNavigatorKey,
_serversNavigatorKey,
_settingsNavigatorKey,
];
static final GoRouter router = GoRouter(
initialLocation: AppConstants.routeLibrary,
routes: [
// StatefulShellRoute for bottom navigation
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return MainShellScreen(navigationShell: navigationShell);
},
branches: [
// Branch 1: Library
StatefulShellBranch(
navigatorKey: _libraryNavigatorKey,
routes: [
GoRoute(
path: AppConstants.routeLibrary,
name: 'library',
builder: (context, state) => const LibraryScreen(),
),
],
),
// Branch 2: Servers (home)
StatefulShellBranch(
navigatorKey: _serversNavigatorKey,
routes: [
GoRoute(
path: AppConstants.routeServerList,
name: 'server-list',
builder: (context, state) => const ServerListScreen(),
routes: [
// Nested browse routes
GoRoute(
path: 'browse/:serverId',
name: 'browse-library',
builder: (context, state) {
final serverId = state.pathParameters['serverId']!;
return LibraryBrowserScreen(serverId: serverId);
},
routes: [
GoRoute(
path: 'feed',
name: 'browse-feed',
builder: (context, state) {
final serverId = state.pathParameters['serverId']!;
final extra = state.extra as Map<String, dynamic>;
return FeedScreen(
serverId: serverId,
feedUrl: extra['feedUrl'] as String,
feedTitle: extra['feedTitle'] as String,
);
},
),
],
),
],
),
],
),
// Branch 3: Settings
StatefulShellBranch(
navigatorKey: _settingsNavigatorKey,
routes: [
GoRoute(
path: AppConstants.routeSettings,
name: 'settings',
builder: (context, state) => const SettingsScreen(),
),
],
),
],
),
// Standalone routes (full-screen, no bottom navigation)
GoRoute(
path: AppConstants.routeAddServer,
name: 'add-server',
builder: (context, state) => const AddServerScreen(),
),
GoRoute(
path: '${AppConstants.routeEditServer}/:id',
name: 'edit-server',
builder: (context, state) {
final serverId = state.pathParameters['id']!;
return EditServerScreen(serverId: serverId);
},
),
GoRoute(
path: AppConstants.routePublicationDetail,
name: 'publication-detail',
builder: (context, state) {
final entry = state.extra as Map<String, dynamic>;
return PublicationDetailScreen(
entry: entry['entry'] as OPDSEntry,
serverId: entry['serverId'] as String,
feedUrl: entry['feedUrl'] as String?,
);
},
),
GoRoute(
path: AppConstants.routeReader,
name: 'reader',
builder: (context, state) {
final data = state.extra as Map<String, dynamic>;
return ReaderScreen(
entry: data['entry'] as OPDSEntry,
serverId: data['serverId'] as String,
initialPage: data['initialPage'] as int? ?? 0,
feedUrl: data['feedUrl'] as String?,
);
},
),
GoRoute(
path: AppConstants.routeEpubReader,
name: 'epub-reader',
builder: (context, state) {
final data = state.extra as Map<String, dynamic>;
return EpubReaderScreen(
entry: data['entry'] as OPDSEntry,
serverId: data['serverId'] as String,
feedUrl: data['feedUrl'] as String?,
);
},
),
],
errorBuilder: (context, state) => Scaffold(
body: Center(
child: Text(
AppLocalizations.of(context).routeNotFound(state.uri.toString())),
),
),
);
}