v2.52.3 — F3-Rest: ☁️-Chip-Puls + Auto-Sync-Timer app-weit

## Chip-Puls (home_screen)
- ListenableBuilder hört auf Listenable.merge([_vm, _cloud, SyncService.laeuftNotifier]) — der ☁️-Musikserver-Chip pulsiert jetzt bei laufendem Sync (auch im Hintergrund/Auto-Sync), nicht nur beim Verbinden/Laden
- serverSyncLaeuft = SyncService.laeuftNotifier.value || CloudStatus.verbinde || serverLadt

## Auto-Sync-Timer app-weit (main.dart)
- _starteAutoSyncFallsNoetig() entfernt (F3a: kein Sync beim App-Start); stattdessen SyncService.starteAutoSyncTimer() — Timer tickt erst nach dem Intervall, Fälligkeit via istSyncFaellig
- shared_preferences-Import aus main.dart entfernt (Intervall-Logik lebt in SyncService/CloudScreen)

## Sync-Notification
- Sync-Kanal de.baka.melo.sync wird in main() angelegt (Android 8+: Channel nötig, sonst erscheint die Notification nicht)
- onDidReceiveNotificationResponse: Tipp auf 'sync_fertig'/'sync_fehler' → SyncService.syncBenachrichtigungGetippt++ → MeloHome öffnet den Cloud-Tab

## Version
- Versionsanzeige 2.51 → 2.52.3 (settings/home/erweitert), MeloLogger.init('2.35') → '2.52.3'
This commit is contained in:
Dustin
2026-08-05 11:03:03 +02:00
parent 73aed70edd
commit 187b26603b
5 changed files with 58 additions and 53 deletions
+31 -48
View File
@@ -2,7 +2,6 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:io' show Platform;
import 'package:audio_service/audio_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
@@ -13,7 +12,9 @@ import 'services/cloud_service.dart';
import 'services/melo_logger.dart';
import 'services/audio_handler.dart';
import 'services/musik_scanner.dart';
import 'services/sync_service.dart';
import 'utils/farb_theme.dart';
import 'utils/user_effekte.dart';
import 'screens/home_screen.dart';
import 'screens/login_screen.dart';
@@ -28,13 +29,20 @@ void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Logger startet sofort zeichnet ALLES auf
MeloLogger().init('2.35');
MeloLogger().init('2.52.3');
// ── Notifications initialisieren (Issue #9) ──
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
const initSettings = InitializationSettings(android: androidInit);
await notificationsPlugin.initialize(
settings: initSettings,
// Tipp auf die Sync-Abschluss-/Fehler-Notification → Cloud-Tab öffnen
onDidReceiveNotificationResponse: (response) {
if (response.payload == 'sync_fertig' ||
response.payload == 'sync_fehler') {
SyncService.syncBenachrichtigungGetippt.value++;
}
},
);
// Notification-Channel für Downloads (Fortschritt + Abschluss)
@@ -51,6 +59,20 @@ void main() async {
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(downloadChannel);
// Notification-Channel für den Cloud-Sync (Fortschritt + Abschluss)
const syncChannel = AndroidNotificationChannel(
'de.baka.melo.sync',
'Melo Sync',
description: 'Cloud-Sync-Fortschritt und Abschluss',
importance: Importance.low,
playSound: false,
enableVibration: false,
);
await notificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(syncChannel);
// ── Background Service initialisieren (Issue #3) ──
await FlutterBackgroundService().configure(
iosConfiguration: IosConfiguration(),
@@ -108,8 +130,13 @@ void main() async {
await Permission.notification.request();
}
// Auto-Sync beim Start (wenn eingeloggt und Auto-Sync aktiv)
_starteAutoSyncFallsNoetig();
// Per-User-Akzent (überschreibbar in den Einstellungen) + Begrüßungs-Sound
// beim App-Start (wenn Token vorhanden). Fehler sind unkritisch.
await UserEffekt.anwenden(AuthService().benutzer);
// App-weiter Auto-Sync-Timer (F3): Intervall aus `cloud_interval`
// (0 = Aus), erster Tick erst NACH dem Intervall — kein Sync beim Start.
unawaited(SyncService.starteAutoSyncTimer());
runApp(const MeloApp());
}
@@ -134,50 +161,6 @@ void _starteAutoScan() {
});
}
/// Führt Cloud-Auto-Sync beim App-Start aus, falls konfiguriert
Future<void> _starteAutoSyncFallsNoetig() async {
try {
final auth = AuthService();
if (!auth.istEingeloggt) return;
// Prüfen, ob Auto-Sync aktiviert ist
final SharedPreferences prefs =
await SharedPreferences.getInstance();
final autoSync = prefs.getBool('cloud_auto') ?? true;
if (!autoSync) return;
final cloud = CloudService();
final ok = await cloud.login(auth.benutzer);
if (!ok) return;
// Letzten Sync prüfen — nur syncen wenn nötig
final lastSync = prefs.getString('cloud_last_sync_ts');
final now = DateTime.now();
if (lastSync != null) {
final last = DateTime.tryParse(lastSync);
if (last != null) {
final interval = prefs.getInt('cloud_interval') ?? 6;
if (now.difference(last).inHours < interval) {
return; // Noch nicht fällig
}
}
}
// Sync ausführen
MeloLogger().aktion('auto_sync_start', {});
final st = await cloud.statusDaten();
if (st != null) {
final serverSongs = await cloud.listSongs();
MeloLogger().aktion('auto_sync_done',
{'songs': serverSongs.length});
}
await prefs.setString('cloud_last_sync_ts', now.toIso8601String());
} catch (e) {
MeloLogger().fehler('auto_sync_init', e);
}
}
/// Background Service Callback hält App im Vordergrund beim Download (Issue #3)
@pragma('vm:entry-point')
Future<bool> _onServiceStart(ServiceInstance service) async {