feat: seek media particles and speed playback

Closes #79
Closes #80
This commit is contained in:
talksik
2026-04-07 16:48:40 -07:00
parent 695adddaff
commit 9312f095b2
2 changed files with 48 additions and 7 deletions
+23 -3
View File
@@ -6,7 +6,7 @@ import type { Particle } from "@/api/types";
import { parseParticlePath, particlePath, toFirestoreDocPath, type ParticlePath } from "@/lib/particle-path";
import { ComposeOverlay } from "@/features/compose/compose-overlay";
import { PlaybackPageIndicator } from "@/features/particles/playback-page-indicator";
import { MediaParticleView } from "@/features/particles/media-particle-view";
import { MediaParticleView, type MediaParticleHandle } from "@/features/particles/media-particle-view";
import { TextParticleView } from "@/features/particles/text-particle-view";
import { FallbackParticleView } from "@/features/particles/fallback-particle-view";
import { Avatar, AvatarFallback, AvatarGroup } from "@/components/ui/avatar";
@@ -140,8 +140,11 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
authedUser?.id,
);
const mediaRef = useRef<MediaParticleHandle>(null);
const [composeActive, setComposeActive] = useState(false);
const [progress, setProgress] = useState(0);
const [fastPlayback, setFastPlayback] = useState(false);
// Show/hide chrome on mouse activity (YouTube-style)
const [showControls, setShowControls] = useState(true);
@@ -196,17 +199,23 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
case "ArrowRight":
case "ArrowDown":
e.preventDefault();
next();
if (!mediaRef.current?.seek(10)) next();
break;
case "ArrowLeft":
case "ArrowUp":
e.preventDefault();
prev();
if (!mediaRef.current?.seek(-10)) prev();
break;
case " ":
e.preventDefault();
if (!e.repeat) pause();
break;
case "Shift":
if (!e.repeat) {
mediaRef.current?.setPlaybackRate(1.5);
setFastPlayback(true);
}
break;
case "Escape":
e.preventDefault();
navigate(`/${networkId}`);
@@ -230,6 +239,10 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
e.preventDefault();
resume();
}
if (e.key === "Shift") {
mediaRef.current?.setPlaybackRate(1);
setFastPlayback(false);
}
};
window.addEventListener("keydown", handleKeyDown);
@@ -287,6 +300,7 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
case "media":
return (
<MediaParticleView
ref={mediaRef}
key={particle.id}
particle={particle}
streamPath={path}
@@ -333,6 +347,12 @@ export function StreamView({ path, streamParticle }: StreamViewProps) {
onClick={handlePlaybackClick}
>
{renderParticle(currentParticle)}
{fastPlayback && (
<div className="pointer-events-none absolute right-4 top-14 z-20 rounded-full bg-black/50 px-2.5 py-1 text-xs font-medium text-white backdrop-blur-sm">
1.5x
</div>
)}
</div>
)}
</div>