NK Admin: switching songs stops the previous one; player bar shows edited details

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
metatroncubeswdev 2026-10-30 11:46:22 -04:00
parent cf645071aa
commit f801f91edf
2 changed files with 32 additions and 4 deletions

View File

@ -13,19 +13,42 @@ class AdminPlayer {
final audio = AudioPlayer();
final current = ValueNotifier<AdminTrack?>(null);
/// Bumped on every switch, so only the latest click starts playing.
int _request = 0;
Future<void> toggle(AdminTrack track) async {
if (current.value?.id == track.id) {
audio.playing ? await audio.pause() : await audio.play();
// play() completes only when playback pauses, so it is not awaited.
audio.playing ? await audio.pause() : audio.play();
return;
}
final url = track.audioUrl;
if (url == null) return;
final request = ++_request;
current.value = track;
try {
// Stop first: loading a new file while one plays can be interrupted on the web,
// leaving the old song playing.
await audio.stop();
await audio.setUrl(url);
await audio.play();
if (request == _request) audio.play();
} catch (_) {
if (request != _request) return; // a newer click replaced this load
current.value = null;
rethrow;
}
}
/// Shows fresh details (after an edit) for the loaded song if it is in [tracks].
void refresh(Iterable<AdminTrack> tracks) {
final id = current.value?.id;
for (final t in tracks) {
if (t.id == id) current.value = t;
}
}
Future<void> close() async {
_request++;
await audio.stop();
current.value = null;
}
@ -51,7 +74,11 @@ class PlayButton extends StatelessWidget {
const [ProcessingState.loading, ProcessingState.buffering].contains(snap.data?.processingState);
return IconButton(
tooltip: track.audioKey == null ? 'No audio file' : (playing ? 'Pause' : 'Play'),
onPressed: track.audioKey == null ? null : () => player.toggle(track),
onPressed: track.audioKey == null
? null
: () => player.toggle(track).catchError((Object e) {
if (context.mounted) showMessage(context, 'Could not play "${track.title}": $e');
}),
icon: loading && playing
? const SizedBox.square(dimension: 20, child: CircularProgressIndicator(strokeWidth: 2))
: Icon(playing ? Icons.pause_circle_filled : Icons.play_circle_fill,

View File

@ -49,6 +49,7 @@ class _SongsScreenState extends State<SongsScreen> {
page: _page,
pageSize: _pageSize,
);
AdminPlayer.instance.refresh(page.items);
return page;
}