Infinite playing

💄 Optimized UX
This commit is contained in:
2025-12-20 13:29:04 +08:00
parent f5c8236363
commit b05566dd36
9 changed files with 229 additions and 31 deletions

View File

@@ -103,7 +103,11 @@ class AlbumDetailScreen extends HookConsumerWidget {
}
void _playAlbum(WidgetRef ref, List<Track> tracks, {int initialIndex = 0}) {
final loadingNotifier = ref.read(remoteTrackLoadingProvider.notifier);
final audioHandler = ref.read(audioHandlerProvider);
audioHandler.playTracks(tracks, initialIndex: initialIndex);
loadingNotifier.setLoading(true);
audioHandler.playTracks(tracks, initialIndex: initialIndex).then((_) {
loadingNotifier.setLoading(false);
});
}
}

View File

@@ -525,8 +525,14 @@ class LibraryScreen extends HookConsumerWidget {
onTrailingPressed: () =>
_showTrackOptions(context, ref, track),
onTap: () {
final loadingNotifier = ref.read(
remoteTrackLoadingProvider.notifier,
);
final audio = ref.read(audioHandlerProvider);
audio.playTrack(track);
loadingNotifier.setLoading(true);
audio.playTrack(track).then((_) {
loadingNotifier.setLoading(false);
});
},
padding: const EdgeInsets.symmetric(
horizontal: 16,

View File

@@ -108,19 +108,35 @@ class PlayerScreen extends HookConsumerWidget {
autofocus: true,
onKeyEvent: (node, event) {
if (event is KeyDownEvent) {
if (event.logicalKey == LogicalKeyboardKey.space) {
if (player.state.playing) {
player.pause();
} else {
player.play();
}
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.bracketLeft) {
player.previous();
return KeyEventResult.handled;
} else if (event.logicalKey == LogicalKeyboardKey.bracketRight) {
player.next();
return KeyEventResult.handled;
switch (event.logicalKey) {
case LogicalKeyboardKey.space:
if (player.state.playing) {
player.pause();
} else {
player.play();
}
return KeyEventResult.handled;
case LogicalKeyboardKey.bracketLeft:
player.previous();
return KeyEventResult.handled;
case LogicalKeyboardKey.bracketRight:
player.next();
return KeyEventResult.handled;
case LogicalKeyboardKey.escape:
Navigator.of(context).pop();
return KeyEventResult.handled;
case LogicalKeyboardKey.arrowUp:
player.setVolume(
(player.state.volume + 10).clamp(0, 100),
); // Increase volume
return KeyEventResult.handled;
case LogicalKeyboardKey.arrowDown:
player.setVolume(
(player.state.volume - 10).clamp(0, 100),
); // Decrease volume
return KeyEventResult.handled;
default:
return KeyEventResult.ignored;
}
}
return KeyEventResult.ignored;
@@ -1700,7 +1716,10 @@ class _PlayerControls extends HookWidget {
);
},
child: Icon(
playing ? Symbols.pause : Symbols.play_arrow,
playing
? Symbols.pause_rounded
: Symbols.play_arrow_rounded,
fill: 1,
key: ValueKey<bool>(playing),
size: 48,
),

View File

@@ -114,7 +114,11 @@ class PlaylistDetailScreen extends HookConsumerWidget {
List<Track> tracks, {
int initialIndex = 0,
}) {
final loadingNotifier = ref.read(remoteTrackLoadingProvider.notifier);
final audioHandler = ref.read(audioHandlerProvider);
audioHandler.playTracks(tracks, initialIndex: initialIndex);
loadingNotifier.setLoading(true);
audioHandler.playTracks(tracks, initialIndex: initialIndex).then((_) {
loadingNotifier.setLoading(false);
});
}
}

View File

@@ -379,6 +379,21 @@ class SettingsScreen extends ConsumerWidget {
),
),
),
SwitchListTile(
title: const Text('Continue Playing'),
subtitle: const Text(
'Continue playing music after the queue is empty',
),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
value: settings.continuePlays,
onChanged: (value) {
ref
.read(continuePlaysProvider.notifier)
.update(value);
},
),
const SizedBox(height: 8),
],
),