From 79fb381e678b49ac7980fc038bcb88832ceea4dc Mon Sep 17 00:00:00 2001 From: Boof2015 <75185879+Boof2015@users.noreply.github.com> Date: Tue, 28 Jul 2026 17:17:43 -0400 Subject: [PATCH] queue sheet update --- src/components/queue/QueueTray.tsx | 98 ++++++++++++++----- .../queue/queuePerformance.test.mts | 7 ++ src/components/queue/queuePerformance.ts | 3 + 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/src/components/queue/QueueTray.tsx b/src/components/queue/QueueTray.tsx index 0332c9d..aec384c 100644 --- a/src/components/queue/QueueTray.tsx +++ b/src/components/queue/QueueTray.tsx @@ -7,6 +7,7 @@ import { useState } from 'react'; import { + InteractionManager, Pressable, StyleSheet, View, @@ -77,6 +78,7 @@ import { type QueueIndexByKey, } from './queueActions'; import { + QUEUE_INITIAL_RENDER_DISTANCE, QUEUE_ROW_HEIGHT, queuePreviewRowCount, queueRenderDistance, @@ -204,9 +206,16 @@ export const QueueTray = memo(function QueueTray({ onClose, embedded = false }: // the tray's first frame and unmounts once the real list has painted (onLoad // fires a frame after first layout completes, so rows are already underneath). const [listPainted, setListPainted] = useState(false); - const onListLoad = useCallback(() => setListPainted(true), []); + const listPaintedRef = useRef(false); + const onListLoad = useCallback(() => { + listPaintedRef.current = true; + setListPainted(true); + }, []); + const [renderCoverageReady, setRenderCoverageReady] = useState(embedded); const previewCount = queuePreviewRowCount(windowHeight); - const renderDistance = queueRenderDistance(windowHeight); + const renderDistance = renderCoverageReady + ? queueRenderDistance(windowHeight) + : QUEUE_INITIAL_RENDER_DISTANCE; // Bottom padding clears the gesture-nav inset so the last row is fully // scrollable into view at the 100% snap. const listContentStyle = useMemo( @@ -244,27 +253,43 @@ export const QueueTray = memo(function QueueTray({ onClose, embedded = false }: const virtualLoadQueued = useRef(false); const virtualRetryTimer = useRef | null>(null); const virtualPageLoaderRef = useRef<(reset: boolean) => Promise>(async () => {}); + const deferredMountTask = useRef< + ReturnType | null + >(null); + + const resetVirtualTracks = useCallback(() => { + virtualLoadGeneration.current += 1; + virtualLoadQueued.current = false; + if (virtualRetryTimer.current) { + clearTimeout(virtualRetryTimer.current); + virtualRetryTimer.current = null; + } + + const state = getVirtualQueueState(); + const seed = state + ? seedVirtualQueueTracks( + rollingUpcomingTracksRef.current, + state.activePosition, + state.totalCount, + ) + : []; + const previous = virtualTracksRef.current; + const unchanged = + seed.length === previous.length && + seed.every((track, index) => track === previous[index]); + virtualTracksRef.current = unchanged ? previous : seed; + if (!unchanged) setVirtualTracks(seed); + return state; + }, []); const loadVirtualPage = useCallback((reset: boolean): Promise => { if (reset) { - virtualLoadGeneration.current += 1; - virtualLoadQueued.current = false; - if (virtualRetryTimer.current) { - clearTimeout(virtualRetryTimer.current); - virtualRetryTimer.current = null; + if (!embedded && listPaintedRef.current && deferredMountTask.current) { + deferredMountTask.current.cancel(); + deferredMountTask.current = null; + setRenderCoverageReady(true); } - - const state = getVirtualQueueState(); - const seed = state - ? seedVirtualQueueTracks( - rollingUpcomingTracksRef.current, - state.activePosition, - state.totalCount, - ) - : []; - virtualTracksRef.current = seed; - setVirtualTracks(seed); - + const state = resetVirtualTracks(); if (!state) return Promise.resolve(); if (virtualLoadPromise.current) { virtualLoadQueued.current = true; @@ -358,15 +383,44 @@ export const QueueTray = memo(function QueueTray({ onClose, embedded = false }: } }); return request; - }, []); + }, [embedded, resetVirtualTracks]); virtualPageLoaderRef.current = loadVirtualPage; useEffect(() => { - void loadVirtualPage(true); - }, [loadVirtualPage, virtualActivePosition, virtualMode, virtualState?.sessionId]); + if (embedded || listPaintedRef.current) { + void loadVirtualPage(true); + } else { + resetVirtualTracks(); + } + }, [ + embedded, + loadVirtualPage, + resetVirtualTracks, + virtualActivePosition, + virtualMode, + virtualState?.sessionId, + ]); + + useEffect(() => { + if (embedded || !listPainted) return; + + const task = InteractionManager.runAfterInteractions(() => { + if (deferredMountTask.current !== task) return; + deferredMountTask.current = null; + setRenderCoverageReady(true); + void virtualPageLoaderRef.current(false); + }); + deferredMountTask.current = task; + + return () => { + task.cancel(); + if (deferredMountTask.current === task) deferredMountTask.current = null; + }; + }, [embedded, listPainted]); useEffect(() => () => { virtualLoadGeneration.current += 1; + deferredMountTask.current?.cancel(); if (virtualRetryTimer.current) clearTimeout(virtualRetryTimer.current); }, []); diff --git a/src/components/queue/queuePerformance.test.mts b/src/components/queue/queuePerformance.test.mts index 800d2e5..df3c241 100644 --- a/src/components/queue/queuePerformance.test.mts +++ b/src/components/queue/queuePerformance.test.mts @@ -1,6 +1,8 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { + QUEUE_INITIAL_RENDER_AHEAD_ROWS, + QUEUE_INITIAL_RENDER_DISTANCE, QUEUE_RENDER_AHEAD_MIN_ROWS, QUEUE_RENDER_WINDOW_MULTIPLIER, QUEUE_ROW_HEIGHT, @@ -8,6 +10,11 @@ import { queueRenderDistance, } from './queuePerformance.ts'; +test('queue opens with the former four-row render-ahead distance', () => { + assert.equal(QUEUE_INITIAL_RENDER_AHEAD_ROWS, 4); + assert.equal(QUEUE_INITIAL_RENDER_DISTANCE, QUEUE_ROW_HEIGHT * 4); +}); + test('queue render-ahead covers two windows with a twelve-row minimum', () => { assert.equal(QUEUE_RENDER_AHEAD_MIN_ROWS, 12); assert.equal(QUEUE_RENDER_WINDOW_MULTIPLIER, 2); diff --git a/src/components/queue/queuePerformance.ts b/src/components/queue/queuePerformance.ts index 5a47737..aa2e387 100644 --- a/src/components/queue/queuePerformance.ts +++ b/src/components/queue/queuePerformance.ts @@ -1,4 +1,7 @@ export const QUEUE_ROW_HEIGHT = 64; +export const QUEUE_INITIAL_RENDER_AHEAD_ROWS = 4; +export const QUEUE_INITIAL_RENDER_DISTANCE = + QUEUE_ROW_HEIGHT * QUEUE_INITIAL_RENDER_AHEAD_ROWS; export const QUEUE_RENDER_AHEAD_MIN_ROWS = 12; export const QUEUE_RENDER_WINDOW_MULTIPLIER = 2;