166 lines
6.1 KiB
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())),
|
|
),
|
|
),
|
|
);
|
|
}
|