Skip to content

Commit e1cb40e

Browse files
committed
feat: add download button to full-screen player top bar and bump version to 4.0.0-beta.1
- Add download icon button in top bar next to lyrics toggle for quick track downloading - Use Expanded layout to keep queue chip centered regardless of button count - Button respects askQualityBeforeDownload setting and hidden for local files - Bump version from 4.0.0-alpha.1 to 4.0.0-beta.1 in pubspec.yaml and app_info.dart
1 parent 54ae983 commit e1cb40e

File tree

3 files changed

+113
-32
lines changed

3 files changed

+113
-32
lines changed

lib/constants/app_info.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// App version and info constants
22
/// Update version here only - all other files will reference this
33
class AppInfo {
4-
static const String version = '4.0.0-alpha.1';
4+
static const String version = '4.0.0-beta.1';
55
static const String buildNumber = '100';
66
static const String fullVersion = '$version+$buildNumber';
77

lib/widgets/mini_player_bar.dart

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import 'package:flutter/rendering.dart';
77
import 'package:flutter_riverpod/flutter_riverpod.dart';
88
import 'package:spotiflac_android/l10n/l10n.dart';
99
import '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';
1012
import 'package:spotiflac_android/providers/playback_provider.dart';
13+
import 'package:spotiflac_android/providers/settings_provider.dart';
1114
import 'package:spotiflac_android/services/cover_cache_manager.dart';
15+
import 'package:spotiflac_android/widgets/download_service_picker.dart';
1216

1317
// ─── Mini Player Bar ─────────────────────────────────────────────────────────
1418
class 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 ───────────────────────────────────────────────────────
13011382
class _PlaybackControls extends ConsumerWidget {
13021383
final PlaybackState state;

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: spotiflac_android
22
description: Download Spotify tracks in FLAC from Tidal, Qobuz & Amazon Music
33
publish_to: "none"
4-
version: 4.0.0-alpha.1+100
4+
version: 4.0.0-beta.1+100
55

66
environment:
77
sdk: ^3.10.0

0 commit comments

Comments
 (0)