fix(video): 全屏关闭后内嵌进度条跳变而非从0扫动

程序化 seek 同步全屏播放进度时,新增 snapProgress 抑制进度条
的宽度过渡动画,使其直接落到观看位置,恢复播放时再启用过渡。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
TerryM
2026-05-30 16:54:03 +08:00
parent eb0eabe21f
commit 07f040a549

View File

@@ -120,13 +120,22 @@ export function MessageInlineVideo({
const [currentTime, setCurrentTime] = useState(initialTime); const [currentTime, setCurrentTime] = useState(initialTime);
const [duration, setDuration] = useState(attachment.durationSec ?? 0); const [duration, setDuration] = useState(attachment.durationSec ?? 0);
const [isScrubbing, setIsScrubbing] = useState(false); const [isScrubbing, setIsScrubbing] = useState(false);
// When we programmatically seek (e.g. syncing the playhead back from the
// fullscreen overlay) the progress fill should jump straight to the watched
// position instead of sweeping up from its old width via the CSS transition.
// Cleared as soon as real playback resumes so live progress stays smooth.
const [snapProgress, setSnapProgress] = useState(false);
const t = TOKENS[size]; const t = TOKENS[size];
useEffect(() => { useEffect(() => {
const v = videoRef.current; const v = videoRef.current;
if (!v) return; if (!v) return;
const onPlay = () => setIsPlaying(true); const onPlay = () => {
setIsPlaying(true);
// Real playback advances the fill smoothly again; re-enable transitions.
setSnapProgress(false);
};
const onPause = () => setIsPlaying(false); const onPause = () => setIsPlaying(false);
const onTime = () => { const onTime = () => {
setCurrentTime(v.currentTime); setCurrentTime(v.currentTime);
@@ -232,7 +241,9 @@ export function MessageInlineVideo({
// Update React state synchronously so the progress bar paints the // Update React state synchronously so the progress bar paints the
// new playhead in the next frame, before the <video> seek round- // new playhead in the next frame, before the <video> seek round-
// trip emits its own events (paused videos don't fire timeupdate // trip emits its own events (paused videos don't fire timeupdate
// and `seeked` can lag ~hundreds of ms). // and `seeked` can lag ~hundreds of ms). Snap the fill to the new
// position so it doesn't sweep up from its pre-fullscreen width.
setSnapProgress(true);
setCurrentTime(finalTime); setCurrentTime(finalTime);
onTimeUpdate?.(finalTime); onTimeUpdate?.(finalTime);
const apply = () => { const apply = () => {
@@ -334,7 +345,9 @@ export function MessageInlineVideo({
> >
<div <div
className={`h-full bg-white ${ className={`h-full bg-white ${
isScrubbing ? "" : "transition-[width] duration-150 ease-out" isScrubbing || snapProgress
? ""
: "transition-[width] duration-150 ease-out"
}`} }`}
style={{ width: `${progressPct}%` }} style={{ width: `${progressPct}%` }}
/> />