45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { useCallback, useState } from 'react';
|
|
import type { Particle } from '@/api/types';
|
|
|
|
export type StreamViewMode = 'player' | 'list';
|
|
|
|
function decideMode(
|
|
streamParticle: Particle & { type: 'stream' },
|
|
userId: string | undefined,
|
|
): StreamViewMode {
|
|
const marker = userId ? streamParticle.playback_markers?.[userId] : undefined;
|
|
const lastChildAt = streamParticle.last_child_created_at;
|
|
const caughtUp =
|
|
!!marker && !!lastChildAt && lastChildAt.getTime() <= marker.getTime();
|
|
return caughtUp ? 'list' : 'player';
|
|
}
|
|
|
|
/**
|
|
* Which mode a stream opens in: the player (autoplay catch-up) when there's
|
|
* unseen content, the browsable list when the user is fully caught up.
|
|
* Decided once on entry from the playback marker vs. the stream's last
|
|
* activity — browsing afterwards advances the marker, but the mode only
|
|
* changes via the user's toggle.
|
|
*/
|
|
export function useStreamViewMode(
|
|
streamParticle: Particle & { type: 'stream' },
|
|
userId: string | undefined,
|
|
): { mode: StreamViewMode; toggle: () => void } {
|
|
const [mode, setMode] = useState<StreamViewMode>(() =>
|
|
decideMode(streamParticle, userId),
|
|
);
|
|
|
|
// Re-decide when navigating between streams without an unmount.
|
|
const [prevStreamId, setPrevStreamId] = useState(streamParticle.id);
|
|
if (prevStreamId !== streamParticle.id) {
|
|
setPrevStreamId(streamParticle.id);
|
|
setMode(decideMode(streamParticle, userId));
|
|
}
|
|
|
|
const toggle = useCallback(() => {
|
|
setMode((prev) => (prev === 'player' ? 'list' : 'player'));
|
|
}, []);
|
|
|
|
return { mode, toggle };
|
|
}
|