fix(ui): one transport for every control, and a queue panel that fits
The queue panel drove the playback store directly, so its buttons played locally while another device held the audio. Both control sets now go through one transport that forwards a press when the audio is elsewhere. The panel's artwork is capped against viewport height too: at full width on a phone the square alone pushed Up Next off the screen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { useMemo } from 'react';
|
||||
import { usePlaybackStore } from '../store/usePlaybackStore';
|
||||
import { useOptionalPlaybackSync } from '../components/PlaybackSyncProvider';
|
||||
|
||||
/**
|
||||
* The transport every control set should call.
|
||||
*
|
||||
* While another device holds the audio, a press has to travel to that device
|
||||
* instead of starting a second stream here. Controls that reach into the
|
||||
* playback store directly work on the desktop and silently do nothing useful
|
||||
* from a phone, so there is one place that makes the choice.
|
||||
*/
|
||||
export interface Transport {
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
toggle: () => void;
|
||||
next: () => void;
|
||||
prev: () => void;
|
||||
seek: (seconds: number) => void;
|
||||
/** True when the presses are being forwarded rather than played here. */
|
||||
remote: boolean;
|
||||
}
|
||||
|
||||
export function useTransport(): Transport {
|
||||
const sync = useOptionalPlaybackSync();
|
||||
const hasRemoteOwner = sync?.hasRemoteOwner ?? false;
|
||||
const sendCommand = sync?.sendCommand;
|
||||
|
||||
return useMemo(() => {
|
||||
const local = () => usePlaybackStore.getState();
|
||||
const away = hasRemoteOwner && sendCommand !== undefined;
|
||||
return {
|
||||
play: () => (away ? void sendCommand!({ type: 'play' }) : local().play()),
|
||||
pause: () => (away ? void sendCommand!({ type: 'pause' }) : local().pause()),
|
||||
toggle: () => {
|
||||
const playing = local().isPlaying;
|
||||
if (away) void sendCommand!({ type: playing ? 'pause' : 'play' });
|
||||
else if (playing) local().pause();
|
||||
else local().play();
|
||||
},
|
||||
next: () => (away ? void sendCommand!({ type: 'next' }) : local().next()),
|
||||
prev: () => (away ? void sendCommand!({ type: 'prev' }) : local().prev()),
|
||||
seek: (seconds: number) =>
|
||||
away ? void sendCommand!({ type: 'seek', position: seconds }) : local().setPosition(seconds),
|
||||
remote: away,
|
||||
};
|
||||
}, [hasRemoteOwner, sendCommand]);
|
||||
}
|
||||
Reference in New Issue
Block a user