ui: open YouTube URLs inline on the welcome screen

This commit is contained in:
2026-10-12 14:45:02 +02:00
parent 2a75d55c98
commit e3e6a66216
2 changed files with 38 additions and 5 deletions
+1 -1
View File
@@ -186,7 +186,7 @@ Terebi reports facts, not watched status. A consumer such as Tubular decides com
The layout follows [IINA's video-first window](https://iina.io/img/screenshot.png) and the supplied screenshots: a 32-point transparent titlebar with native traffic lights and file icon, plus a frosted 440 × 68-point floating controller. Conjure-inspired **Sunset** styling uses translucent dark-brown glass, warm cream primary text, sand secondary text, and a fixed orange accent for the volume fill, active pin, and drop target. Native slider thumbs and buffered ranges share the palette; warning symbols retain their semantic yellow. Shared vertical padding and an optical offset for symbol/slider insets balance the controller's visible top and bottom margins in both play and pause states. The controller starts centered with a four-percent bottom inset and keeps its relative position when the window changes size. The layout follows [IINA's video-first window](https://iina.io/img/screenshot.png) and the supplied screenshots: a 32-point transparent titlebar with native traffic lights and file icon, plus a frosted 440 × 68-point floating controller. Conjure-inspired **Sunset** styling uses translucent dark-brown glass, warm cream primary text, sand secondary text, and a fixed orange accent for the volume fill, active pin, and drop target. Native slider thumbs and buffered ranges share the palette; warning symbols retain their semantic yellow. Shared vertical padding and an optical offset for symbol/slider insets balance the controller's visible top and bottom margins in both play and pause states. The controller starts centered with a four-percent bottom inset and keeps its relative position when the window changes size.
The empty player uses the same tinted HUD-glass material, faint warm outlines, 12-point rounded corners, and Sunset palette in a centered welcome card. File and YouTube opening actions share a consistently sized row with a subtle orange fill; the card fits the 400 × 240-point minimum window, and the full window still accepts media-file and YouTube-link drops. The empty player uses the same tinted HUD-glass material, faint warm outlines, 12-point rounded corners, and Sunset palette in a centered welcome card. File and YouTube opening actions are separate, equally sized buttons with a 10-point gap and subtle orange fills. The YouTube button reveals and focuses an inline URL field below the buttons, spanning their combined width including the gap; Return or the arrow button submits through the existing YouTube URL validation. Other URL-opening entry points retain their dialog. The card fits the minimum window, and the full window still accepts media-file and YouTube-link drops.
With no media open, the full window uses native behind-window HUD glass with a 35%-opaque brown tint. Static, cached amber/rust radial gradients add ambient color only to the empty screen; they disappear during loading or errors, and are never drawn over 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 Metal surface stays attached but hidden; opening media restores a solid black background and letterboxing without tinting the video, and closing it restores the ambient frosted background. macOS controls the material’s appearance, including Reduce Transparency. With no media open, the full window uses native behind-window HUD glass with a 35%-opaque brown tint. Static, cached amber/rust radial gradients add ambient color only to the empty screen; they disappear during loading or errors, and are never drawn over 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 Metal surface stays attached but hidden; opening media restores a solid black background and letterboxing without tinting the video, and closing it restores the ambient frosted background. macOS controls the material’s appearance, including Reduce Transparency.
+36 -3
View File
@@ -1257,6 +1257,9 @@ private struct PlayerContent: View {
@Environment(\.accessibilityReduceMotion) private var reduceMotion @Environment(\.accessibilityReduceMotion) private var reduceMotion
@State private var showsRemainingTime = false @State private var showsRemainingTime = false
@State private var dropTargeted = false @State private var dropTargeted = false
@State private var showsYouTubeInput = false
@State private var youTubeURL = ""
@FocusState private var youTubeInputFocused: Bool
@State private var controlSize = CGSize(width: 440, height: 68) @State private var controlSize = CGSize(width: 440, height: 68)
// Relative offsets preserve the dragged position across resize/fullscreen. // Relative offsets preserve the dragged position across resize/fullscreen.
@State private var controlOffset = CGSize.zero @State private var controlOffset = CGSize.zero
@@ -1541,26 +1544,56 @@ private struct PlayerContent: View {
} }
Spacer(minLength: 0) Spacer(minLength: 0)
} }
HStack(spacing: 0) { HStack(spacing: 10) {
Button(action: model.openPanel) { Button(action: model.openPanel) {
Label("Open File…", systemImage: "doc") Label("Open File…", systemImage: "doc")
.frame(maxWidth: .infinity, minHeight: 40) .frame(maxWidth: .infinity, minHeight: 40)
.contentShape(Rectangle()) .contentShape(Rectangle())
} }
Divider().frame(height: 20).accessibilityHidden(true) .background(Color(SunsetPalette.actionFill), in: RoundedRectangle(cornerRadius: 8))
Button(action: model.openYouTubePanel) { Button {
showsYouTubeInput = true
youTubeInputFocused = true
} label: {
Label("YouTube URL…", systemImage: "link") Label("YouTube URL…", systemImage: "link")
.frame(maxWidth: .infinity, minHeight: 40) .frame(maxWidth: .infinity, minHeight: 40)
.contentShape(Rectangle()) .contentShape(Rectangle())
} }
.accessibilityLabel("Open YouTube URL…") .accessibilityLabel("Open YouTube URL…")
.background(Color(SunsetPalette.actionFill), in: RoundedRectangle(cornerRadius: 8))
} }
.font(.system(size: 13, weight: .medium)) .font(.system(size: 13, weight: .medium))
.foregroundStyle(Color(SunsetPalette.text)) .foregroundStyle(Color(SunsetPalette.text))
.imageScale(.large) .imageScale(.large)
.buttonStyle(.plain) .buttonStyle(.plain)
.disabled(!model.canOpen) .disabled(!model.canOpen)
if showsYouTubeInput {
HStack(spacing: 8) {
TextField("YouTube video URL", text: $youTubeURL)
.textFieldStyle(.plain)
.focused($youTubeInputFocused)
.accessibilityLabel("YouTube video URL")
.onAppear { youTubeInputFocused = true }
.onSubmit { model.openYouTube(youTubeURL) }
Button {
model.openYouTube(youTubeURL)
} label: {
Image(systemName: "arrow.right")
.frame(width: 24, height: 24)
.contentShape(Rectangle())
}
.buttonStyle(.plain)
.accessibilityLabel("Open YouTube Video")
.help("Open YouTube Video")
.disabled(youTubeURL.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
}
.font(.system(size: 13))
.foregroundStyle(Color(SunsetPalette.text))
.padding(.horizontal, 12)
.frame(height: 40)
.background(Color(SunsetPalette.actionFill), in: RoundedRectangle(cornerRadius: 8)) .background(Color(SunsetPalette.actionFill), in: RoundedRectangle(cornerRadius: 8))
.disabled(!model.canOpen)
}
Text("Drop a media file or YouTube link here") Text("Drop a media file or YouTube link here")
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundStyle(Color(SunsetPalette.secondaryText)) .foregroundStyle(Color(SunsetPalette.secondaryText))