From 0216d2c1f1695bf5e870524b286cba879be7e245 Mon Sep 17 00:00:00 2001 From: core Date: Mon, 1 Jun 2026 22:48:02 +0500 Subject: [PATCH] =?UTF-8?q?live:=20fix=20double-click=20fullscreen=20?= =?UTF-8?q?=E2=80=94=20return=20to=20grid=20in=20mode=201,=20solo-only=20i?= =?UTF-8?q?n=20mode=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track whether fullscreen was entered by the double-click itself (_fsBySolo). Mode 1 (from the grid): a double-click fullscreens the camera and a second double-click now exits fullscreen back to live view. Mode 2 (already in fullscreen via F): double-click toggles solo/grid without leaving fullscreen; Esc or F exits. Exiting fullscreen by any means resets the flag and clears solo. Co-Authored-By: Claude Opus 4.8 (1M context) --- VERSION | 2 +- frontend/static/app.js | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/VERSION b/VERSION index b054b1a..c3fe93e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.145 +0.0.146 diff --git a/frontend/static/app.js b/frontend/static/app.js index 726d5d0..43c860a 100644 --- a/frontend/static/app.js +++ b/frontend/static/app.js @@ -505,7 +505,7 @@ class WebCodecsHevcPlayer { // Страница LIVE VIEW // ════════════════════════════════════════════════════════════════ const Live = { - cameras: [], dim: 2, layout: 4, transcode: false, go2rtcUrl: "", selected: [], singleMain: false, maxDim: 8, playing: true, page: 0, + cameras: [], dim: 2, layout: 4, transcode: false, go2rtcUrl: "", selected: [], singleMain: false, maxDim: 8, playing: true, page: 0, _fsBySolo: false, async init() { const data = await api("/api/cameras"); @@ -652,8 +652,11 @@ const Live = { if (this._fsBound) return; this._fsBound = true; const onFs = () => { - // выход из фуллскрина (в т.ч. по ESC) — снять «соло», вернуться к сетке - if (!(document.fullscreenElement || document.webkitFullscreenElement)) this.clearSolo(); + // выход из фуллскрина (в т.ч. по ESC/F) — сбросить флаг и «соло», вернуться к сетке + if (!(document.fullscreenElement || document.webkitFullscreenElement)) { + this._fsBySolo = false; + this.clearSolo(); + } this.resizePlayers(); }; document.addEventListener("fullscreenchange", onFs); @@ -853,16 +856,27 @@ const Live = { grid.querySelectorAll(".tile.solo").forEach((t) => t.classList.remove("solo")); }, - toggleSolo(tile) { // одна камера на весь экран (внутри полноэкранного режима) + // Двойной клик по камере. + // Режим 1 (из сетки): вход в фуллскрин этой камеры; повторный двойной клик — выход в live view. + // Режим 2 (уже в фуллскрине по F): соло ↔ сетка без выхода из фуллскрина (выход — Esc/F). + toggleSolo(tile) { const grid = document.getElementById("grid"); + const isFs = !!(document.fullscreenElement || document.webkitFullscreenElement); const wasSolo = grid.classList.contains("solo") && tile.classList.contains("solo"); this.clearSolo(); - if (!wasSolo) { // включить «соло» этой ячейки + if (wasSolo) { + if (this._fsBySolo) { // режим 1: фуллскрин включён самим кликом → назад в live view + this._fsBySolo = false; + if (isFs) toggleFullscreen(document.getElementById("live-main") || grid); + } // режим 2 (вошли по F): остаёмся в фуллскрине — просто сетка + } else { grid.classList.add("solo"); tile.classList.add("solo"); - // ещё не в полноэкранном — войти, чтобы камера заняла весь экран (выход — ESC) - if (!(document.fullscreenElement || document.webkitFullscreenElement)) toggleFullscreen(document.getElementById("live-main") || grid); - } // повторный двойной клик — назад к сетке (фуллскрин сохраняется) + if (!isFs) { // режим 1: входим в фуллскрин этой камеры + this._fsBySolo = true; + toggleFullscreen(document.getElementById("live-main") || grid); + } + } this.resizePlayers(); },