From da87170047f26832de818c745f729b23885cd4d1 Mon Sep 17 00:00:00 2001 From: EtienneLescot Date: Sat, 22 Aug 2026 12:40:31 +0200 Subject: [PATCH] Revert "fix(timeline): remove the dead Add Full Camera toolbar button" This reverts commit cca6fe86a26b4311bf6ff2751787a0623ff06b77. --- .../v4/V4Timeline.geometry.test.tsx | 30 +++++++++++++++---- src/components/ai-edition/v4/V4Timeline.tsx | 20 ++++++++++--- src/i18n/locales/ar/timeline.json | 3 +- src/i18n/locales/en/timeline.json | 3 +- src/i18n/locales/es/timeline.json | 3 +- src/i18n/locales/fr/timeline.json | 3 +- src/i18n/locales/it/timeline.json | 3 +- src/i18n/locales/ja-JP/timeline.json | 3 +- src/i18n/locales/ko-KR/timeline.json | 3 +- src/i18n/locales/pt-BR/timeline.json | 3 +- src/i18n/locales/ru/timeline.json | 3 +- src/i18n/locales/tr/timeline.json | 3 +- src/i18n/locales/vi/timeline.json | 3 +- src/i18n/locales/zh-CN/timeline.json | 3 +- src/i18n/locales/zh-TW/timeline.json | 3 +- src/lib/ai-edition/store/useTimeline.ts | 6 ++-- 16 files changed, 69 insertions(+), 26 deletions(-) diff --git a/src/components/ai-edition/v4/V4Timeline.geometry.test.tsx b/src/components/ai-edition/v4/V4Timeline.geometry.test.tsx index d237428f5..f3a067bca 100644 --- a/src/components/ai-edition/v4/V4Timeline.geometry.test.tsx +++ b/src/components/ai-edition/v4/V4Timeline.geometry.test.tsx @@ -64,7 +64,7 @@ function clip(startSec: number, endSec: number) { } /** The asset every clip above points at. No `cameraTrack`: this recording has no webcam, - * which is what Add Full Camera is gated on. */ + * which is what the Full Camera button is gated on. */ const NO_CAMERA_ASSET = { id: "a1", label: "rec", durationSec: TOTAL_SEC }; /** By default one 30-minute clip carrying a single one-second annotation. */ @@ -221,11 +221,29 @@ describe("V4Timeline create-from-toolbar", () => { expect(durationOf(tl)).toBeCloseTo(0.25, 3); }); - // The toolbar button is gone, but Add Full Camera is still reachable via the `C` - // shortcut, and an empty lane advertises it — so on a camera-less project it was - // still inviting a `C` press that `addCameraFullscreen` refuses (#353). It borrows - // the Layout pane's "No Webcam" wording instead, so the two surfaces agree about - // the same project. + // #353. A camera-fullscreen region grows the webcam overlay, so with no webcam on the + // timeline it renders nothing in the preview and nothing in the export — the region is + // stored and forgotten. `addCameraFullscreen` now refuses to write one; the button says + // so before it is clicked instead of looking like it worked. + it("disables Add Full Camera when no clip on the timeline has a camera", () => { + renderTimeline(); + expect(screen.getByTitle("buttons.addCameraFullscreen")).toBeDisabled(); + }); + + it("enables Add Full Camera as soon as a clip's asset carries one", () => { + renderTimeline(undefined, undefined, [ + { + ...NO_CAMERA_ASSET, + cameraTrack: { sourcePath: "/tmp/cam.webm", startMs: 0, offsetMs: 0, visible: true }, + }, + ]); + expect(screen.getByTitle("buttons.addCameraFullscreen")).toBeEnabled(); + }); + + // The disabled button is only half the promise: an empty lane advertises the shortcut + // that fills it, so on a camera-less project it was still inviting a `C` press that + // `addCameraFullscreen` now refuses. It borrows the Layout pane's "No Webcam" wording + // instead, so the two surfaces agree about the same project. it("does not advertise the C shortcut on a lane that cannot be filled", () => { renderTimeline(); expect(screen.getByText("layout.noWebcam")).toBeInTheDocument(); diff --git a/src/components/ai-edition/v4/V4Timeline.tsx b/src/components/ai-edition/v4/V4Timeline.tsx index a6300bb47..493f17d5c 100644 --- a/src/components/ai-edition/v4/V4Timeline.tsx +++ b/src/components/ai-edition/v4/V4Timeline.tsx @@ -431,9 +431,9 @@ export function V4Timeline({ const clips = tl.clips; // A camera-fullscreen region grows the webcam overlay, so on a project with no webcam // it renders nothing in the preview and nothing in the export. `addCameraFullscreen` - // refuses to write one (see useTimeline) — this is why the empty lane's hint below - // swaps to "no webcam" instead of advertising the `C` shortcut. Same question, same - // helper as the Layout pane: is a camera attached anywhere on this timeline? + // refuses to write one (see useTimeline) — this makes the control say so before it is + // clicked instead of looking like it worked. Same question, same helper as the Layout + // pane: is a camera attached anywhere on this timeline? const hasAnyCamera = useMemo(() => hasAnyClipWithCamera(tl.assets, clips), [tl.assets, clips]); const total = useMemo( () => @@ -1359,6 +1359,17 @@ export function V4Timeline({ > + ) : ( // Media is an ARRANGING surface: add, remove, reorder. Nothing here @@ -1452,7 +1463,8 @@ export function V4Timeline({
{renderPills(zoomPills, t("hints.pressZoom"))}
{/* Advertising "Press C" on a project with no webcam invites a keystroke - that `addCameraFullscreen` now refuses (#353). */} + that `addCameraFullscreen` now refuses (#353). The toolbar button is + already disabled; this keeps the lane from contradicting it. */} {renderPills( cameraFullscreenPills, hasAnyCamera ? t("hints.pressCameraFullscreen") : ts("layout.noWebcam"), diff --git a/src/i18n/locales/ar/timeline.json b/src/i18n/locales/ar/timeline.json index e434620eb..4412a0a0b 100644 --- a/src/i18n/locales/ar/timeline.json +++ b/src/i18n/locales/ar/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "تفعيل التركيز التلقائي لجميع التكبيرات (الكاميرا تتبع المؤشر)", "addTrim": "إضافة قص (T)", "addAnnotation": "إضافة شرح (A)", - "addSpeed": "إضافة سرعة (S)" + "addSpeed": "إضافة سرعة (S)", + "addCameraFullscreen": "إضافة كاميرا كاملة الشاشة (C)" }, "hints": { "pressZoom": "اضغط Z لإضافة تكبير", diff --git a/src/i18n/locales/en/timeline.json b/src/i18n/locales/en/timeline.json index cd15921ef..c41966115 100644 --- a/src/i18n/locales/en/timeline.json +++ b/src/i18n/locales/en/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Auto-Focus all zooms (camera follows the cursor)", "addTrim": "Add Trim (T)", "addAnnotation": "Add Annotation (A)", - "addSpeed": "Add Speed (S)" + "addSpeed": "Add Speed (S)", + "addCameraFullscreen": "Add Full Camera (C)" }, "hints": { "pressZoom": "Press Z to add zoom", diff --git a/src/i18n/locales/es/timeline.json b/src/i18n/locales/es/timeline.json index c05eebf89..989289e00 100644 --- a/src/i18n/locales/es/timeline.json +++ b/src/i18n/locales/es/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Activar enfoque automático para todos los zooms (la cámara sigue el cursor)", "addTrim": "Agregar recorte (T)", "addAnnotation": "Agregar anotación (A)", - "addSpeed": "Agregar velocidad (S)" + "addSpeed": "Agregar velocidad (S)", + "addCameraFullscreen": "Agregar cámara a pantalla completa (C)" }, "hints": { "pressZoom": "Presiona Z para agregar zoom", diff --git a/src/i18n/locales/fr/timeline.json b/src/i18n/locales/fr/timeline.json index 3147db21d..a35b8858a 100644 --- a/src/i18n/locales/fr/timeline.json +++ b/src/i18n/locales/fr/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Activer la mise au point automatique pour tous les zooms (la caméra suit le curseur)", "addTrim": "Ajouter une coupe (T)", "addAnnotation": "Ajouter une annotation (A)", - "addSpeed": "Ajouter une vitesse (S)" + "addSpeed": "Ajouter une vitesse (S)", + "addCameraFullscreen": "Ajouter Caméra plein écran (C)" }, "hints": { "pressZoom": "Appuyez sur Z pour ajouter un zoom", diff --git a/src/i18n/locales/it/timeline.json b/src/i18n/locales/it/timeline.json index 468764831..09bb116ee 100644 --- a/src/i18n/locales/it/timeline.json +++ b/src/i18n/locales/it/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Attiva la messa a fuoco automatica per tutti gli zoom (la fotocamera segue il cursore)", "addTrim": "Aggiungi taglio (T)", "addAnnotation": "Aggiungi annotazione (A)", - "addSpeed": "Aggiungi velocità (S)" + "addSpeed": "Aggiungi velocità (S)", + "addCameraFullscreen": "Aggiungi Camera a schermo intero (C)" }, "hints": { "pressZoom": "Premi Z per aggiungere zoom", diff --git a/src/i18n/locales/ja-JP/timeline.json b/src/i18n/locales/ja-JP/timeline.json index 7ebcc6b36..68911ba91 100644 --- a/src/i18n/locales/ja-JP/timeline.json +++ b/src/i18n/locales/ja-JP/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "すべてのズームでオートフォーカスをオンにする(カメラがカーソルに追従)", "addTrim": "トリムを追加 (T)", "addAnnotation": "注釈を追加 (A)", - "addSpeed": "再生速度を追加 (S)" + "addSpeed": "再生速度を追加 (S)", + "addCameraFullscreen": "フルスクリーンカメラを追加 (C)" }, "hints": { "pressZoom": "Zキーを押してズームを追加", diff --git a/src/i18n/locales/ko-KR/timeline.json b/src/i18n/locales/ko-KR/timeline.json index 986d173ce..8a100ee6d 100644 --- a/src/i18n/locales/ko-KR/timeline.json +++ b/src/i18n/locales/ko-KR/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "모든 줌에 자동 초점 켜기 (카메라가 커서를 따라갑니다)", "addTrim": "트림 추가 (T)", "addAnnotation": "주석 추가 (A)", - "addSpeed": "속도 추가 (S)" + "addSpeed": "속도 추가 (S)", + "addCameraFullscreen": "전체 화면 카메라 추가 (C)" }, "hints": { "pressZoom": "Z를 눌러 줌 추가", diff --git a/src/i18n/locales/pt-BR/timeline.json b/src/i18n/locales/pt-BR/timeline.json index ed9c42bd7..5359feba9 100644 --- a/src/i18n/locales/pt-BR/timeline.json +++ b/src/i18n/locales/pt-BR/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Ativar foco automático para todos os zooms (a câmera segue o cursor)", "addTrim": "Adicionar Recorte (T)", "addAnnotation": "Adicionar Anotação (A)", - "addSpeed": "Adicionar Velocidade (S)" + "addSpeed": "Adicionar Velocidade (S)", + "addCameraFullscreen": "Adicionar Câmera em Tela Cheia (C)" }, "hints": { "pressZoom": "Pressione Z para adicionar zoom", diff --git a/src/i18n/locales/ru/timeline.json b/src/i18n/locales/ru/timeline.json index 9ce1261fb..387086953 100644 --- a/src/i18n/locales/ru/timeline.json +++ b/src/i18n/locales/ru/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Включить автофокус для всех зумов (камера следует за курсором)", "addTrim": "Добавить обрезку (T)", "addAnnotation": "Добавить аннотацию (A)", - "addSpeed": "Изменить скорость (S)" + "addSpeed": "Изменить скорость (S)", + "addCameraFullscreen": "Добавить камеру на весь экран (C)" }, "hints": { "pressZoom": "Нажмите Z для добавления масштабирования", diff --git a/src/i18n/locales/tr/timeline.json b/src/i18n/locales/tr/timeline.json index c56c0613b..d5a531f3e 100644 --- a/src/i18n/locales/tr/timeline.json +++ b/src/i18n/locales/tr/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Tüm yakınlaştırmalarda Otomatik Odağı aç (kamera imleci takip eder)", "addTrim": "Kırpma Ekle (T)", "addAnnotation": "Açıklama Ekle (A)", - "addSpeed": "Hız Ekle (S)" + "addSpeed": "Hız Ekle (S)", + "addCameraFullscreen": "Tam Ekran Kamera Ekle (C)" }, "hints": { "pressZoom": "Yakınlaştırma eklemek için Z tuşuna basın", diff --git a/src/i18n/locales/vi/timeline.json b/src/i18n/locales/vi/timeline.json index fe6011b27..1d963e585 100644 --- a/src/i18n/locales/vi/timeline.json +++ b/src/i18n/locales/vi/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "Bật lấy nét tự động cho tất cả các thu phóng (máy ảnh theo dõi con trỏ)", "addTrim": "Thêm Cắt (T)", "addAnnotation": "Thêm Chú thích (A)", - "addSpeed": "Thêm Tốc độ (S)" + "addSpeed": "Thêm Tốc độ (S)", + "addCameraFullscreen": "Thêm Camera Toàn màn hình (C)" }, "hints": { "pressZoom": "Nhấn Z để thêm thu phóng", diff --git a/src/i18n/locales/zh-CN/timeline.json b/src/i18n/locales/zh-CN/timeline.json index bd405fa89..1451e6d31 100644 --- a/src/i18n/locales/zh-CN/timeline.json +++ b/src/i18n/locales/zh-CN/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "为所有缩放开启自动对焦(摄像头跟随光标)", "addTrim": "添加剪辑 (T)", "addAnnotation": "添加标注 (A)", - "addSpeed": "添加速度 (S)" + "addSpeed": "添加速度 (S)", + "addCameraFullscreen": "添加全屏摄像头 (C)" }, "hints": { "pressZoom": "按 Z 添加缩放", diff --git a/src/i18n/locales/zh-TW/timeline.json b/src/i18n/locales/zh-TW/timeline.json index 6692ad24a..7f4ba9874 100644 --- a/src/i18n/locales/zh-TW/timeline.json +++ b/src/i18n/locales/zh-TW/timeline.json @@ -8,7 +8,8 @@ "autoFocusAllOff": "為所有縮放開啟自動對焦(攝影機跟隨游標)", "addTrim": "新增剪輯 (T)", "addAnnotation": "新增標註 (A)", - "addSpeed": "新增速度 (S)" + "addSpeed": "新增速度 (S)", + "addCameraFullscreen": "新增全螢幕攝影機 (C)" }, "hints": { "pressZoom": "按 Z 新增縮放", diff --git a/src/lib/ai-edition/store/useTimeline.ts b/src/lib/ai-edition/store/useTimeline.ts index 67f2ecdfb..7823459ec 100644 --- a/src/lib/ai-edition/store/useTimeline.ts +++ b/src/lib/ai-edition/store/useTimeline.ts @@ -407,9 +407,9 @@ export function useTimeline() { // a missing `webcamRect`) and nothing in the export — it just sits in // `legacyEditor.cameraFullscreenRegions` forever. The agent's `addCameraFullscreen` // tool already refuses this and says why (electron/ai-edition/agent-tools.ts, - // `noCameraUnderSpan`); the gate lives HERE rather than at each caller so the `C` - // shortcut and any future entry point are covered by construction. - // `hasAnyClipWithCamera` is the consolidated answer to "does this + // `noCameraUnderSpan`); the gate lives HERE rather than at each button so both UI + // entry points — the toolbar and the `C` shortcut — and any future one are covered + // by construction. `hasAnyClipWithCamera` is the consolidated answer to "does this // project have a camera at all", used the same way by the Layout pane. const addCameraFullscreen = useCallback( async (durationSec = DEFAULT_NEW_REGION_SEC) => {