@@ -7,8 +7,12 @@ import 'package:flutter/rendering.dart';
77import 'package:flutter_riverpod/flutter_riverpod.dart' ;
88import 'package:spotiflac_android/l10n/l10n.dart' ;
99import 'package:spotiflac_android/models/playback_item.dart' ;
10+ import 'package:spotiflac_android/models/track.dart' ;
11+ import 'package:spotiflac_android/providers/download_queue_provider.dart' ;
1012import 'package:spotiflac_android/providers/playback_provider.dart' ;
13+ import 'package:spotiflac_android/providers/settings_provider.dart' ;
1114import 'package:spotiflac_android/services/cover_cache_manager.dart' ;
15+ import 'package:spotiflac_android/widgets/download_service_picker.dart' ;
1216
1317// ─── Mini Player Bar ─────────────────────────────────────────────────────────
1418class MiniPlayerBar extends ConsumerWidget {
@@ -341,19 +345,24 @@ class _FullScreenPlayerState extends ConsumerState<_FullScreenPlayer> {
341345 ),
342346 child: Row (
343347 children: [
344- IconButton (
345- icon: const Icon (
346- Icons .keyboard_arrow_down_rounded,
347- size: 30 ,
348+ // ── Left side
349+ Expanded (
350+ child: Align (
351+ alignment: Alignment .centerLeft,
352+ child: IconButton (
353+ icon: const Icon (
354+ Icons .keyboard_arrow_down_rounded,
355+ size: 30 ,
356+ ),
357+ visualDensity: isCompactLayout
358+ ? VisualDensity .compact
359+ : VisualDensity .standard,
360+ onPressed: () => Navigator .of (context).pop (),
361+ tooltip: 'Close' ,
362+ ),
348363 ),
349- visualDensity: isCompactLayout
350- ? VisualDensity .compact
351- : VisualDensity .standard,
352- onPressed: () => Navigator .of (context).pop (),
353- tooltip: 'Close' ,
354364 ),
355- const Spacer (),
356- // Queue info (tappable to open queue sheet)
365+ // ── Center: Queue info
357366 if (state.queue.length > 1 )
358367 GestureDetector (
359368 onTap: () => _showQueueSheet (context, ref),
@@ -387,26 +396,37 @@ class _FullScreenPlayerState extends ConsumerState<_FullScreenPlayer> {
387396 ),
388397 ),
389398 ),
390- const Spacer (),
391- // Lyrics toggle button
392- IconButton (
393- visualDensity: isCompactLayout
394- ? VisualDensity .compact
395- : VisualDensity .standard,
396- icon: Icon (
397- Icons .lyrics_outlined,
398- color: _currentPage == 1
399- ? colorScheme.primary
400- : colorScheme.onSurfaceVariant,
399+ // ── Right side
400+ Expanded (
401+ child: Row (
402+ mainAxisAlignment: MainAxisAlignment .end,
403+ children: [
404+ if (! item.isLocal && item.track != null )
405+ _DownloadButton (
406+ item: item,
407+ compact: isCompactLayout,
408+ ),
409+ IconButton (
410+ visualDensity: isCompactLayout
411+ ? VisualDensity .compact
412+ : VisualDensity .standard,
413+ icon: Icon (
414+ Icons .lyrics_outlined,
415+ color: _currentPage == 1
416+ ? colorScheme.primary
417+ : colorScheme.onSurfaceVariant,
418+ ),
419+ onPressed: () {
420+ if (_currentPage == 0 ) {
421+ _switchToLyrics ();
422+ } else {
423+ _switchToCover ();
424+ }
425+ },
426+ tooltip: 'Lyrics' ,
427+ ),
428+ ],
401429 ),
402- onPressed: () {
403- if (_currentPage == 0 ) {
404- _switchToLyrics ();
405- } else {
406- _switchToCover ();
407- }
408- },
409- tooltip: 'Lyrics' ,
410430 ),
411431 ],
412432 ),
@@ -1297,6 +1317,67 @@ class _Chip extends StatelessWidget {
12971317 }
12981318}
12991319
1320+ // ─── Download Button ─────────────────────────────────────────────────────────
1321+ class _DownloadButton extends ConsumerWidget {
1322+ final PlaybackItem item;
1323+ final bool compact;
1324+
1325+ const _DownloadButton ({required this .item, this .compact = false });
1326+
1327+ @override
1328+ Widget build (BuildContext context, WidgetRef ref) {
1329+ final track = item.track;
1330+ if (track == null ) return const SizedBox .shrink ();
1331+
1332+ final colorScheme = Theme .of (context).colorScheme;
1333+ final iconSize = compact ? 18.0 : 22.0 ;
1334+
1335+ return IconButton (
1336+ visualDensity: compact ? VisualDensity .compact : VisualDensity .standard,
1337+ icon: Icon (
1338+ Icons .download_rounded,
1339+ color: colorScheme.onSurfaceVariant,
1340+ size: iconSize,
1341+ ),
1342+ onPressed: () => _onDownloadTap (context, ref, track),
1343+ tooltip: context.l10n.downloadTitle,
1344+ );
1345+ }
1346+
1347+ void _onDownloadTap (BuildContext context, WidgetRef ref, Track track) {
1348+ final settings = ref.read (settingsProvider);
1349+
1350+ if (settings.askQualityBeforeDownload) {
1351+ DownloadServicePicker .show (
1352+ context,
1353+ trackName: track.name,
1354+ artistName: track.artistName,
1355+ coverUrl: track.coverUrl,
1356+ onSelect: (quality, service) {
1357+ ref
1358+ .read (downloadQueueProvider.notifier)
1359+ .addToQueue (track, service, qualityOverride: quality);
1360+ if (! context.mounted) return ;
1361+ ScaffoldMessenger .of (context).showSnackBar (
1362+ SnackBar (
1363+ content: Text (context.l10n.snackbarAddedToQueue (track.name)),
1364+ ),
1365+ );
1366+ },
1367+ );
1368+ } else {
1369+ ref
1370+ .read (downloadQueueProvider.notifier)
1371+ .addToQueue (track, settings.defaultService);
1372+ ScaffoldMessenger .of (context).showSnackBar (
1373+ SnackBar (
1374+ content: Text (context.l10n.snackbarAddedToQueue (track.name)),
1375+ ),
1376+ );
1377+ }
1378+ }
1379+ }
1380+
13001381// ─── Playback Controls ───────────────────────────────────────────────────────
13011382class _PlaybackControls extends ConsumerWidget {
13021383 final PlaybackState state;
0 commit comments