import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../providers/providers.dart'; import '../../sources/source.dart'; import '../widgets/comic_cover.dart'; import '../widgets/source_logo.dart'; /// Catalog tab root helpers live in the router redirect; picker is [SourcePickerPage]. const _kLastCatalogSource = 'catalog_last_source_id'; Future saveLastCatalogSource(SourceId id) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_kLastCatalogSource, id.name); } Future loadLastCatalogSource() async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getString(_kLastCatalogSource); if (raw == null) return null; return SourceId.tryParse(raw); } class SourcePickerPage extends ConsumerStatefulWidget { const SourcePickerPage({super.key}); @override ConsumerState createState() => _SourcePickerPageState(); } class _SourcePickerPageState extends ConsumerState { SourceId? _last; @override void initState() { super.initState(); loadLastCatalogSource().then((id) { if (!mounted) return; setState(() => _last = id); }); } @override Widget build(BuildContext context) { final registry = ref.watch(sourceRegistryProvider); final sources = registry.all; final last = _last; final continueSource = last != null && registry.isEnabled(last) ? registry.get(last) : null; return Scaffold( appBar: AppBar( title: const Text('Catalog'), actions: [ const PeekModeToggleButton(), IconButton( tooltip: 'Settings', icon: const Icon(Icons.settings_outlined), onPressed: () => context.push('/settings'), ), ], ), body: ListView( padding: const EdgeInsets.symmetric(vertical: 8), children: [ if (continueSource != null) Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 4), child: Align( alignment: Alignment.centerLeft, child: ActionChip( avatar: SourceLogo(sourceId: continueSource.id, size: 18), label: Text('Continue ยท ${continueSource.displayName}'), onPressed: () => _open(continueSource.id), ), ), ), for (final s in sources) ListTile( leading: SourceLogo(sourceId: s.id), title: Text(s.displayName), subtitle: Text(s.blurb), trailing: const Icon(Icons.chevron_right), onTap: () => _open(s.id), ), ], ), ); } void _open(SourceId id) { saveLastCatalogSource(id); context.push('/catalog/${id.name}'); } } /// Lists [ComicSource.catalogMenus] for one enabled source. class SourceHomePage extends ConsumerWidget { const SourceHomePage({ super.key, required this.sourceId, this.embeddedAsRoot = false, }); final SourceId sourceId; final bool embeddedAsRoot; @override Widget build(BuildContext context, WidgetRef ref) { final registry = ref.watch(sourceRegistryProvider); if (!registry.isEnabled(sourceId)) { return Scaffold( appBar: AppBar(title: const Text('Catalog')), body: const Center(child: Text('Source not enabled in this build.')), ); } final source = registry.get(sourceId); final menus = source.catalogMenus; return Scaffold( appBar: AppBar( title: Row( mainAxisSize: MainAxisSize.min, children: [ SourceLogo(sourceId: sourceId, size: 24), const SizedBox(width: 8), Text(source.displayName), ], ), leading: embeddedAsRoot ? null : IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { if (context.canPop()) { context.pop(); } else { context.go('/catalog'); } }, ), actions: [ const PeekModeToggleButton(), IconButton( tooltip: 'Settings', icon: const Icon(Icons.settings_outlined), onPressed: () => context.push('/settings'), ), ], ), body: ListView.separated( itemCount: menus.length, separatorBuilder: (_, _) => const Divider(height: 1), itemBuilder: (context, i) { final menu = menus[i]; return ListTile( leading: Icon(_iconFor(menu.kind)), title: Text(menu.title), trailing: const Icon(Icons.chevron_right), onTap: () { saveLastCatalogSource(sourceId); context.push('/catalog/${sourceId.name}/${menu.kind.pathSegment}'); }, ); }, ), ); } IconData _iconFor(CatalogMenuKind kind) { switch (kind) { case CatalogMenuKind.popular: return Icons.local_fire_department_outlined; case CatalogMenuKind.latest: return Icons.schedule_outlined; case CatalogMenuKind.official: return Icons.verified_outlined; case CatalogMenuKind.uncensored: return Icons.visibility_outlined; case CatalogMenuKind.recommended: return Icons.thumb_up_outlined; case CatalogMenuKind.search: return Icons.search; case CatalogMenuKind.hotToday: return Icons.wb_sunny_outlined; case CatalogMenuKind.hotWeek: return Icons.date_range_outlined; case CatalogMenuKind.hotMonth: return Icons.calendar_month_outlined; case CatalogMenuKind.directory: return Icons.grid_view_outlined; } } }