feat: persist last active tab and preserve per-tab navigation state
Build and Release / Build Windows x64 (push) Has been cancelled
Build and Release / Build macOS (push) Has been cancelled

This commit is contained in:
2026-09-05 15:59:02 +03:00
parent af00cb8179
commit 28a63483da
19 changed files with 476 additions and 173 deletions
@@ -3,10 +3,10 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../core/utils/result.dart';
@@ -791,12 +791,10 @@ class _ArtistPostsScreenState extends ConsumerState<ArtistPostsScreen> {
settings.mediaQualityMode),
favoriteKeys: favoriteKeys,
viewedKeys: viewedKeys,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: displayedPosts,
),
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
postsList: displayedPosts,
),
onFavorite: (post) async {
if (favoriteKeys.contains(post.cacheKey)) {
@@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../core/utils/result.dart';
@@ -1574,12 +1575,10 @@ class _FavoriteArtistMediaStrip extends ConsumerWidget {
final isVideo = MediaUrlSelector.isVideo(post);
return InkWell(
borderRadius: BorderRadius.circular(14),
onTap: () => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: posts,
),
onTap: () => AppNavigator.openPost(
context,
post: post,
postsList: posts,
),
child: Container(
decoration: BoxDecoration(
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../shared/widgets/adaptive_scaffold.dart';
@@ -167,12 +168,10 @@ class CollectionDetailsScreen extends ConsumerWidget {
mediaQualityMode:
MediaQualityMode.fromName(settings.mediaQualityMode),
favoriteKeys: favoriteKeys,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: items,
),
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
postsList: items,
),
onFavorite: (post) async {
if (favoriteKeys.contains(post.cacheKey)) {
@@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../shared/widgets/adaptive_scaffold.dart';
@@ -970,12 +971,10 @@ class _FavoritesScreenState extends ConsumerState<FavoritesScreen> {
mediaQualityMode: MediaQualityMode.fromName(settings.mediaQualityMode),
favoriteKeys: posts.map((post) => post.cacheKey).toSet(),
downloadedKeys: downloadedKeys,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: posts,
),
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
postsList: posts,
),
onFavorite: (post) =>
ref.read(favoritesControllerProvider.notifier).remove(post),
@@ -8,6 +8,7 @@ import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../core/utils/result.dart';
@@ -331,12 +332,10 @@ class _FeedScreenState extends ConsumerState<FeedScreen>
selectionMode: _selectionMode,
selectedKeys: _selectedKeys,
gridMode: settings.gridMode,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: state.posts,
),
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
postsList: state.posts,
),
onPreview: (post) => _showPreview(context, post),
onToggleSelected: (post) => _toggleSelected(post),
@@ -392,7 +391,7 @@ class _FeedScreenState extends ConsumerState<FeedScreen>
void _openRandom(List<Post> posts) {
if (posts.isEmpty) return;
final post = posts[Random().nextInt(posts.length)];
context.push('/post/${post.providerId}/${post.id}', extra: post);
AppNavigator.openPost(context, post: post, postsList: posts);
}
Future<void> _applySearchQuery(String query) async {
@@ -8,6 +8,7 @@ import 'package:share_plus/share_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/app_strings.dart';
import '../../../app/motion.dart';
import '../../../app/responsive.dart';
@@ -872,7 +873,7 @@ class PostDetailsScreen extends ConsumerWidget {
}
void _openSimilar(BuildContext context, WidgetRef ref, Post post) {
context.push('/post/${post.providerId}/${post.id}/similar', extra: post);
AppNavigator.openSimilarPosts(context, post: post);
}
Future<void> _openSourcePage(WidgetRef ref, Post post) async {
@@ -888,7 +889,16 @@ class PostDetailsScreen extends ConsumerWidget {
}
void _replacePost(BuildContext context, Post post) {
context.replace('/post/${post.providerId}/${post.id}', extra: post);
Navigator.of(context).pushReplacement(
MaterialPageRoute<void>(
builder: (ctx) => PostDetailsScreen(
providerId: post.providerId,
postId: post.id,
initialPost: post,
postsList: postsList,
),
),
);
}
void _close(BuildContext context) {
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../core/utils/result.dart';
@@ -98,9 +98,9 @@ class SimilarPostsScreen extends ConsumerWidget {
MediaQualityMode.fromName(settings.mediaQualityMode),
favoriteKeys: favorites,
viewedKeys: viewed,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: post,
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
),
onFavorite: (post) =>
_toggleFavorite(ref, post, favorites),
@@ -1,9 +1,9 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../backend/backend.dart';
import '../../../core/utils/result.dart';
import '../../../shared/widgets/adaptive_scaffold.dart';
@@ -62,9 +62,9 @@ class HiddenPostsScreen extends ConsumerWidget {
item: item,
onOpen: item.post == null
? null
: () => context.push(
'/post/${item.post!.providerId}/${item.post!.id}',
extra: item.post,
: () => AppNavigator.openPost(
context,
post: item.post!,
),
onRestore: () async {
await ref
@@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../app/app.dart';
import '../../../app/app_navigator.dart';
import '../../../app/responsive.dart';
import '../../../backend/backend.dart';
import '../../../shared/widgets/adaptive_scaffold.dart';
@@ -142,12 +143,10 @@ class _ViewedScreenState extends ConsumerState<ViewedScreen> {
mediaQualityMode:
MediaQualityMode.fromName(settings.mediaQualityMode),
favoriteKeys: favoriteKeys,
onOpen: (post) => context.push(
'/post/${post.providerId}/${post.id}',
extra: PostNavigationContext(
currentPost: post,
posts: allPosts,
),
onOpen: (post) => AppNavigator.openPost(
context,
post: post,
postsList: allPosts,
),
onFavorite: (post) => _toggleFavorite(
ref,
@@ -260,12 +259,10 @@ class _ViewedScreenState extends ConsumerState<ViewedScreen> {
isFavorite: favoriteKeys.contains(item.post.cacheKey),
isRu: isRu,
onOpen: () {
context.push(
'/post/${item.post.providerId}/${item.post.id}',
extra: PostNavigationContext(
currentPost: item.post,
posts: allPosts,
),
AppNavigator.openPost(
context,
post: item.post,
postsList: allPosts,
);
},
onFavorite: () => _toggleFavorite(