mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-20 18:07:44 +02:00
fix(navigation): open download queue from snackbar actions
This commit is contained in:
@@ -30,6 +30,7 @@ import 'package:spotiflac_android/utils/clickable_metadata.dart';
|
|||||||
import 'package:spotiflac_android/widgets/cached_cover_image.dart';
|
import 'package:spotiflac_android/widgets/cached_cover_image.dart';
|
||||||
import 'package:spotiflac_android/widgets/motion_header_banner.dart';
|
import 'package:spotiflac_android/widgets/motion_header_banner.dart';
|
||||||
import 'package:spotiflac_android/widgets/cross_extension_share_sheet.dart';
|
import 'package:spotiflac_android/widgets/cross_extension_share_sheet.dart';
|
||||||
|
import 'package:spotiflac_android/widgets/view_queue_snackbar_action.dart';
|
||||||
|
|
||||||
class _ArtistCache {
|
class _ArtistCache {
|
||||||
static final _cache = TtlCache<_CacheEntry>(const Duration(minutes: 10));
|
static final _cache = TtlCache<_CacheEntry>(const Duration(minutes: 10));
|
||||||
@@ -1055,10 +1056,7 @@ class _ArtistScreenState extends ConsumerState<ArtistScreen>
|
|||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(message),
|
content: Text(message),
|
||||||
action: SnackBarAction(
|
action: buildViewQueueSnackBarAction(context),
|
||||||
label: context.l10n.snackbarViewQueue,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import 'package:spotiflac_android/widgets/error_card.dart';
|
|||||||
import 'package:spotiflac_android/widgets/in_library_badge.dart';
|
import 'package:spotiflac_android/widgets/in_library_badge.dart';
|
||||||
import 'package:spotiflac_android/widgets/preview_button.dart';
|
import 'package:spotiflac_android/widgets/preview_button.dart';
|
||||||
import 'package:spotiflac_android/widgets/settings_group.dart';
|
import 'package:spotiflac_android/widgets/settings_group.dart';
|
||||||
|
import 'package:spotiflac_android/widgets/view_queue_snackbar_action.dart';
|
||||||
|
|
||||||
part 'home_tab_helpers.dart';
|
part 'home_tab_helpers.dart';
|
||||||
part 'home_tab_widgets.dart';
|
part 'home_tab_widgets.dart';
|
||||||
@@ -1077,10 +1078,7 @@ class _HomeTabState extends ConsumerState<HomeTab>
|
|||||||
ScaffoldMessenger.of(this.context).showSnackBar(
|
ScaffoldMessenger.of(this.context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(queueSnackbarMessage),
|
content: Text(queueSnackbarMessage),
|
||||||
action: SnackBarAction(
|
action: buildViewQueueSnackBarAction(this.context),
|
||||||
label: l10n.snackbarViewQueue,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1109,10 +1107,7 @@ class _HomeTabState extends ConsumerState<HomeTab>
|
|||||||
ScaffoldMessenger.of(this.context).showSnackBar(
|
ScaffoldMessenger.of(this.context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(queueSnackbarMessage),
|
content: Text(queueSnackbarMessage),
|
||||||
action: SnackBarAction(
|
action: buildViewQueueSnackBarAction(this.context),
|
||||||
label: l10n.snackbarViewQueue,
|
|
||||||
onPressed: () {},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,10 @@ class _MainShellState extends ConsumerState<MainShell>
|
|||||||
duration: const Duration(milliseconds: 180),
|
duration: const Duration(milliseconds: 180),
|
||||||
value: 1,
|
value: 1,
|
||||||
);
|
);
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: this,
|
||||||
|
handler: _onShellTabRequested,
|
||||||
|
);
|
||||||
ShellNavigationService.syncState(
|
ShellNavigationService.syncState(
|
||||||
currentTabIndex: _currentIndex,
|
currentTabIndex: _currentIndex,
|
||||||
showRepoTab: false,
|
showRepoTab: false,
|
||||||
@@ -433,6 +437,7 @@ class _MainShellState extends ConsumerState<MainShell>
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
ShellNavigationService.unregisterTabSelectionHandler(this);
|
||||||
_shareSubscription?.cancel();
|
_shareSubscription?.cancel();
|
||||||
_pageController.dispose();
|
_pageController.dispose();
|
||||||
_tabJumpTransitionController.dispose();
|
_tabJumpTransitionController.dispose();
|
||||||
@@ -452,6 +457,19 @@ class _MainShellState extends ConsumerState<MainShell>
|
|||||||
ref.read(trackProvider.notifier).clear();
|
ref.read(trackProvider.notifier).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onShellTabRequested(ShellTab tab) {
|
||||||
|
final showStore = ref.read(
|
||||||
|
settingsProvider.select((s) => s.showExtensionStore),
|
||||||
|
);
|
||||||
|
final index = switch (tab) {
|
||||||
|
ShellTab.home => 0,
|
||||||
|
ShellTab.library => 1,
|
||||||
|
ShellTab.repository => showStore ? 2 : null,
|
||||||
|
ShellTab.settings => showStore ? 3 : 2,
|
||||||
|
};
|
||||||
|
if (index != null) _onNavTap(index);
|
||||||
|
}
|
||||||
|
|
||||||
void _onNavTap(int index) {
|
void _onNavTap(int index) {
|
||||||
if (index == 0 && _currentIndex == 0) {
|
if (index == 0 && _currentIndex == 0) {
|
||||||
_resetHomeToMain();
|
_resetHomeToMain();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
enum ShellTab { home, library, repository, settings }
|
||||||
|
|
||||||
class ShellNavigationService {
|
class ShellNavigationService {
|
||||||
static final GlobalKey<NavigatorState> homeTabNavigatorKey =
|
static final GlobalKey<NavigatorState> homeTabNavigatorKey =
|
||||||
GlobalKey<NavigatorState>();
|
GlobalKey<NavigatorState>();
|
||||||
@@ -10,6 +12,29 @@ class ShellNavigationService {
|
|||||||
|
|
||||||
static int _currentTabIndex = 0;
|
static int _currentTabIndex = 0;
|
||||||
static bool _showRepoTab = false;
|
static bool _showRepoTab = false;
|
||||||
|
static Object? _tabSelectionOwner;
|
||||||
|
static ValueChanged<ShellTab>? _tabSelectionHandler;
|
||||||
|
|
||||||
|
static void registerTabSelectionHandler({
|
||||||
|
required Object owner,
|
||||||
|
required ValueChanged<ShellTab> handler,
|
||||||
|
}) {
|
||||||
|
_tabSelectionOwner = owner;
|
||||||
|
_tabSelectionHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unregisterTabSelectionHandler(Object owner) {
|
||||||
|
if (!identical(_tabSelectionOwner, owner)) return;
|
||||||
|
_tabSelectionOwner = null;
|
||||||
|
_tabSelectionHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool requestTab(ShellTab tab) {
|
||||||
|
final handler = _tabSelectionHandler;
|
||||||
|
if (handler == null) return false;
|
||||||
|
handler(tab);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void syncState({
|
static void syncState({
|
||||||
required int currentTabIndex,
|
required int currentTabIndex,
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||||
|
import 'package:spotiflac_android/services/shell_navigation_service.dart';
|
||||||
|
|
||||||
|
SnackBarAction buildViewQueueSnackBarAction(BuildContext context) {
|
||||||
|
return SnackBarAction(
|
||||||
|
label: context.l10n.snackbarViewQueue,
|
||||||
|
onPressed: () {
|
||||||
|
ShellNavigationService.requestTab(ShellTab.library);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:spotiflac_android/l10n/app_localizations.dart';
|
||||||
|
import 'package:spotiflac_android/services/shell_navigation_service.dart';
|
||||||
|
import 'package:spotiflac_android/widgets/view_queue_snackbar_action.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('ShellNavigationService tab requests', () {
|
||||||
|
test('forwards a named tab request to the registered shell', () {
|
||||||
|
final owner = Object();
|
||||||
|
ShellTab? requestedTab;
|
||||||
|
addTearDown(
|
||||||
|
() => ShellNavigationService.unregisterTabSelectionHandler(owner),
|
||||||
|
);
|
||||||
|
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: owner,
|
||||||
|
handler: (tab) => requestedTab = tab,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(ShellNavigationService.requestTab(ShellTab.library), isTrue);
|
||||||
|
expect(requestedTab, ShellTab.library);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not remove a newer shell handler', () {
|
||||||
|
final oldOwner = Object();
|
||||||
|
final currentOwner = Object();
|
||||||
|
ShellTab? requestedTab;
|
||||||
|
addTearDown(
|
||||||
|
() =>
|
||||||
|
ShellNavigationService.unregisterTabSelectionHandler(currentOwner),
|
||||||
|
);
|
||||||
|
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: oldOwner,
|
||||||
|
handler: (_) {},
|
||||||
|
);
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: currentOwner,
|
||||||
|
handler: (tab) => requestedTab = tab,
|
||||||
|
);
|
||||||
|
|
||||||
|
ShellNavigationService.unregisterTabSelectionHandler(oldOwner);
|
||||||
|
|
||||||
|
expect(ShellNavigationService.requestTab(ShellTab.settings), isTrue);
|
||||||
|
expect(requestedTab, ShellTab.settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('reports when no shell can handle the request', () {
|
||||||
|
final owner = Object();
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: owner,
|
||||||
|
handler: (_) {},
|
||||||
|
);
|
||||||
|
ShellNavigationService.unregisterTabSelectionHandler(owner);
|
||||||
|
|
||||||
|
expect(ShellNavigationService.requestTab(ShellTab.library), isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('View Queue snackbar action requests the Library tab', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
final owner = Object();
|
||||||
|
ShellTab? requestedTab;
|
||||||
|
addTearDown(
|
||||||
|
() => ShellNavigationService.unregisterTabSelectionHandler(owner),
|
||||||
|
);
|
||||||
|
ShellNavigationService.registerTabSelectionHandler(
|
||||||
|
owner: owner,
|
||||||
|
handler: (tab) => requestedTab = tab,
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
home: Scaffold(
|
||||||
|
body: Builder(
|
||||||
|
builder: (context) => buildViewQueueSnackBarAction(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.text('View Queue'));
|
||||||
|
|
||||||
|
expect(requestedTab, ShellTab.library);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user