Stop the video jumping

This commit is contained in:
dirwin31
2026-08-27 18:01:49 -07:00
parent f0d8de490c
commit 695573c057
3 changed files with 45 additions and 7 deletions
@@ -1257,6 +1257,7 @@
/* Match qcamera.ts so the visible frame does not widen during the full-quality swap. */
aspect-ratio: 526 / 330;
background: #07080b;
contain: layout paint;
overflow: hidden;
position: relative;
width: 100%;
@@ -1264,12 +1265,16 @@
.dashcam-player-overlay .dashcam-player .dashcam-video-shell video {
border-radius: 0;
height: 100%;
display: block;
height: 100% !important;
inset: 0;
/* Keep the visible frame size fixed when qcamera swaps to a wider full stream. */
max-height: none;
max-width: none;
/* Crop both encodes into the same viewport instead of letting intrinsic media sizing win. */
object-fit: cover;
object-position: center center;
position: absolute;
width: 100%;
width: 100% !important;
}
.dashcam-player-overlay .dashcam-player .dashcam-video-shell video.active {
@@ -359,6 +359,30 @@ async function openOverlay(route) {
let upgradeTimer = null
let isUpgrading = false
const clearDeferredNativeControls = video => {
if (typeof video._dashcamControlsCleanup === "function") video._dashcamControlsCleanup()
}
const setNativeControls = (video, enabled) => {
clearDeferredNativeControls(video)
video.controls = enabled
}
const deferNativeControlsUntilInteraction = video => {
clearDeferredNativeControls(video)
video.controls = false
const restore = () => {
if (video !== activeVideo || !overlay) return
setNativeControls(video, true)
}
const events = ["pointermove", "pointerdown", "focus"]
const cleanup = () => {
events.forEach(eventName => video.removeEventListener(eventName, restore))
delete video._dashcamControlsCleanup
}
video._dashcamControlsCleanup = cleanup
events.forEach(eventName => video.addEventListener(eventName, restore))
}
const setPlayerMessage = (message, isError = false) => {
playerState.textContent = message
playerState.hidden = !message
@@ -386,6 +410,7 @@ async function openOverlay(route) {
upgradeController = null
stagingVideo.pause()
stagingVideo.removeAttribute("src")
setNativeControls(stagingVideo, false)
stagingVideo.load()
}
@@ -452,11 +477,12 @@ async function openOverlay(route) {
activeVideo.classList.remove("active")
activeVideo.classList.add("staging")
activeVideo.controls = false
setNativeControls(activeVideo, false)
stagingVideo.classList.remove("staging")
stagingVideo.classList.add("active")
stagingVideo.controls = true
if (isPlaying) deferNativeControlsUntilInteraction(stagingVideo)
else setNativeControls(stagingVideo, true)
const oldActive = activeVideo
activeVideo = stagingVideo
@@ -559,11 +585,11 @@ async function openOverlay(route) {
stagingVideo.removeAttribute("src")
stagingVideo.classList.remove("active")
stagingVideo.classList.add("staging")
stagingVideo.controls = false
setNativeControls(stagingVideo, false)
activeVideo.classList.remove("staging")
activeVideo.classList.add("active")
activeVideo.controls = true
setNativeControls(activeVideo, true)
activeVideo.src = cameraVideoUrl(segmentUrl, camera, showingPreview ? "low" : undefined)
activeVideo.load()
if (autoplay) activeVideo.play().catch(() => {})
@@ -737,6 +763,7 @@ function closeOverlay() {
document.removeEventListener("keydown", overlay._closeOnEscape)
const videos = overlay.querySelectorAll("video")
videos.forEach(v => {
v._dashcamControlsCleanup?.()
v.pause()
v.removeAttribute("src")
v.load()
@@ -90,9 +90,15 @@ def test_sort_order_select_and_route_items_are_keyed_and_reactive():
def test_player_shell_keeps_both_quality_levels_at_one_fixed_size():
source = COMPONENT_CSS_PATH.read_text(encoding="utf-8")
component = COMPONENT_PATH.read_text(encoding="utf-8")
assert "aspect-ratio: 526 / 330;" in source
assert "contain: layout paint;" in source
assert "height: 100% !important;" in source
assert "width: 100% !important;" in source
assert "object-fit: cover;" in source
assert "deferNativeControlsUntilInteraction(stagingVideo)" in component
assert "stagingVideo.controls = true" not in component
def test_groups_routes_into_today_yesterday_dates_and_unknown():