Einzelne Server-Titel offline nehmen und wieder entfernen

This commit is contained in:
Hermes (Server)
2026-08-27 12:24:56 +02:00
parent fcf53dcb6c
commit 8e3c986d13
5 changed files with 248 additions and 6 deletions
+61 -6
View File
@@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
import '../library/database.dart';
import '../library/song_media.dart';
import '../player/audio_handler.dart';
import '../services/download_service.dart';
import '../services/navidrome_service.dart';
import '../shared/cover.dart';
import '../shared/lauf_balken.dart';
@@ -69,6 +70,45 @@ class _ServerTitelScreenState extends State<ServerTitelScreen> {
}
}
/// Nach Laden oder Entfernen ist der Einmal-Schnappschuss [_geladen] veraltet
/// — hier wird er nachgezogen.
Future<void> _aktualisiereGeladen() async {
final geladen = await context.read<MeloDb>().downloadIds();
if (mounted) setState(() => _geladen = geladen);
}
Future<void> _offlineNehmen(SubsonicSong song) async {
final dienst = context.read<DownloadService>();
final messenger = ScaffoldMessenger.of(context);
if (dienst.laeuft) {
messenger.showSnackBar(
const SnackBar(content: Text('Es läuft schon ein Download')),
);
return;
}
final neu = await dienst.ladeEinzelnenTitel(song);
await _aktualisiereGeladen();
if (!mounted) return;
messenger.showSnackBar(SnackBar(
content: Text(neu
? 'Offline: ${song.titel}'
: (dienst.fehler ?? 'War schon heruntergeladen')),
));
}
Future<void> _offlineEntfernen(SubsonicSong song) async {
final dienst = context.read<DownloadService>();
final messenger = ScaffoldMessenger.of(context);
final weg = await dienst.entferne(song.id);
await _aktualisiereGeladen();
if (!mounted) return;
messenger.showSnackBar(SnackBar(
content: Text(weg
? 'Vom Gerät entfernt: ${song.titel}'
: (dienst.fehler ?? 'Ließ sich nicht entfernen')),
));
}
Future<void> _spiele(List<SubsonicSong> songs, int ab) async {
final handler = context.read<MeloAudioHandler>();
final messenger = ScaffoldMessenger.of(context);
@@ -130,6 +170,8 @@ class _ServerTitelScreenState extends State<ServerTitelScreen> {
nummer: i,
geladen: _geladen.contains(song.id),
onTap: () => _spiele(songs, i - 1),
onOffline: () => _offlineNehmen(song),
onEntfernen: () => _offlineEntfernen(song),
);
},
),
@@ -230,12 +272,16 @@ class _Zeile extends StatelessWidget {
required this.nummer,
required this.geladen,
required this.onTap,
required this.onOffline,
required this.onEntfernen,
});
final SubsonicSong song;
final int nummer;
final bool geladen;
final VoidCallback onTap;
final VoidCallback onOffline;
final VoidCallback onEntfernen;
static String _dauer(int sekunden) {
final m = (sekunden ~/ 60).toString();
@@ -286,12 +332,21 @@ class _Zeile extends StatelessWidget {
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (geladen)
const Padding(
padding: EdgeInsets.only(right: MeloSpace.sm),
child: Icon(Icons.download_done,
size: 16, color: MeloTheme.text3),
),
// Bisher gab es den Lade-Knopf nur je Album — einen einzelnen
// Titel mitzunehmen ging gar nicht.
geladen
? IconButton(
tooltip: 'Vom Gerät entfernen',
icon: const Icon(Icons.download_done,
size: 20, color: MeloTheme.red),
onPressed: onEntfernen,
)
: IconButton(
tooltip: 'Offline nehmen',
icon: const Icon(Icons.download_outlined,
size: 20, color: MeloTheme.text3),
onPressed: onOffline,
),
Text(_dauer(song.dauerSekunden),
style: const TextStyle(color: MeloTheme.text3)),
],