From 58609e4d999cec7b430ada416bb848f868d04617 Mon Sep 17 00:00:00 2001 From: hl-valdemar Date: Tue, 13 Oct 2026 23:51:28 +0200 Subject: [PATCH] ui: move Cast between window mode and settings controls --- README.md | 6 +++--- Sources/App/CastControls.swift | 4 ++-- Sources/App/TerebiApp.swift | 4 ++-- TODO.md | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 940b33a..a482ef9 100644 --- a/README.md +++ b/README.md @@ -207,7 +207,7 @@ The full `make check-startup` rerun passed, including held-key suppression, YouT ## Chromecast -Open media, then choose the **Cast** icon (the Apple TV/AirPlay-style screen-and-triangle symbol) in the playback controls or compact controls, or **Playback → Cast to Device → Find Cast Devices…**. In normal mode it sits left of captions and the compact-mode button, not in the titlebar. Allow macOS Local Network access, then select a discovered Chromecast/Cast-enabled TV on the same LAN. The icon does not add AirPlay support. No Chrome, hosted custom receiver, Google developer registration, or external casting runtime is required. +Open media, then choose the **Cast** icon (the Apple TV/AirPlay-style screen-and-triangle symbol) between pin and settings in the top-right titlebar container, or between exit compact mode and settings in compact controls, or **Playback → Cast to Device → Find Cast Devices…**. Allow macOS Local Network access, then select a discovered Chromecast/Cast-enabled TV on the same LAN. The icon does not add AirPlay support. No Chrome, hosted custom receiver, Google developer registration, or external casting runtime is required. Terebi pauses local output before transferring the acknowledged position and play/pause intent to Google's Default Media Receiver. The existing controls, keyboard shortcuts and macOS media commands control remote playback, seeking, volume/mute and resolved-source subtitles. **Play on This Mac** restores receiver-confirmed position and intent; local volume is preserved independently. Connection/load failures return to local playback with an error. Opening another source ends casting and opens it locally. Frame stepping and YouTube quality changes are local-only; automatic quality is suspended while casting. @@ -273,11 +273,11 @@ The inline URL field, including its placeholder, uses the same 12-point system f With no media open or while casting, the full window uses native behind-window HUD glass with a 35%-opaque brown tint. Static, cached amber/rust radial gradients add ambient color to the empty and casting screens; they disappear during loading or errors, and are never drawn over local video or playback chrome. Glass title/control/error surfaces use the same brown tint with half-point sand outlines. Decorative drawing does not intercept input. The idle or casting Metal surface stays attached but hidden; local playback retains a solid black background and letterboxing without tinting the video. Closing media or starting casting restores the frosted background. macOS controls the material’s appearance, including Reduce Transparency. -In normal mode, the right-hand control group is Cast, captions, then compact mode. The captions selector is omitted when no external subtitle tracks are available; Cast moves next to compact mode without reserving a caption slot. Its native symbol uses a 13-point configuration within a 24-point click target. The native pull-down menu includes a visible Off option and prefers opening above the button; AppKit can reposition it to fit the screen. In compact mode, subtitle selection and Off are available through the settings button's Subtitles submenu; the compact cog uses a 21-point symbol to balance the adjacent icons. The settings menu uses a plain button style so its symbol respects that size and inherits the same cream icon color as the other controls, rather than the orange accent tint. Subtitle glass hugs the text with 16-point horizontal and 12-point vertical internal padding, with the complete container capped at 80% of the window width; longer text wraps within that limit. Its HUD-glass background uses 60% opacity without dimming the text. Visible compact controls raise subtitles by the actual compact control height plus spacing, rather than the normal controller's clearance. Subtitle-load errors remain visible independently of auto-hidden controls. +In normal mode, the right-hand playback control group is captions, then compact mode. The captions selector is omitted when no external subtitle tracks are available, without reserving a caption slot. Its native symbol uses a 13-point configuration within a 24-point click target. The native pull-down menu includes a visible Off option and prefers opening above the button; AppKit can reposition it to fit the screen. In compact mode, subtitle selection and Off are available through the settings button's Subtitles submenu; the compact cog uses a 21-point symbol to balance the adjacent icons. The settings menu uses a plain button style so its symbol respects that size and inherits the same cream icon color as the other controls, rather than the orange accent tint. Subtitle glass hugs the text with 16-point horizontal and 12-point vertical internal padding, with the complete container capped at 80% of the window width; longer text wraps within that limit. Its HUD-glass background uses 60% opacity without dimming the text. Visible compact controls raise subtitles by the actual compact control height plus spacing, rather than the normal controller's clearance. Subtitle-load errors remain visible independently of auto-hidden controls. Accepted relative seeks, including keyboard shortcuts, preserve control visibility instead of revealing hidden chrome. Seek failures still reveal the error; dragging the timeline continues to show the controls. -Normal and compact titlebars have no full-width glass strip or separator: content extends beneath AppKit’s transparent titlebar using `fullSizeContentView`, `titlebarAppearsTransparent`, and `titlebarSeparatorStyle = .none`. Titles retain their rounded HUD-glass backdrop. In normal mode, the pin and settings buttons share a separate container matching the title's 24-point height, horizontal padding, vertical inset, tint, outline and corner radius. Settings sits immediately right of the pin, and both retain 24-point click targets. That button container is not shown in compact mode; only the compact title and adjacent progress occupy the top row with 8-point outer insets. Native traffic lights and window dragging are preserved. +Normal and compact titlebars have no full-width glass strip or separator: content extends beneath AppKit’s transparent titlebar using `fullSizeContentView`, `titlebarAppearsTransparent`, and `titlebarSeparatorStyle = .none`. Titles retain their rounded HUD-glass backdrop. In normal mode, pin, Cast, and settings share a separate container matching the title's 24-point height, horizontal padding, vertical inset, tint, outline and corner radius. Cast sits between pin and settings; all three retain 24-point click targets. That button container is not shown in compact mode; only the compact title and adjacent progress occupy the top row with 8-point outer insets. Native traffic lights and window dragging are preserved. Compact titles default to ` · <position> / <duration> <unit>`, using acknowledged playback position rather than slider previews. Total duration selects the format: below one minute, `12 / 45 s`; from one minute to below one hour, `05:12 / 42:08 m`; from one hour onward, `01:23 / 02:10 h`. Values truncate to the displayed precision. Set `[ui].compact_title_progress = "percentage"` to append only a whole percentage number (`<title> · 59`, without a percent sign), or `"none"` for title-only display. Percentages truncate and stay within 0–100. Loading, failed, live, unknown-duration and closed media have no progress suffix. Normal-mode titles remain unchanged. diff --git a/Sources/App/CastControls.swift b/Sources/App/CastControls.swift index d7b2b44..cdf93d3 100644 --- a/Sources/App/CastControls.swift +++ b/Sources/App/CastControls.swift @@ -32,8 +32,8 @@ struct CastDeviceMenu: View { } label: { if icon { Image(systemName: "airplayvideo") - .font(.system(size: 14)) - .frame(width: 24, height: 24) + .font(.system(size: 15)) + .frame(width: 24, height: 22) } else { Text("Cast to Device") } diff --git a/Sources/App/TerebiApp.swift b/Sources/App/TerebiApp.swift index 23090ec..57693f0 100644 --- a/Sources/App/TerebiApp.swift +++ b/Sources/App/TerebiApp.swift @@ -1805,6 +1805,7 @@ private struct PlayerContent: View { .imageScale(.small) .foregroundStyle(Color(model.isOnTop ? SunsetPalette.accent : SunsetPalette.secondaryText)) .disabled(model.isFullScreen || model.compactWindow.isTransitioning) + CastDeviceMenu(model: model) actionsMenu } .padding(.horizontal, 8) @@ -1870,8 +1871,8 @@ private struct PlayerContent: View { .disabled(!model.canTogglePlayback) iconButton("pip.exit", "Exit Compact Mode", action: model.toggleCompact) .disabled(!model.canToggleCompact) - actionsMenu CastDeviceMenu(model: model) + actionsMenu } if showsBufferReadout { bufferReadout } } @@ -1919,7 +1920,6 @@ private struct PlayerContent: View { } Spacer(minLength: 8) HStack(spacing: 12) { - CastDeviceMenu(model: model) if !model.subtitleTracks.isEmpty { captionsMenu } iconButton("pip.enter", "Enter Compact Mode", action: model.toggleCompact) .disabled(!model.canToggleCompact) diff --git a/TODO.md b/TODO.md index 0985399..043c1eb 100644 --- a/TODO.md +++ b/TODO.md @@ -7,7 +7,7 @@ - [x] fix Miruro Cast upstream overfetch: select HLS streams and share bounded video/audio packet buffering — verify sustained playback on TV - [x] styling/ui changes — implemented; verify layout and casting appearance in the app: - move the captions button in the controls left of the compact mode icon - - move the chrome cast button from the top-right container to the controls left of the captions button (that is, it's new position) + - place the Cast button between pin and settings in the top-right container; in compact mode, between exit compact mode and settings - don't leave and empty spot where the captions were supposed to be if captions aren't available; buttons should be moved over in that case. - the background is currently black in the player when casting (chrome cast), but we should follow the design language of the rest of the app. - replace the current chrome cast icon with the apple tv casting icon.