From 41309ff6ee02efb16b9e7e919239a8a7fdb27f35 Mon Sep 17 00:00:00 2001 From: virtus Date: Mon, 27 Apr 2026 21:36:14 +0700 Subject: [PATCH] feat: Enhance route persistence and restoration logic for improved navigation --- lib/app/app.dart | 24 ++++++--- .../splash/presentation/splash_screen.dart | 53 ++++++++++++++----- 2 files changed, 59 insertions(+), 18 deletions(-) diff --git a/lib/app/app.dart b/lib/app/app.dart index 6d6db29..2888185 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -24,15 +24,27 @@ class _ReaderAppState extends ConsumerState { final _scaffoldMessengerKey = GlobalKey(); ProviderSubscription? _sessionExpirySub; late final GoRouter _router; + String? _previousPath; void _persistRouteForRestore() { if (!mounted) return; - unawaited(() async { - final uri = _router.state.uri; - final fullPath = uri.hasQuery ? '${uri.path}?${uri.query}' : uri.path; - if (fullPath == RouteNames.splash) return; - await ref.read(localStoreProvider).saveLastRoutePath(fullPath); - }()); + final uri = _router.state.uri; + final fullPath = uri.hasQuery ? '${uri.path}?${uri.query}' : uri.path; + if (fullPath == RouteNames.splash) return; + + // When navigating into reader from a novel page, save "novelPath|readerPath" + // so the splash screen can reconstruct the full back stack on restore. + final String pathToSave; + if (fullPath.startsWith('/reader/') && + _previousPath != null && + _previousPath!.startsWith('/novel/')) { + pathToSave = '$_previousPath|$fullPath'; + } else { + pathToSave = fullPath; + } + _previousPath = fullPath; + + unawaited(ref.read(localStoreProvider).saveLastRoutePath(pathToSave)); } @override diff --git a/lib/features/splash/presentation/splash_screen.dart b/lib/features/splash/presentation/splash_screen.dart index c73b99b..904fc7d 100644 --- a/lib/features/splash/presentation/splash_screen.dart +++ b/lib/features/splash/presentation/splash_screen.dart @@ -19,17 +19,19 @@ class _SplashScreenState extends ConsumerState { bool _isRestorableRoute(String path) { if (path.isEmpty || path == RouteNames.splash) return false; - return path == RouteNames.home || - path == RouteNames.login || - path == RouteNames.search || - path.startsWith('${RouteNames.search}?') || - path == RouteNames.genres || - path == RouteNames.bookshelf || - path == RouteNames.profile || - path == RouteNames.settings || - path.startsWith('/novel/') || - path.startsWith('/reader/') || - path.startsWith('/comments/'); + // Composite "parentPath|deepPath" — validate the deep path portion + final checkPath = path.contains('|') ? path.substring(path.indexOf('|') + 1) : path; + return checkPath == RouteNames.home || + checkPath == RouteNames.login || + checkPath == RouteNames.search || + checkPath.startsWith('${RouteNames.search}?') || + checkPath == RouteNames.genres || + checkPath == RouteNames.bookshelf || + checkPath == RouteNames.profile || + checkPath == RouteNames.settings || + checkPath.startsWith('/novel/') || + checkPath.startsWith('/reader/') || + checkPath.startsWith('/comments/'); } @override @@ -40,7 +42,34 @@ class _SplashScreenState extends ConsumerState { final lastPath = await ref.read(localStoreProvider).loadLastRoutePath(); if (!mounted) return; if (lastPath != null && _isRestorableRoute(lastPath)) { - context.go(lastPath); + if (lastPath.contains('|')) { + // Composite "parentPath|deepPath" e.g. "/novel/123|/reader/abc" + // Restore full stack: Home → Novel Detail → Reader + final sep = lastPath.indexOf('|'); + final parentPath = lastPath.substring(0, sep); + final deepPath = lastPath.substring(sep + 1); + context.go(RouteNames.home); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + context.push(parentPath); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) context.push(deepPath); + }); + }); + } else { + // Single deep route (novel, comments) outside ShellRoute: push on Home + final isDeepRoute = lastPath.startsWith('/reader/') || + lastPath.startsWith('/novel/') || + lastPath.startsWith('/comments/'); + if (isDeepRoute) { + context.go(RouteNames.home); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) context.push(lastPath); + }); + } else { + context.go(lastPath); + } + } return; } context.go(RouteNames.home);