fix(library): preserve album view when returning from detail screens

This commit is contained in:
zarzet committed 2026-10-03 17:57:26 +07:00
1 parent 61708829fd
commit 6a4054d75e
3 files changed
+56 -5

No files matched your search

+10 -2
View File
@@ -860,7 +860,10 @@ class _MainShellState extends ConsumerState<MainShell>
navigatorKey: _libraryTabNavigatorKey,
observers: [_libraryPreviewStopObserver],
heroAnimationsEnabled: heroAnimationsEnabled,
child: _LibraryTabRoot(parentPageController: _pageController),
child: _LibraryTabRoot(
parentPageController: _pageController,
isTabActive: _currentIndex == 1,
),
),
if (showStore)
_TabNavigator(
@@ -1232,8 +1235,12 @@ class _PreviewStopNavigatorObserver extends NavigatorObserver {
class _LibraryTabRoot extends ConsumerWidget {
final PageController parentPageController;
final bool isTabActive;
const _LibraryTabRoot({required this.parentPageController});
const _LibraryTabRoot({
required this.parentPageController,
required this.isTabActive,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -1241,6 +1248,7 @@ class _LibraryTabRoot extends ConsumerWidget {
settingsProvider.select((s) => s.showExtensionStore),
);
return QueueTab(
isTabActive: isTabActive,
parentPageController: parentPageController,
parentPageIndex: 1,
nextPageIndex: showStore ? 2 : 3,
+5 -1
View File
@@ -211,6 +211,7 @@ DownloadHistoryItem? _historyItemForCompletionBridge(
class QueueTab extends ConsumerStatefulWidget {
final String? librarySection;
final bool isTabActive;
final PageController? parentPageController;
final int parentPageIndex;
final int? nextPageIndex;
@@ -218,6 +219,7 @@ class QueueTab extends ConsumerStatefulWidget {
const QueueTab({
super.key,
this.librarySection,
this.isTabActive = true,
this.parentPageController,
this.parentPageIndex = 1,
this.nextPageIndex,
@@ -364,7 +366,9 @@ class _QueueTabState extends ConsumerState<QueueTab> {
/// configured, jump the filter pager to it.
void _applyDefaultLibraryViewOnTabVisible() {
if (widget.librarySection != null) return;
final isVisible = TickerMode.valuesOf(context).enabled;
// Route transitions also disable TickerMode. Only a shell tab change
// should reset the user's current album/single view.
final isVisible = widget.isTabActive;
final becameVisible = isVisible && !_wasTabVisible;
_wasTabVisible = isVisible;
if (!becameVisible) return;
+41 -2
View File
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -92,7 +93,8 @@ print(json.dumps([dict(row) for row in db.execute(data['sql'], data['args'])]))
class _Settings extends SettingsNotifier {
@override
AppSettings build() => const AppSettings(localLibraryEnabled: true);
AppSettings build() =>
const AppSettings(localLibraryEnabled: true, defaultLibraryView: 'all');
@override
void setHistoryFilterMode(String mode) {
@@ -287,6 +289,8 @@ void main() {
tester.view.physicalSize = const Size(800, 1400);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final tabActive = ValueNotifier(true);
addTearDown(tabActive.dispose);
await tester.pumpWidget(
ProviderScope(
overrides: [
@@ -302,7 +306,15 @@ void main() {
theme: AppTheme.light(),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const Scaffold(body: QueueTab()),
home: ValueListenableBuilder<bool>(
valueListenable: tabActive,
builder: (_, active, _) => Scaffold(
body: TickerMode(
enabled: active,
child: QueueTab(isTabActive: active),
),
),
),
),
),
);
@@ -327,6 +339,25 @@ void main() {
);
expect(container.read(settingsProvider).historyFilterMode, 'albums');
// Pushing an album/detail route disables the underlying route's ticker.
// Popping it must retain Albums rather than reapply the All default.
final navigator = Navigator.of(tester.element(find.byType(QueueTab)));
unawaited(
navigator.push<void>(
MaterialPageRoute<void>(
builder: (_) => const Scaffold(body: Text('Album details')),
),
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 400));
expect(find.text('Album details'), findsOneWidget);
navigator.pop();
await tester.pump();
await tester.pump(const Duration(milliseconds: 400));
expect(container.read(settingsProvider).historyFilterMode, 'albums');
await _waitFor(tester, find.text('1/12'));
await tester.enterText(find.byType(TextField), 'one-track');
await tester.pump(const Duration(milliseconds: 400));
await _waitFor(tester, find.text('1 album'));
@@ -350,6 +381,14 @@ void main() {
await tester.pump(const Duration(milliseconds: 400));
await _waitFor(tester, find.text('complete'));
expect(find.text('1/12'), findsNothing);
expect(container.read(settingsProvider).historyFilterMode, 'albums');
// An actual shell-tab switch still applies the configured All default.
tabActive.value = false;
await tester.pump();
tabActive.value = true;
await tester.pump();
await tester.pump(const Duration(milliseconds: 400));
expect(container.read(settingsProvider).historyFilterMode, 'all');
expect(tester.takeException(), isNull);
await tester.pumpWidget(const SizedBox());
// Let any already-dispatched SQLite queries finish after provider disposal.