From 35f14ab0445f0f87aac2772bb72b1441ee7b8299 Mon Sep 17 00:00:00 2001 From: Vincent Rozenberg Date: Fri, 4 Sep 2026 01:56:08 +0200 Subject: [PATCH] feat: fullscreen carries across videos, and stays out of the way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In fullscreen, Next now keeps you there and shows nothing but the picture: one video after another, no arrows, no header, no counter. Three things had to change for that. The player was keyed on the video, so every Next rebuilt the stage — and the stage is what is fullscreen. It now survives, resetting its own per-video state instead of being thrown away to get it. The cleanup that ran on every change of source called exitFullscreen outright. It exists for the Picture-in-Picture leak, which does need handling per video; leaving fullscreen and dropping the source belong to leaving the player, and are now only done there. And resolving a stream set the source to nothing first, which unmounted the element mid-fullscreen. The outgoing video is paused in place instead, and the source goes straight from one address to the next. The edge arrows are gone in fullscreen. The transport bar stays — it is playback, not navigation — and fades on its own as before. Also: Remove all downloads in the menu bar panel, which asks in the window rather than in a panel that closes when you look away; and the JavaScript round-trip logging is gone now that the scrape is settled. Verified in the running app: three videos in a row without leaving fullscreen, chrome faded to nothing, and Remove all reaching the window's own "Delete every download?" with 50 downloads left untouched. --- src-tauri/src/tray.rs | 15 +- src/App.tsx | 14 +- src/components/Player.tsx | 272 +++++++++++++++++++++++++++-------- src/components/TrayPanel.tsx | 23 +++ 4 files changed, 251 insertions(+), 73 deletions(-) diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index d86c6d2..5c897a5 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -129,15 +129,6 @@ async fn browser_youtube_url(app: &AppHandle) -> Result { /// Arc allows this out of the box. Chrome and its relatives ship with it off, /// and say so in the error, which is passed straight back rather than being /// flattened into "something went wrong". -pub async fn run_js_logged(app: &AppHandle, browser: &str, js: &str) -> Result { - let r = run_js(browser, js).await; - match &r { - Ok(out) => log(app, &format!("js ok, {} chars back", out.len())), - Err(e) => log(app, &format!("js failed: {e}")), - } - r -} - pub async fn run_js(browser: &str, js: &str) -> Result { let safari = browser == "Safari"; let script = if safari { @@ -211,7 +202,7 @@ pub async fn scrape_subscriptions(app: &AppHandle) -> Result() .unwrap_or(0); @@ -232,7 +223,7 @@ pub async fn scrape_subscriptions(app: &AppHandle) -> Result { + const un = listen("downloads:wipe-request", () => setConfirmWipe(true)); + return () => { + void un.then((f) => f()); + }; + }, []); + // The menu bar reads the subscription list, but replacing what is here is // not a thing to agree to in a panel that closes when you look away. useEffect(() => { @@ -742,9 +751,12 @@ export default function App() { + {/* The player is deliberately not keyed on the video. Remounting would + build a new stage element, and the stage is what is fullscreen — so + every Next dropped out of fullscreen. It resets its own per-video + state instead. */} {playing && playingIndex != null && ( completely. + * Ends any Picture-in-Picture session on a