3 Commits

Author SHA1 Message Date
virtus d505806f6e chore: Bump version to 1.0.3+6 in pubspec.yaml
Build Android APK / build-apk (push) Successful in 17m27s
Build Android AAB / build-aab (push) Successful in 18m23s
2026-04-27 21:36:59 +07:00
virtus 41309ff6ee feat: Enhance route persistence and restoration logic for improved navigation 2026-04-27 21:36:14 +07:00
virtus fd370f7833 chore: Bump version to 1.0.3+5 in pubspec.yaml
Build Android APK / build-apk (push) Successful in 12m9s
Build Android AAB / build-aab (push) Successful in 14m14s
2026-04-27 01:18:14 +07:00
3 changed files with 60 additions and 19 deletions
+15 -3
View File
@@ -24,15 +24,27 @@ class _ReaderAppState extends ConsumerState<ReaderApp> {
final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>(); final _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
ProviderSubscription<int>? _sessionExpirySub; ProviderSubscription<int>? _sessionExpirySub;
late final GoRouter _router; late final GoRouter _router;
String? _previousPath;
void _persistRouteForRestore() { void _persistRouteForRestore() {
if (!mounted) return; if (!mounted) return;
unawaited(() async {
final uri = _router.state.uri; final uri = _router.state.uri;
final fullPath = uri.hasQuery ? '${uri.path}?${uri.query}' : uri.path; final fullPath = uri.hasQuery ? '${uri.path}?${uri.query}' : uri.path;
if (fullPath == RouteNames.splash) return; if (fullPath == RouteNames.splash) return;
await ref.read(localStoreProvider).saveLastRoutePath(fullPath);
}()); // 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 @override
@@ -19,17 +19,19 @@ class _SplashScreenState extends ConsumerState<SplashScreen> {
bool _isRestorableRoute(String path) { bool _isRestorableRoute(String path) {
if (path.isEmpty || path == RouteNames.splash) return false; if (path.isEmpty || path == RouteNames.splash) return false;
return path == RouteNames.home || // Composite "parentPath|deepPath" — validate the deep path portion
path == RouteNames.login || final checkPath = path.contains('|') ? path.substring(path.indexOf('|') + 1) : path;
path == RouteNames.search || return checkPath == RouteNames.home ||
path.startsWith('${RouteNames.search}?') || checkPath == RouteNames.login ||
path == RouteNames.genres || checkPath == RouteNames.search ||
path == RouteNames.bookshelf || checkPath.startsWith('${RouteNames.search}?') ||
path == RouteNames.profile || checkPath == RouteNames.genres ||
path == RouteNames.settings || checkPath == RouteNames.bookshelf ||
path.startsWith('/novel/') || checkPath == RouteNames.profile ||
path.startsWith('/reader/') || checkPath == RouteNames.settings ||
path.startsWith('/comments/'); checkPath.startsWith('/novel/') ||
checkPath.startsWith('/reader/') ||
checkPath.startsWith('/comments/');
} }
@override @override
@@ -40,7 +42,34 @@ class _SplashScreenState extends ConsumerState<SplashScreen> {
final lastPath = await ref.read(localStoreProvider).loadLastRoutePath(); final lastPath = await ref.read(localStoreProvider).loadLastRoutePath();
if (!mounted) return; if (!mounted) return;
if (lastPath != null && _isRestorableRoute(lastPath)) { if (lastPath != null && _isRestorableRoute(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); context.go(lastPath);
}
}
return; return;
} }
context.go(RouteNames.home); context.go(RouteNames.home);
+1 -1
View File
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.3+4 version: 1.0.3+6
environment: environment:
sdk: ^3.11.3 sdk: ^3.11.3