diff --git a/lib/screens/artist_screen.dart b/lib/screens/artist_screen.dart index 42283120..326c1f0b 100644 --- a/lib/screens/artist_screen.dart +++ b/lib/screens/artist_screen.dart @@ -1638,12 +1638,7 @@ class _ArtistScreenState extends ConsumerState ref .read(downloadQueueProvider.notifier) .addToQueue(track, service, qualityOverride: quality); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.snackbarAddedToQueue(track.name)), - duration: const Duration(seconds: 2), - ), - ); + showAddedToQueueSnackBar(context, track.name); } if (settings.askQualityBeforeDownload || settings.allowQualityVariants) { diff --git a/lib/screens/home_tab.dart b/lib/screens/home_tab.dart index 6ac5c304..b659fc7c 100644 --- a/lib/screens/home_tab.dart +++ b/lib/screens/home_tab.dart @@ -543,9 +543,18 @@ class _HomeTabState extends ConsumerState : isRateLimit ? l10n.errorRateLimitedMessage : l10n.errorUrlFetchFailed; - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text(displayMessage))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(displayMessage), + // Retrying an unrecognized URL is deterministic; skip the action. + action: errorMsg == 'url_not_recognized' + ? null + : SnackBarAction( + label: l10n.dialogRetry, + onPressed: _fetchMetadata, + ), + ), + ); ref.read(trackProvider.notifier).clear(); } else { _navigateToDetailIfNeeded(); @@ -649,11 +658,7 @@ class _HomeTabState extends ConsumerState ref .read(downloadQueueProvider.notifier) .addToQueue(track, service, qualityOverride: quality); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.snackbarAddedToQueue(track.name)), - ), - ); + showAddedToQueueSnackBar(context, track.name); }, ); } else { @@ -669,11 +674,7 @@ class _HomeTabState extends ConsumerState return; } ref.read(downloadQueueProvider.notifier).addToQueue(track, service); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.snackbarAddedToQueue(track.name)), - ), - ); + showAddedToQueueSnackBar(context, track.name); } } } @@ -1982,11 +1983,7 @@ class _HomeTabState extends ConsumerState ref .read(downloadQueueProvider.notifier) .addToQueue(track, service, qualityOverride: quality); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(context.l10n.snackbarAddedToQueue(track.name)), - ), - ); + showAddedToQueueSnackBar(context, track.name); }, ); } else { @@ -2002,9 +1999,7 @@ class _HomeTabState extends ConsumerState return; } ref.read(downloadQueueProvider.notifier).addToQueue(track, service); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(context.l10n.snackbarAddedToQueue(track.name))), - ); + showAddedToQueueSnackBar(context, track.name); } } diff --git a/lib/screens/main_shell.dart b/lib/screens/main_shell.dart index e388f0dc..51d3ce95 100644 --- a/lib/screens/main_shell.dart +++ b/lib/screens/main_shell.dart @@ -300,9 +300,18 @@ class _MainShellState extends ConsumerState : isRateLimit ? l10n.errorRateLimitedMessage : l10n.errorUrlFetchFailed; - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text(displayMessage))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(displayMessage), + // Retrying an unrecognized URL is deterministic; skip the action. + action: errorMsg == 'url_not_recognized' + ? null + : SnackBarAction( + label: l10n.dialogRetry, + onPressed: () => _handleSharedUrl(url), + ), + ), + ); } } diff --git a/lib/widgets/track_detail_actions.dart b/lib/widgets/track_detail_actions.dart index 3b2c1351..0fd225d5 100644 --- a/lib/widgets/track_detail_actions.dart +++ b/lib/widgets/track_detail_actions.dart @@ -8,6 +8,7 @@ import 'package:spotiflac_android/providers/library_collections_provider.dart'; import 'package:spotiflac_android/providers/local_library_provider.dart'; import 'package:spotiflac_android/providers/settings_provider.dart'; import 'package:spotiflac_android/widgets/download_service_picker.dart'; +import 'package:spotiflac_android/widgets/view_queue_snackbar_action.dart'; /// Shared single-track "add to queue" flow for detail screens: shows the /// quality/service picker when the user opted into it, otherwise resolves @@ -24,10 +25,7 @@ void downloadSingleTrack( final settings = ref.read(settingsProvider); void notifyQueued() { - if (!context.mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(context.l10n.snackbarAddedToQueue(track.name))), - ); + showAddedToQueueSnackBar(context, track.name); } if (settings.askQualityBeforeDownload || forceQualityPicker) { diff --git a/lib/widgets/view_queue_snackbar_action.dart b/lib/widgets/view_queue_snackbar_action.dart index 8bcadb5b..4618c4ed 100644 --- a/lib/widgets/view_queue_snackbar_action.dart +++ b/lib/widgets/view_queue_snackbar_action.dart @@ -10,3 +10,14 @@ SnackBarAction buildViewQueueSnackBarAction(BuildContext context) { }, ); } + +/// Shared "Added to queue" snackbar with a View action jumping to Library. +void showAddedToQueueSnackBar(BuildContext context, String trackName) { + if (!context.mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(context.l10n.snackbarAddedToQueue(trackName)), + action: buildViewQueueSnackBarAction(context), + ), + ); +}