v2.40 — Issue #9: Progress-Notification für Download/Upload (flutter_local_notifications)

- flutter_local_notifications ^22.2.0 hinzugefügt
- Notification-Channel 'de.baka.melo.downloads' in main() initialisiert
- DownloadService._showProgress(): Fortschritts-Notification mit ProgressBar
- DownloadService._completeNotification(): Abschluss-Notification (Erfolg/Fehler/Abbruch)
- Integration in downloadBatch(): Fortschritt pro Song, Abschluss nach Batch
- CloudScreen._upload(): Upload-Fortschritt + Abschluss-Notification
This commit is contained in:
Dustin
2026-08-02 16:04:09 +02:00
parent f23dc685cb
commit b8c206e58f
7 changed files with 228 additions and 1 deletions
+70
View File
@@ -4,14 +4,17 @@ import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import '../models/song.dart';
import '../database/db_helper.dart';
import '../utils/audio_validator.dart';
import 'melo_logger.dart';
import '../config/app_config.dart';
import '../main.dart'; // für notificationsPlugin
/// Download-Service: Lädt YouTube-Audio über den yt-proxy herunter.
/// Nutzt ChangeNotifier für UI-Updates via ListenableBuilder.
/// Issue #9: Fortschritt per System-Notification (ProgressBar).
class DownloadService extends ChangeNotifier {
static final http.Client _client = http.Client();
@@ -23,6 +26,10 @@ class DownloadService extends ChangeNotifier {
static String get _apiKey => AppConfig.ytProxyApiKey;
static Map<String, String> get _authHeader => {'X-API-Key': _apiKey};
static const String _channelId = 'de.baka.melo.downloads';
static const int _notifyProgressId = 100;
static const int _notifyCompleteId = 101;
final DbHelper _db = DbHelper();
bool _ladt = false;
@@ -91,12 +98,14 @@ class DownloadService extends ChangeNotifier {
int erfolgreich = 0;
_aktuellerTitel = '0/${urls.length} Starte...';
notifyListeners();
_showProgress(0, urls.length);
for (int i = 0; i < urls.length; i++) {
if (sollAbbrechen) break;
_aktuellerTitel = '${i + 1}/${urls.length} ${urls[i]._titelKurz()}';
notifyListeners();
_showProgress(i, urls.length, titel: urls[i]._titelKurz());
MeloLogger().zustand('download_einzeln_start', {
'index': i,
@@ -137,6 +146,7 @@ class DownloadService extends ChangeNotifier {
_aktuellerTitel = '$erfolgreich/${urls.length} Songs geladen';
}
notifyListeners();
_completeNotification(erfolgreich, urls.length, abgebrochen: sollAbbrechen);
MeloLogger().zustand('download_batch_ende', {
'erfolgreich': erfolgreich,
'gesamt': urls.length,
@@ -458,6 +468,66 @@ class DownloadService extends ChangeNotifier {
return _downloadEinzeln(song.ytUrl!);
}
// ─── #9: Notification-Progress ─────────────────
/// Zeigt oder aktualisiert eine Fortschritts-Notification.
/// [current] = aktueller Index (1-basiert), [total] = Gesamtanzahl.
void _showProgress(int current, int total, {String? titel}) {
if (!Platform.isAndroid) return;
notificationsPlugin.show(
id: _notifyProgressId,
title: 'Melo lädt herunter',
body: titel ?? '$current / $total Songs',
notificationDetails: NotificationDetails(
android: AndroidNotificationDetails(
_channelId,
'Melo Downloads',
channelDescription: 'Download-Fortschritt',
importance: Importance.low,
priority: Priority.low,
onlyAlertOnce: true,
showProgress: true,
maxProgress: total,
progress: current,
ongoing: true,
autoCancel: false,
),
),
);
}
/// Zeigt Abschluss-Notification (Erfolg oder Fehler).
void _completeNotification(int erfolgreich, int gesamt, {bool abgebrochen = false}) {
if (!Platform.isAndroid) return;
// Fortschritts-Notification abbrechen
notificationsPlugin.cancel(id: _notifyProgressId);
final titel = abgebrochen
? 'Download abgebrochen'
: (erfolgreich > 0 ? 'Download fertig' : 'Download fehlgeschlagen');
final body = abgebrochen
? '$erfolgreich / $gesamt Songs geladen'
: (erfolgreich > 0
? '$erfolgreich / $gesamt Songs geladen ✅'
: 'Kein Song konnte geladen werden ❌');
notificationsPlugin.show(
id: _notifyCompleteId,
title: titel,
body: body,
notificationDetails: NotificationDetails(
android: AndroidNotificationDetails(
_channelId,
'Melo Downloads',
channelDescription: 'Download-Abschluss',
importance: Importance.defaultImportance,
priority: Priority.defaultPriority,
autoCancel: true,
),
),
);
}
@override
void dispose() {
abbrechen();