mirror of
https://github.com/yattee/yattee.git
synced 2026-10-29 16:07:20 +00:00
Fix player brightness controls on iPhone Duo
Brightness controls used UIScreen.main, which on iPhone Duo can be a different display than the one hosting the player. Route all brightness reads and writes through PlayerBrightness, which targets the screen of the window hosting the controls.
This commit is contained in:
@@ -460,7 +460,7 @@ struct ControlsSectionRenderer: View {
|
||||
|
||||
/// Brightness icon image using variable value SF Symbol.
|
||||
private var brightnessImage: Image {
|
||||
Image(systemName: "sun.max.fill", variableValue: UIScreen.main.brightness)
|
||||
Image(systemName: "sun.max.fill", variableValue: PlayerBrightness.value(for: actions.screen))
|
||||
}
|
||||
|
||||
/// Panel toggle button content with glass background support.
|
||||
@@ -796,9 +796,9 @@ struct ControlsSectionRenderer: View {
|
||||
if effectiveBehavior == .alwaysVisible || isBrightnessExpanded {
|
||||
Slider(
|
||||
value: Binding(
|
||||
get: { UIScreen.main.brightness },
|
||||
get: { PlayerBrightness.value(for: actions.screen) },
|
||||
set: { newValue in
|
||||
UIScreen.main.brightness = newValue
|
||||
PlayerBrightness.set(newValue, for: actions.screen)
|
||||
}
|
||||
),
|
||||
in: 0...1,
|
||||
|
||||
36
Yattee/Views/Player/PlayerBrightness.swift
Normal file
36
Yattee/Views/Player/PlayerBrightness.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// PlayerBrightness.swift
|
||||
// Yattee
|
||||
//
|
||||
// Screen brightness for the player's brightness controls. On iPhone Duo the
|
||||
// interior and exterior are separate screens, so `UIScreen.main` can name a
|
||||
// display other than the one the player is on: brightness must go to the
|
||||
// screen of the window hosting the controls.
|
||||
//
|
||||
|
||||
#if os(iOS)
|
||||
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
enum PlayerBrightness {
|
||||
/// The screen to control: the host window's screen, else the foreground
|
||||
/// scene's, else `UIScreen.main`.
|
||||
static func screen(for hostScreen: UIScreen?) -> UIScreen {
|
||||
if let hostScreen { return hostScreen }
|
||||
let activeScene = UIApplication.shared.connectedScenes
|
||||
.compactMap { $0 as? UIWindowScene }
|
||||
.first { $0.activationState == .foregroundActive }
|
||||
return activeScene?.screen ?? UIScreen.main
|
||||
}
|
||||
|
||||
static func value(for hostScreen: UIScreen?) -> Double {
|
||||
screen(for: hostScreen).brightness
|
||||
}
|
||||
|
||||
static func set(_ value: Double, for hostScreen: UIScreen?) {
|
||||
screen(for: hostScreen).brightness = value
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -57,6 +57,10 @@ struct PlayerControlsActions {
|
||||
/// behavior (details toggle, no rotate glyph, no orientation lock).
|
||||
var canRotate: Bool = true
|
||||
|
||||
/// Screen of the window hosting the controls; brightness targets it
|
||||
/// (iPhone Duo interior and exterior are separate screens).
|
||||
var screen: UIScreen?
|
||||
|
||||
/// iPad, or an iPhone windowing mode that can't rotate on request.
|
||||
var usesRotationFreeFullscreen: Bool { isIPad || !canRotate }
|
||||
|
||||
|
||||
@@ -137,8 +137,8 @@ struct PlayerControlsView: View {
|
||||
@State private var targetSeekProgress: Double = 0
|
||||
@State private var hideTimer: Timer?
|
||||
@State private var showControls: Bool?
|
||||
/// Tracks brightness value for side slider (needed because UIScreen.main.brightness isn't observable)
|
||||
@State private var currentBrightness: Double = UIScreen.main.brightness
|
||||
/// Tracks brightness value for side slider (needed because UIScreen.brightness isn't observable)
|
||||
@State private var currentBrightness: Double = PlayerBrightness.value(for: nil)
|
||||
/// Track safe area to force re-render when it changes
|
||||
@State private var currentSafeArea: UIEdgeInsets = .zero
|
||||
/// Window hosting these controls, captured by `HostWindowReader`. Safe
|
||||
@@ -146,6 +146,7 @@ struct PlayerControlsView: View {
|
||||
/// display's window (iPhone Duo exterior with its 84pt status bar inset
|
||||
/// while the player sits on the interior in Split View).
|
||||
@State private var hostWindow: UIWindow?
|
||||
private var hostScreen: UIScreen? { hostWindow?.windowScene?.screen }
|
||||
@Environment(\.statusBarVisibilityController) private var statusBarController
|
||||
/// Active player controls layout from preset (passed from parent to avoid flashing during view recreation)
|
||||
var activeLayout: PlayerControlsLayout = .default
|
||||
@@ -272,6 +273,7 @@ struct PlayerControlsView: View {
|
||||
guard window !== hostWindow else { return }
|
||||
hostWindow = window
|
||||
currentSafeArea = windowSafeArea
|
||||
currentBrightness = PlayerBrightness.value(for: hostScreen)
|
||||
})
|
||||
.onAppear {
|
||||
// Update safe area on appear to ensure correct layout
|
||||
@@ -300,7 +302,7 @@ struct PlayerControlsView: View {
|
||||
appEnvironment?.navigationCoordinator.shouldSnapPanscan = newValue
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIScreen.brightnessDidChangeNotification)) { _ in
|
||||
currentBrightness = UIScreen.main.brightness
|
||||
currentBrightness = PlayerBrightness.value(for: hostScreen)
|
||||
}
|
||||
.sheet(isPresented: $showingCaptionsSheet) {
|
||||
captionsSheet
|
||||
@@ -429,6 +431,7 @@ struct PlayerControlsView: View {
|
||||
panelSide: panelSide,
|
||||
isIPad: isIPad,
|
||||
canRotate: OrientationManager.shared.canRotateProgrammatically,
|
||||
screen: hostWindow?.windowScene?.screen,
|
||||
showVolumeControls: showVolumeControls,
|
||||
showDebugButton: onToggleDebug != nil,
|
||||
showCloseButton: onClose != nil,
|
||||
@@ -1585,7 +1588,7 @@ struct PlayerControlsView: View {
|
||||
/// Always goes to the next higher preset from current position, wrapping from 100 to 0.
|
||||
private func cycleBrightnessPreset() {
|
||||
let presets: [Double] = [0.0, 0.25, 0.5, 0.75, 1.0]
|
||||
let current = UIScreen.main.brightness
|
||||
let current = PlayerBrightness.value(for: hostScreen)
|
||||
|
||||
// Find next higher preset (with small tolerance for floating point)
|
||||
let newValue: Double
|
||||
@@ -1596,7 +1599,7 @@ struct PlayerControlsView: View {
|
||||
newValue = 0.0
|
||||
}
|
||||
|
||||
UIScreen.main.brightness = newValue
|
||||
PlayerBrightness.set(newValue, for: hostScreen)
|
||||
currentBrightness = newValue
|
||||
}
|
||||
|
||||
@@ -1632,7 +1635,7 @@ struct PlayerControlsView: View {
|
||||
value: Binding(
|
||||
get: { currentBrightness },
|
||||
set: { newValue in
|
||||
UIScreen.main.brightness = newValue
|
||||
PlayerBrightness.set(newValue, for: hostScreen)
|
||||
currentBrightness = newValue
|
||||
}
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user