fixes to shuffle and queue
This commit is contained in:
parent
351d47b3ff
commit
5bf85a5f44
3 changed files with 312 additions and 55 deletions
|
|
@ -210,28 +210,84 @@ class _QueueToggle extends StatelessWidget {
|
|||
}
|
||||
|
||||
/// The play queue with reorder-free remove controls. Fills whichever space the
|
||||
/// top region gives it.
|
||||
class _QueuePanel extends ConsumerWidget {
|
||||
/// top region gives it. Because the engine keeps `state.queue` in true play
|
||||
/// order (even when shuffled), rows read top-to-bottom as history → now
|
||||
/// playing → up next: already-played rows are dimmed and the list auto-scrolls
|
||||
/// to keep the current track at the top as playback advances.
|
||||
class _QueuePanel extends ConsumerStatefulWidget {
|
||||
const _QueuePanel();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<_QueuePanel> createState() => _QueuePanelState();
|
||||
}
|
||||
|
||||
class _QueuePanelState extends ConsumerState<_QueuePanel> {
|
||||
/// Fixed row height: a [TimbreSpacing.minTouchTarget] tall remove button plus
|
||||
/// the [TimbreSpacing.xs] vertical padding above and below it. Pinning the
|
||||
/// extent lets us scroll to a row by index without measuring.
|
||||
static const double _rowExtent =
|
||||
TimbreSpacing.minTouchTarget + TimbreSpacing.xs * 2;
|
||||
|
||||
final ScrollController _controller = ScrollController();
|
||||
bool _didInitialScroll = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// Bring the row at [index] to the top of the viewport (clamped), after the
|
||||
/// current frame so the list has laid out.
|
||||
void _scrollToIndex(int? index) {
|
||||
if (index == null || index < 0) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!_controller.hasClients) return;
|
||||
final target =
|
||||
(index * _rowExtent).clamp(0.0, _controller.position.maxScrollExtent);
|
||||
_controller.animateTo(
|
||||
target,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeOutCubic,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final state = ref.watch(playbackProvider);
|
||||
final accent = Theme.of(context).colorScheme.primary;
|
||||
|
||||
// Follow the playing track as it advances (or as shuffle reorders things).
|
||||
ref.listen<int?>(
|
||||
playbackProvider.select((s) => s.currentIndex),
|
||||
(_, next) => _scrollToIndex(next),
|
||||
);
|
||||
// Jump to the current track the first time the queue is populated.
|
||||
if (!_didInitialScroll && state.queue.isNotEmpty) {
|
||||
_didInitialScroll = true;
|
||||
_scrollToIndex(state.currentIndex);
|
||||
}
|
||||
|
||||
return HairlinePanel(
|
||||
title: 'Queue',
|
||||
trailing: '(${state.queue.length})',
|
||||
padding: const EdgeInsets.symmetric(vertical: TimbreSpacing.md),
|
||||
child: ListView.builder(
|
||||
controller: _controller,
|
||||
padding: EdgeInsets.zero,
|
||||
itemExtent: _rowExtent,
|
||||
itemCount: state.queue.length,
|
||||
itemBuilder: (context, i) {
|
||||
final song = state.queue[i];
|
||||
final isCurrent = i == state.currentIndex;
|
||||
final current = state.currentIndex;
|
||||
final isCurrent = i == current;
|
||||
final isPast = current != null && i < current;
|
||||
final titleColor = isCurrent
|
||||
? accent
|
||||
: (isPast ? TimbreColors.dimmed : TimbreColors.foreground);
|
||||
return InkWell(
|
||||
onTap: () => ref
|
||||
.read(playbackProvider.notifier)
|
||||
.playSongs(state.queue, startIndex: i),
|
||||
onTap: () => ref.read(playbackProvider.notifier).jumpTo(i),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: TimbreSpacing.lg,
|
||||
|
|
@ -250,7 +306,7 @@ class _QueuePanel extends ConsumerWidget {
|
|||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
color: isCurrent ? accent : TimbreColors.foreground,
|
||||
color: titleColor,
|
||||
fontWeight:
|
||||
isCurrent ? FontWeight.w700 : FontWeight.w400,
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue