import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:hive_flutter/hive_flutter.dart'; import '../data/local/hive_boxes.dart'; import '../data/local/models/app_settings.dart'; import '../core/widgets/bottom_nav_bar.dart'; import '../features/dashboard/presentation/dashboard_screen.dart'; import '../features/imsakiyah/presentation/imsakiyah_screen.dart'; import '../features/checklist/presentation/checklist_screen.dart'; import '../features/laporan/presentation/laporan_screen.dart'; import '../features/tools/presentation/tools_screen.dart'; import '../features/dzikir/presentation/dzikir_screen.dart'; import '../features/doa/presentation/doa_screen.dart'; import '../features/hadits/presentation/hadits_screen.dart'; import '../features/qibla/presentation/qibla_screen.dart'; import '../features/quran/presentation/quran_screen.dart'; import '../features/quran/presentation/quran_reading_screen.dart'; import '../features/quran/presentation/quran_murattal_screen.dart'; import '../features/quran/presentation/quran_bookmarks_screen.dart'; import '../features/quran/presentation/quran_enrichment_screen.dart'; import '../features/notifications/presentation/notification_center_screen.dart'; import '../features/settings/presentation/settings_screen.dart'; /// Navigation key for the shell navigator (bottom-nav screens). final _rootNavigatorKey = GlobalKey(); final _shellNavigatorKey = GlobalKey(); /// GoRouter configuration per PRD §5.2. final GoRouter appRouter = GoRouter( navigatorKey: _rootNavigatorKey, initialLocation: '/', routes: [ // ── Shell route (bottom nav persists) ── ShellRoute( navigatorKey: _shellNavigatorKey, pageBuilder: (context, state, child) => NoTransitionPage( key: ValueKey('shell-${state.pageKey.value}'), child: _ScaffoldWithNav(child: child), ), routes: [ GoRoute( path: '/', pageBuilder: (context, state) => NoTransitionPage( key: state.pageKey, child: const DashboardScreen(), ), routes: [ GoRoute( path: 'qibla', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const QiblaScreen(), ), ], ), GoRoute( path: '/imsakiyah', pageBuilder: (context, state) => NoTransitionPage( key: state.pageKey, child: const ImsakiyahScreen(), ), ), GoRoute( path: '/checklist', pageBuilder: (context, state) => NoTransitionPage( key: state.pageKey, child: const ChecklistScreen(), ), ), GoRoute( path: '/laporan', pageBuilder: (context, state) => NoTransitionPage( key: state.pageKey, child: const LaporanScreen(), ), ), GoRoute( path: '/tools', pageBuilder: (context, state) => NoTransitionPage( key: state.pageKey, child: const ToolsScreen(), ), routes: [ GoRoute( path: 'dzikir', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const DzikirScreen(), ), GoRoute( path: 'quran', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const QuranScreen(), routes: [ GoRoute( path: 'enrichment', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const QuranEnrichmentScreen(), ), GoRoute( path: 'bookmarks', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const QuranBookmarksScreen(), ), GoRoute( path: ':surahId', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) { final surahId = state.pathParameters['surahId']!; final startVerse = int.tryParse( state.uri.queryParameters['startVerse'] ?? ''); return QuranReadingScreen( surahId: surahId, initialVerse: startVerse); }, routes: [ GoRoute( path: 'murattal', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) { final surahId = state.pathParameters['surahId']!; final qariId = state.uri.queryParameters['qariId']; final autoplay = state.uri.queryParameters['autoplay'] == 'true'; return QuranMurattalScreen( surahId: surahId, initialQariId: qariId, autoPlay: autoplay, ); }, ), ], ), ], ), GoRoute( path: 'qibla', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const QiblaScreen(), ), GoRoute( path: 'doa', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const DoaScreen(), ), GoRoute( path: 'hadits', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const HaditsScreen(), ), ], ), // Simple Mode Tab: Zikir GoRoute( path: '/dzikir', builder: (context, state) => const DzikirScreen(isSimpleModeTab: true), ), // Simple Mode Tab: Tilawah GoRoute( path: '/quran', builder: (context, state) => const QuranScreen(isSimpleModeTab: true), routes: [ GoRoute( path: 'enrichment', builder: (context, state) => const QuranEnrichmentScreen(isSimpleModeTab: true), ), GoRoute( path: 'bookmarks', builder: (context, state) => const QuranBookmarksScreen(isSimpleModeTab: true), ), GoRoute( path: ':surahId', builder: (context, state) { final surahId = state.pathParameters['surahId']!; final startVerse = int.tryParse(state.uri.queryParameters['startVerse'] ?? ''); return QuranReadingScreen( surahId: surahId, initialVerse: startVerse, isSimpleModeTab: true); }, routes: [ GoRoute( path: 'murattal', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) { final surahId = state.pathParameters['surahId']!; final qariId = state.uri.queryParameters['qariId']; final autoplay = state.uri.queryParameters['autoplay'] == 'true'; return QuranMurattalScreen( surahId: surahId, initialQariId: qariId, autoPlay: autoplay, isSimpleModeTab: true, ); }, ), ], ), ], ), GoRoute( path: '/doa', builder: (context, state) => const DoaScreen(isSimpleModeTab: true), ), GoRoute( path: '/hadits', builder: (context, state) => const HaditsScreen(isSimpleModeTab: true), ), ], ), // ── Settings (pushed, no bottom nav) ── GoRoute( path: '/notifications', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const NotificationCenterScreen(), ), GoRoute( path: '/settings', parentNavigatorKey: _rootNavigatorKey, builder: (context, state) => const SettingsScreen(), ), ], ); /// Scaffold wrapper that provides the persistent bottom nav bar. class _ScaffoldWithNav extends StatefulWidget { const _ScaffoldWithNav({required this.child}); final Widget child; @override State<_ScaffoldWithNav> createState() => _ScaffoldWithNavState(); } class _ScaffoldWithNavState extends State<_ScaffoldWithNav> { DateTime? _lastBackPressedAt; bool _shouldHideBottomNav({ required bool isSimpleMode, required String path, }) { if (!isSimpleMode) return false; if (path == '/dzikir') return true; if (!path.startsWith('/quran/')) return false; final tail = path.substring('/quran/'.length); if (tail == 'bookmarks' || tail == 'enrichment') return false; return !tail.contains('/'); } /// Maps route locations to bottom nav indices. int _currentIndex(BuildContext context) { final location = GoRouterState.of(context).uri.toString(); final box = Hive.box(HiveBoxes.settings); final isSimpleMode = box.get('default')?.simpleMode ?? false; if (isSimpleMode) { if (location.startsWith('/imsakiyah')) return 1; if (location.startsWith('/quran')) return 2; if (location.startsWith('/dzikir')) return 3; if (location.startsWith('/tools') || location.startsWith('/doa') || location.startsWith('/hadits')) { return 4; } return 0; } else { if (location.startsWith('/imsakiyah')) return 1; if (location.startsWith('/checklist')) return 2; if (location.startsWith('/laporan')) return 3; if (location.startsWith('/tools')) return 4; return 0; } } void _onTap(BuildContext context, int index) { final box = Hive.box(HiveBoxes.settings); final isSimpleMode = box.get('default')?.simpleMode ?? false; if (isSimpleMode) { switch (index) { case 0: context.go('/'); break; case 1: context.go('/imsakiyah'); break; case 2: context.go('/quran'); break; case 3: context.go('/dzikir'); break; case 4: context.go('/tools'); break; } } else { switch (index) { case 0: context.go('/'); break; case 1: context.go('/imsakiyah'); break; case 2: context.go('/checklist'); break; case 3: context.go('/laporan'); break; case 4: context.go('/tools'); break; } } } bool _isMainShellRoute({ required bool isSimpleMode, required String path, }) { if (isSimpleMode) { return path == '/' || path == '/imsakiyah' || path == '/quran' || path == '/dzikir' || path == '/tools'; } return path == '/' || path == '/imsakiyah' || path == '/checklist' || path == '/laporan' || path == '/tools'; } Future _handleMainRouteBack( BuildContext context, { required String path, }) async { if (path != '/') { context.go('/'); return; } final now = DateTime.now(); final pressedRecently = _lastBackPressedAt != null && now.difference(_lastBackPressedAt!) <= const Duration(seconds: 2); if (pressedRecently) { await SystemNavigator.pop(); return; } _lastBackPressedAt = now; final messenger = ScaffoldMessenger.maybeOf(context); messenger ?..hideCurrentSnackBar() ..showSnackBar( const SnackBar( content: Text('Tekan sekali lagi untuk keluar'), duration: Duration(seconds: 2), ), ); } @override Widget build(BuildContext context) { return ValueListenableBuilder>( valueListenable: Hive.box(HiveBoxes.settings).listenable(), builder: (context, box, _) { final isSimpleMode = box.get('default')?.simpleMode ?? false; final path = GoRouterState.of(context).uri.path; final hideBottomNav = _shouldHideBottomNav( isSimpleMode: isSimpleMode, path: path, ); final modeScopedChild = KeyedSubtree( key: ValueKey( 'shell:$path:${isSimpleMode ? 'simple' : 'full'}', ), child: widget.child, ); final pageBody = hideBottomNav ? SafeArea( top: false, child: modeScopedChild, ) : modeScopedChild; final handleBackInShell = defaultTargetPlatform == TargetPlatform.android && _isMainShellRoute(isSimpleMode: isSimpleMode, path: path); return PopScope( canPop: !handleBackInShell, onPopInvokedWithResult: (didPop, _) async { if (didPop || !handleBackInShell) return; await _handleMainRouteBack(context, path: path); }, child: Scaffold( body: pageBody, bottomNavigationBar: hideBottomNav ? null : AppBottomNavBar( currentIndex: _currentIndex(context), onTap: (i) => _onTap(context, i), ), ), ); }, ); } }