Files
cxyz/cxyz-android/lib/router.dart
T
nsrb a7c6058540 Add cxyz Android project structure and initial configuration
- Introduced a new Flutter project for the cxyz Android manga/comic reader, including essential files such as pubspec.yaml, AndroidManifest.xml, and Gradle configuration.
- Added .gitignore files to exclude unnecessary files and directories for both the main project and Android-specific files.
- Implemented initial README.md with project description, features, setup instructions, and API details for ComicLand, MangaRead, and MangaTown.
- Configured analysis options and dependencies in pubspec.yaml to support Flutter development.
- Established a pnpm workspace and lockfile for dependency management.
- Included various Android resources such as icons, styles, and launch backgrounds for a complete application setup.
2026-08-29 17:50:31 +07:00

156 lines
4.9 KiB
Dart

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<NavigatorState>();
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<GoRouter>((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,
);
},
),
],
);
});