mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 05:02:53 +00:00
Keep the landscape panel hidden where the corner layout doesn't fit
The corner preset's landscape fallback opened the panel whenever the device could host the corner layout. On the iPhone Duo exterior display the player falls back to the widescreen layout, so the floating panel opened on every rotation into landscape. Resolve the fallback from whether the corner layout fits the current size instead.
This commit is contained in:
@@ -500,12 +500,20 @@ struct PanelSettings: Codable, Hashable, Sendable {
|
||||
/// landscape in the corner layout on a device that can show it, where the
|
||||
/// panels are the point of the layout and open visible.
|
||||
func effectiveDefaultVisibility(for orientation: PanelOrientation) -> PanelDefaultVisibility {
|
||||
effectiveDefaultVisibility(for: orientation, cornerLayoutFits: Self.canHostCornerLayout)
|
||||
}
|
||||
|
||||
/// Same as `effectiveDefaultVisibility(for:)`, but the corner fallback
|
||||
/// follows whether the corner layout fits the current screen — the iPhone
|
||||
/// Duo exterior display can't host it and falls back to the floating
|
||||
/// widescreen panel, which must not open by default.
|
||||
func effectiveDefaultVisibility(for orientation: PanelOrientation, cornerLayoutFits: Bool) -> PanelDefaultVisibility {
|
||||
switch orientation {
|
||||
case .portrait:
|
||||
return portraitDefaultVisibility ?? defaultVisibility ?? .visible
|
||||
case .landscape:
|
||||
let fallback: PanelDefaultVisibility =
|
||||
effectiveLayoutMode == .corner && Self.canHostCornerLayout ? .visible : .hidden
|
||||
effectiveLayoutMode == .corner && cornerLayoutFits ? .visible : .hidden
|
||||
return landscapeDefaultVisibility ?? defaultVisibility ?? fallback
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ final class NavigationCoordinator {
|
||||
if !isPlayerExpanded {
|
||||
hasAppliedPanelDefaultVisibility = false
|
||||
isCornerLayoutActive = false
|
||||
cornerLayoutFits = false
|
||||
isWideScreenLayoutActive = false
|
||||
}
|
||||
}
|
||||
@@ -66,6 +67,11 @@ final class NavigationCoordinator {
|
||||
/// different view than the layout resolver.
|
||||
var isCornerLayoutActive = false
|
||||
|
||||
/// Whether the expanded player's current size fits the corner layout,
|
||||
/// regardless of the preset's layout mode. Lets the async preset load
|
||||
/// resolve the landscape panel default for the screen actually in use.
|
||||
var cornerLayoutFits = false
|
||||
|
||||
/// Whether the expanded player currently resolves to the widescreen
|
||||
/// (landscape) layout. Set from the sheet's layout pass so non-view code
|
||||
/// (remote control state) reads the real layout instead of screen bounds.
|
||||
|
||||
@@ -90,11 +90,17 @@ extension ExpandedPlayerSheet {
|
||||
/// `size` must include the safe areas so the status bar toggling with the
|
||||
/// layout can't feed back into the decision.
|
||||
func isCornerLayout(size: CGSize) -> Bool {
|
||||
playerControlsLayout.effectivePanelSettings.effectiveLayoutMode == .corner
|
||||
&& cornerLayoutFits(size: size)
|
||||
}
|
||||
|
||||
/// The size half of `isCornerLayout(size:)`, independent of the preset's
|
||||
/// layout mode.
|
||||
func cornerLayoutFits(size: CGSize) -> Bool {
|
||||
#if os(iOS)
|
||||
guard size.height >= Self.minHeightForCornerLayout else { return false }
|
||||
#endif
|
||||
return playerControlsLayout.effectivePanelSettings.effectiveLayoutMode == .corner
|
||||
&& size.width >= Self.minWidthForCornerLayout
|
||||
return size.width >= Self.minWidthForCornerLayout
|
||||
&& isWideScreenLayout(size: size)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -329,10 +329,14 @@ struct ExpandedPlayerSheet: View {
|
||||
// Gate on the full size including safe areas: the corner layout
|
||||
// shows the status bar, which would otherwise shrink the measured
|
||||
// height and flip the decision back (layout oscillation).
|
||||
let cornerActive = isCornerLayout(size: CGSize(
|
||||
let fullSize = CGSize(
|
||||
width: geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing,
|
||||
height: geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom
|
||||
))
|
||||
)
|
||||
let cornerActive = isCornerLayout(size: fullSize)
|
||||
let cornerFits = cornerLayoutFits(size: fullSize)
|
||||
#else
|
||||
let cornerFits = false
|
||||
#endif
|
||||
|
||||
ZStack(alignment: .top) {
|
||||
@@ -397,6 +401,9 @@ struct ExpandedPlayerSheet: View {
|
||||
.onChange(of: cornerActive) { _, newValue in
|
||||
navigationCoordinator?.isCornerLayoutActive = newValue
|
||||
}
|
||||
.onChange(of: cornerFits, initial: true) { _, newValue in
|
||||
navigationCoordinator?.cornerLayoutFits = newValue
|
||||
}
|
||||
#endif
|
||||
.onChange(of: wideScreen, initial: true) { _, newValue in
|
||||
navigationCoordinator?.isWideScreenLayoutActive = newValue
|
||||
@@ -422,6 +429,7 @@ struct ExpandedPlayerSheet: View {
|
||||
// Entering landscape: apply the preset's default
|
||||
applyPanelDefaultVisibility(
|
||||
playerControlsLayout.effectivePanelSettings,
|
||||
cornerLayoutFits: cornerFits,
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
// Portrait panel doesn't exist in wide layout - clear flag so gesture handler allows pinch
|
||||
@@ -450,6 +458,7 @@ struct ExpandedPlayerSheet: View {
|
||||
if navigationCoordinator?.hasAppliedPanelDefaultVisibility != true {
|
||||
let visible = applyPanelDefaultVisibility(
|
||||
PanelSettings.cached,
|
||||
cornerLayoutFits: cornerFits,
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
#if os(iOS) || os(macOS)
|
||||
@@ -760,6 +769,7 @@ private struct PlayerEventHandlersModifier: ViewModifier {
|
||||
if navigationCoordinator?.hasAppliedPanelDefaultVisibility != true {
|
||||
let visible = applyPanelDefaultVisibility(
|
||||
layout.effectivePanelSettings,
|
||||
cornerLayoutFits: navigationCoordinator?.cornerLayoutFits ?? PanelSettings.canHostCornerLayout,
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
#if os(iOS) || os(macOS)
|
||||
@@ -786,10 +796,14 @@ private struct PlayerEventHandlersModifier: ViewModifier {
|
||||
/// state, which lives in view @State rather than settings.
|
||||
@MainActor
|
||||
@discardableResult
|
||||
private func applyPanelDefaultVisibility(_ settings: PanelSettings, settingsManager: SettingsManager?) -> Bool {
|
||||
private func applyPanelDefaultVisibility(
|
||||
_ settings: PanelSettings,
|
||||
cornerLayoutFits: Bool,
|
||||
settingsManager: SettingsManager?
|
||||
) -> Bool {
|
||||
guard let settingsManager else { return true }
|
||||
settingsManager.landscapeDetailsPanelVisible = settings
|
||||
.effectiveDefaultVisibility(for: .landscape)
|
||||
.effectiveDefaultVisibility(for: .landscape, cornerLayoutFits: cornerLayoutFits)
|
||||
.resolve(lastVisible: settingsManager.landscapeDetailsPanelLastVisible)
|
||||
return settings
|
||||
.effectiveDefaultVisibility(for: .portrait)
|
||||
|
||||
Reference in New Issue
Block a user