ui: frost the empty player window background
This commit is contained in:
@@ -188,6 +188,8 @@ The layout follows [IINA's video-first window](https://iina.io/img/screenshot.pn
|
|||||||
|
|
||||||
The empty player uses the same HUD-glass material, 12-point rounded corners, and muted icon/text palette in a centered welcome card. File and YouTube opening actions share a consistently sized row; 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 HUD-glass material, 12-point rounded corners, and muted icon/text palette in a centered welcome card. File and YouTube opening actions share a consistently sized row; the card fits the 400 × 240-point 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 to frost the desktop and windows beneath it. The idle Metal surface stays attached but hidden; opening media restores a solid black background and letterboxing, and closing it restores the frosted background. macOS controls the material’s appearance, including Reduce Transparency.
|
||||||
|
|
||||||
Opening video fits the window to its display aspect ratio, including non-square pixels, and constrains subsequent window resizing. Fullscreen retains the normal letterboxed renderer; audio-only playback and close release the aspect constraint. Extreme ratios that cannot fit both the screen and usable controls keep a freely resizable letterboxed window.
|
Opening video fits the window to its display aspect ratio, including non-square pixels, and constrains subsequent window resizing. Fullscreen retains the normal letterboxed renderer; audio-only playback and close release the aspect constraint. Extreme ratios that cannot fit both the screen and usable controls keep a freely resizable letterboxed window.
|
||||||
|
|
||||||
**Compact mode** uses the same window, Metal view, and playback session—not a second window or macOS system PiP. Use the PiP-shaped button in the normal playback controls, **⌃⌘P**, or **Playback Actions → Enter Compact Mode**. The compact-mode button replaces the fullscreen button; fullscreen remains available through its menu, keyboard shortcuts, and double-clicking normal-mode video. Compact mode starts at the current screen's top-right corner with a 16-point inset and a preferred width of 320 points, preserving display aspect where usable screen bounds and the 160 × 90-point minimum allow; extreme ratios retain letterboxing. Compact mode floats above ordinary windows, joins all Spaces, and is configured to join eligible other-app fullscreen spaces and Stage Manager sets. Small hover controls provide play/pause, restore, and Playback Actions; keyboard playback controls remain available.
|
**Compact mode** uses the same window, Metal view, and playback session—not a second window or macOS system PiP. Use the PiP-shaped button in the normal playback controls, **⌃⌘P**, or **Playback Actions → Enter Compact Mode**. The compact-mode button replaces the fullscreen button; fullscreen remains available through its menu, keyboard shortcuts, and double-clicking normal-mode video. Compact mode starts at the current screen's top-right corner with a 16-point inset and a preferred width of 320 points, preserving display aspect where usable screen bounds and the 160 × 90-point minimum allow; extreme ratios retain letterboxing. Compact mode floats above ordinary windows, joins all Spaces, and is configured to join eligible other-app fullscreen spaces and Stage Manager sets. Small hover controls provide play/pause, restore, and Playback Actions; keyboard playback controls remain available.
|
||||||
|
|||||||
@@ -999,17 +999,20 @@ final class PlayerModel: ObservableObject {
|
|||||||
@MainActor
|
@MainActor
|
||||||
private struct PlayerGlass: NSViewRepresentable {
|
private struct PlayerGlass: NSViewRepresentable {
|
||||||
var titlebar = false
|
var titlebar = false
|
||||||
|
var blendingMode: NSVisualEffectView.BlendingMode = .withinWindow
|
||||||
|
|
||||||
func makeNSView(context: Context) -> NSVisualEffectView {
|
func makeNSView(context: Context) -> NSVisualEffectView {
|
||||||
let view = NSVisualEffectView()
|
let view = NSVisualEffectView()
|
||||||
view.blendingMode = .withinWindow
|
view.blendingMode = blendingMode
|
||||||
view.state = .active
|
view.state = .active
|
||||||
view.appearance = NSAppearance(named: .vibrantDark)
|
view.appearance = NSAppearance(named: .vibrantDark)
|
||||||
view.material = titlebar ? .titlebar : .hudWindow
|
view.material = titlebar ? .titlebar : .hudWindow
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNSView(_ view: NSVisualEffectView, context: Context) {}
|
func updateNSView(_ view: NSVisualEffectView, context: Context) {
|
||||||
|
view.blendingMode = blendingMode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
@@ -1389,10 +1392,17 @@ private struct PlayerContent: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
Color.black
|
if model.fileName == nil {
|
||||||
|
PlayerGlass(blendingMode: .behindWindow)
|
||||||
|
.allowsHitTesting(false)
|
||||||
|
.accessibilityHidden(true)
|
||||||
|
} else {
|
||||||
|
Color.black
|
||||||
|
}
|
||||||
if let view = model.videoView {
|
if let view = model.videoView {
|
||||||
VideoSurface(view: view)
|
VideoSurface(view: view)
|
||||||
.accessibilityLabel("Video")
|
.accessibilityLabel("Video")
|
||||||
|
.opacity(model.fileName == nil ? 0 : 1)
|
||||||
.gesture(
|
.gesture(
|
||||||
TapGesture(count: 2).onEnded { model.toggleFullScreen() }
|
TapGesture(count: 2).onEnded { model.toggleFullScreen() }
|
||||||
.exclusively(before: TapGesture().onEnded { model.hideControls() })
|
.exclusively(before: TapGesture().onEnded { model.hideControls() })
|
||||||
@@ -1607,7 +1617,8 @@ private struct WindowChrome: NSViewRepresentable {
|
|||||||
window.styleMask.insert(.fullSizeContentView)
|
window.styleMask.insert(.fullSizeContentView)
|
||||||
window.titleVisibility = .hidden
|
window.titleVisibility = .hidden
|
||||||
window.titlebarAppearsTransparent = true
|
window.titlebarAppearsTransparent = true
|
||||||
window.backgroundColor = .black
|
window.isOpaque = false
|
||||||
|
window.backgroundColor = .clear
|
||||||
window.acceptsMouseMovedEvents = true
|
window.acceptsMouseMovedEvents = true
|
||||||
window.collectionBehavior.insert(.fullScreenPrimary)
|
window.collectionBehavior.insert(.fullScreenPrimary)
|
||||||
window.appearance = NSAppearance(named: .darkAqua)
|
window.appearance = NSAppearance(named: .darkAqua)
|
||||||
|
|||||||
Reference in New Issue
Block a user