| | |
| | | export const DISPATCH_VIDEO_END_POSTER = VEHICLE_APPROACHING_END_POSTER; |
| | | /** 兜底超时(ms):防卡死安全阀——视频加载/播放失败时 onTimeUpdate/onEnded 都不触发,超过此时长强制归位 */ |
| | | export const DISPATCH_FALLBACK_MS = 10000; |
| | | /** |
| | | * 结尾遮挡层提前量(秒):结尾遮挡层只需在视频「真正快播放完」时才盖上(此值即距视频自然结束的秒数)。 |
| | | * 必须显著小于 BG_SHRINK_LEAD_SEC——否则遮挡层会在背景刚开始收缩、视频仍在播时就盖住,抹掉视频尾段效果。 |
| | | */ |
| | | export const END_COVER_LEAD_SEC = 0.4; |
| | | |
| | | export type DispatchPhase = 'idle' | 'video' | 'settle'; |
| | | |
| | |
| | | export function useDispatchTransition(playDispatchTransition: boolean) { |
| | | const [dispatchPhase, setDispatchPhase] = useState<DispatchPhase>('idle'); |
| | | const [transitionDone, setTransitionDone] = useState(false); |
| | | // 结尾遮挡层是否可见。独立于 settle:settle 起即开始背景收缩(视频仍在播), |
| | | // 而遮挡层延后到视频「真正快播放完」(距结束 END_COVER_LEAD_SEC)才置真,避免过早盖住视频尾段。 |
| | | const [endCoverVisible, setEndCoverVisible] = useState(false); |
| | | // shouldPlayEnter 控制转场期间的内容延迟、背景图门槛与整卡升起 keyframe。 |
| | | // 过去依赖 CallingCar 的 key={tripStatus} 重挂载做「挂载快照」,去 key 后组件不再重挂载, |
| | | // 改为在渲染期同步捕捉 playDispatchTransition 的上升沿(false→true)置真—— |
| | |
| | | |
| | | const enterTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| | | const settleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| | | const endCoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| | | const fallbackTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| | | const settleTriggeredRef = useRef(false); |
| | | |
| | |
| | | settleTriggeredRef.current = true; |
| | | if (fallbackTimerRef.current) clearTimeout(fallbackTimerRef.current); |
| | | setDispatchPhase('settle'); |
| | | // 结尾遮挡层延后显示:settle 起先跑背景收缩(视频照常播放),待收缩接近尾声、视频「真正快播放完」 |
| | | // (距结束 END_COVER_LEAD_SEC)时才盖上遮挡层。settle 由精确自适应定时器在 duration-BG_SHRINK_LEAD_SEC |
| | | // 触发,故此处再等 (BG_SHRINK_LEAD_SEC-END_COVER_LEAD_SEC) 即精确落在 duration-END_COVER_LEAD_SEC。 |
| | | // 该时刻仍早于本层卸载(settleTimer 800ms),遮挡层可先于视频卸载上屏、挡住卸载黑帧。 |
| | | // 兜底路径(onError/超时触发的 settle)同样适用:遮挡层在 settle 后固定延时出现,早于 settleTimer。 |
| | | if (endCoverTimerRef.current) clearTimeout(endCoverTimerRef.current); |
| | | endCoverTimerRef.current = setTimeout( |
| | | () => setEndCoverVisible(true), |
| | | Math.max((BG_SHRINK_LEAD_SEC - END_COVER_LEAD_SEC) * 1000, 0), |
| | | ); |
| | | if (settleTimerRef.current) clearTimeout(settleTimerRef.current); |
| | | settleTimerRef.current = setTimeout(() => { |
| | | setDispatchPhase('idle'); |
| | |
| | | |
| | | if (enterTimerRef.current) clearTimeout(enterTimerRef.current); |
| | | if (settleTimerRef.current) clearTimeout(settleTimerRef.current); |
| | | if (endCoverTimerRef.current) clearTimeout(endCoverTimerRef.current); |
| | | if (fallbackTimerRef.current) clearTimeout(fallbackTimerRef.current); |
| | | if (shrinkTimerRef.current) clearTimeout(shrinkTimerRef.current); |
| | | settleTriggeredRef.current = false; |
| | |
| | | lastTimeSyncRef.current = { currentTime: 0, wallClock: 0 }; |
| | | videoDurationRef.current = 0; |
| | | setTransitionDone(false); |
| | | setEndCoverVisible(false); |
| | | setDispatchPhase('idle'); |
| | | |
| | | enterTimerRef.current = setTimeout(() => { |
| | |
| | | return () => { |
| | | if (enterTimerRef.current) clearTimeout(enterTimerRef.current); |
| | | if (settleTimerRef.current) clearTimeout(settleTimerRef.current); |
| | | if (endCoverTimerRef.current) clearTimeout(endCoverTimerRef.current); |
| | | if (fallbackTimerRef.current) clearTimeout(fallbackTimerRef.current); |
| | | if (shrinkTimerRef.current) clearTimeout(shrinkTimerRef.current); |
| | | }; |
| | |
| | | dispatchPhase, |
| | | transitionDone, |
| | | shouldPlayEnter, |
| | | endCoverVisible, |
| | | enterSettle, |
| | | handleDispatchVideoTimeUpdate, |
| | | }; |