This repository has been archived on 2026-08-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
melo-app/lib/services/audio_handler.dart
T
Hermes (Server) 8b6a04ead8 Fix: Review-Findings korrigiert (Tag-Leiste, Profil, Singleton u.a.)
CRIT:
- Tag-Leiste: Toggle-Kopf 'Tags & Filter' eingebaut (war unerreichbar) + TagStats
- Profil: Cloud-Count vor Dialog aufloesen (kein 'Instance of Future' mehr)
HIGH:
- CloudEinstellungen: toten Sync-Timer entfernt (echter Timer im ViewModel)
- StatistikCard + RecentWidget jetzt eingebaut (gesamtMB/gesamtMin endlich genutzt)
- CloudService als Singleton (konsistenter Token-Zustand in allen Services)
MED/LOW:
- Playlist-Erkennung nur noch via list= Parameter
- Player: fehlende Quelle wird geloggt statt still
- song_tile: null-ID-Guard vor Tag-Dialog
- Scanner-Log mit Exception-Objekt
- FavoritenService: anzahlFavoriten() fuer StatistikCard
2026-07-31 15:42:54 +02:00

92 lines
2.5 KiB
Dart

import 'dart:async';
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
import '../models/song.dart';
import 'player_service.dart';
/// Hintergrund-Audio-Handler für Sperrbildschirm & Benachrichtigung
class MeloAudioHandler extends BaseAudioHandler {
final PlayerService _player = PlayerService();
MeloAudioHandler() {
// Zustand vom Player an audio_service weiterleiten
_player.stateStream.listen(_updateState);
_player.positionStream.listen((pos) {
if (_playing) {
playbackState.add(playbackState.value.copyWith(
updatePosition: pos,
));
}
});
_player.onSongWechsel.listen((song) {
if (song != null) {
mediaItem.add(_toMediaItem(song));
}
});
}
bool _playing = false;
void _updateState(PlayerState state) {
_playing = state.playing;
playbackState.add(PlaybackState(
controls: _playing
? [MediaControl.pause, MediaControl.skipToPrevious, MediaControl.skipToNext, MediaControl.stop]
: [MediaControl.play, MediaControl.skipToPrevious, MediaControl.skipToNext, MediaControl.stop],
systemActions: const {MediaAction.seek},
androidCompactActionIndices: const [0, 1, 2],
processingState: _playing ? AudioProcessingState.ready : AudioProcessingState.idle,
playing: _playing,
speed: 1.0,
));
}
MediaItem _toMediaItem(Song song) => MediaItem(
id: song.id?.toString() ?? '0',
album: song.album.isEmpty ? 'Melo' : song.album,
title: song.titel,
artist: song.kuenstler,
duration: Duration(seconds: song.dauerSekunden),
artUri: song.coverPfad != null ? Uri.file(song.coverPfad!) : null,
);
@override
Future<void> play() async {
if (_player.aktuellerSong != null) {
_playing = true;
await _player.playPause();
}
}
@override
Future<void> pause() async {
_playing = false;
await _player.playPause();
}
@override
Future<void> stop() async {
_playing = false;
await _player.playPause();
playbackState.add(playbackState.value.copyWith(
controls: [MediaControl.play],
playing: false,
processingState: AudioProcessingState.idle,
));
}
@override
Future<void> seek(Duration position) async {
_player.spiele(_player.aktuellerSong!, position: position.inSeconds);
}
@override
Future<void> skipToNext() => _player.naechstes();
@override
Future<void> skipToPrevious() => _player.vorheriges();
// Exposed for the ViewModel
PlayerService get player => _player;
}