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:
parent
cf645071aa
commit
f801f91edf
@ -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;
|
||||
await audio.setUrl(url);
|
||||
await audio.play();
|
||||
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);
|
||||
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,
|
||||
|
||||
@ -49,6 +49,7 @@ class _SongsScreenState extends State<SongsScreen> {
|
||||
page: _page,
|
||||
pageSize: _pageSize,
|
||||
);
|
||||
AdminPlayer.instance.refresh(page.items);
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user