From 0c234b691e9fdb7a20544d66ce9b6bda1c08f326 Mon Sep 17 00:00:00 2001 From: Garret Patti <42485635+garretpatti@users.noreply.github.com> Date: Sun, 5 Apr 2026 21:47:44 -0400 Subject: [PATCH] add auto mode and controls --- src/components/DoomScrollView.tsx | 145 ++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 15 deletions(-) diff --git a/src/components/DoomScrollView.tsx b/src/components/DoomScrollView.tsx index 7392127..d677ed8 100644 --- a/src/components/DoomScrollView.tsx +++ b/src/components/DoomScrollView.tsx @@ -26,17 +26,25 @@ function pickRandom(items: DoomScrollItem[], excludeRecent: DoomScrollItem[]): D export default function DoomScrollView({ items, videoContext = 'mixed', onClose }: Props) { const settings = useUserSettings() - const muted = videoContext === 'mixed' ? settings.mixedMuted : videoContext === 'movies' ? settings.moviesMuted : settings.tvMuted + const settingsMuted = videoContext === 'mixed' ? settings.mixedMuted : videoContext === 'movies' ? settings.moviesMuted : settings.tvMuted const [history, setHistory] = useState(() => { if (items.length === 0) return [] return [pickRandom(items, [])] }) const [historyIndex, setHistoryIndex] = useState(0) + const [localMuted, setLocalMuted] = useState(settingsMuted) + const [isPaused, setIsPaused] = useState(false) + const [autoPlayEnabled, setAutoPlayEnabled] = useState(false) + const [autoPlaySeconds, setAutoPlaySeconds] = useState(5) + + const videoRef = useRef(null) const cooldownRef = useRef(false) const touchStartY = useRef(null) const current = history[historyIndex] ?? null + const isVideo = current?.mediaType === 'video' + const backCount = history.length - 1 - historyIndex const goNext = useCallback(() => { if (items.length === 0) return @@ -65,6 +73,33 @@ export default function DoomScrollView({ items, videoContext = 'mixed', onClose setTimeout(() => { cooldownRef.current = false }, 300) }, [goNext, goPrev]) + // Reset pause when switching items + useEffect(() => { + setIsPaused(false) + }, [current?.url]) + + // Sync muted imperatively — React's muted prop is not reliable + useEffect(() => { + if (videoRef.current) videoRef.current.muted = localMuted + }, [localMuted, current?.url]) + + // Sync play/pause imperatively + useEffect(() => { + if (!videoRef.current) return + if (isPaused) { + videoRef.current.pause() + } else { + videoRef.current.play().catch(() => {}) + } + }, [isPaused, current?.url]) + + // Auto-play timer — resets on each new item, pause, enable/disable, or interval change + useEffect(() => { + if (!autoPlayEnabled || isPaused) return + const id = setTimeout(() => goNext(), autoPlaySeconds * 1000) + return () => clearTimeout(id) + }, [autoPlayEnabled, isPaused, autoPlaySeconds, current?.url, goNext]) + useEffect(() => { const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') { onClose(); return } @@ -100,18 +135,58 @@ export default function DoomScrollView({ items, videoContext = 'mixed', onClose } }, [navigate, onClose]) - const backCount = history.length - 1 - historyIndex - return (
+ {/* Keyframe for auto-play progress bar */} + + {/* Top bar */} -
- - {backCount > 0 ? `← ${backCount} back` : 'Doom Scroll'} +
+ + {backCount > 0 ? `← ${backCount}` : 'Doom Scroll'} + + {/* Auto-play controls */} +
+ + {autoPlayEnabled && ( +
+ + + {autoPlaySeconds}s + + +
+ )} +
+ + )} +
+ {current?.name} +
+ {isVideo && ( + + )} +
+ {/* Auto-play progress bar — key on current URL restarts animation on each new item */} + {autoPlayEnabled && !isPaused && ( +
+ )} + {/* Prev / Next hint arrows */} {historyIndex > 0 && (