mirror of
https://github.com/yattee/yattee.git
synced 2026-10-23 13:12:53 +00:00
Apply panel default visibility to portrait panel without position jump
The preset's When Player Opens setting only drove the landscape/floating panel state, so on iPhone in portrait the details panel reappeared on every player expansion regardless of the setting. Mirror the resolved visibility into the portrait panel state, and seed it into the sheet's initial state at all creation sites so the first frame already renders the correct layout - applying it in onAppear animated a visible top-to-center video jump during expansion. Portrait panel toggles now also persist the last visibility so Remember Last works there too.
This commit is contained in:
@@ -64,7 +64,11 @@ struct ContentView: View {
|
||||
if isInlinePlayerOverlayActive(appEnvironment: appEnvironment) {
|
||||
ZStack {
|
||||
Color.black
|
||||
ExpandedPlayerSheet()
|
||||
ExpandedPlayerSheet(
|
||||
initialPortraitPanelVisible: ExpandedPlayerSheet.initialPortraitPanelVisibility(
|
||||
settingsManager: appEnvironment.settingsManager
|
||||
)
|
||||
)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
.transition(.opacity)
|
||||
|
||||
@@ -385,6 +385,7 @@ extension ExpandedPlayerSheet {
|
||||
panelRevealOffset = 0
|
||||
isPortraitPanelVisible = true
|
||||
navigationCoordinator?.isPortraitPanelVisible = true
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = true
|
||||
// Match video position from reveal formula
|
||||
let revealProgress = min(1.0, -currentRevealOffset / pinnedPanelHeight)
|
||||
let maxVideoOffset = centerY - topY
|
||||
@@ -508,6 +509,7 @@ extension ExpandedPlayerSheet {
|
||||
withTransaction(transaction) {
|
||||
isPortraitPanelVisible = false
|
||||
navigationCoordinator?.isPortraitPanelVisible = false
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = false
|
||||
isCommentsExpanded = false
|
||||
navigationCoordinator?.isCommentsExpanded = false
|
||||
navigationCoordinator?.commentsFrame = .zero
|
||||
@@ -648,6 +650,7 @@ extension ExpandedPlayerSheet {
|
||||
isPortraitPanelVisible = newValue
|
||||
}
|
||||
navigationCoordinator?.isPortraitPanelVisible = newValue
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = newValue
|
||||
}
|
||||
|
||||
/// Hide floating panel with animation
|
||||
@@ -656,6 +659,7 @@ extension ExpandedPlayerSheet {
|
||||
isPortraitPanelVisible = false
|
||||
}
|
||||
navigationCoordinator?.isPortraitPanelVisible = false
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = false
|
||||
|
||||
// Reset main window transform when hiding panel to fix safe area clipping (iOS only)
|
||||
#if os(iOS)
|
||||
@@ -853,6 +857,7 @@ extension ExpandedPlayerSheet {
|
||||
isPortraitPanelVisible.toggle()
|
||||
}
|
||||
navigationCoordinator?.isPortraitPanelVisible = isPortraitPanelVisible
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = isPortraitPanelVisible
|
||||
},
|
||||
onShowSettings: { [self] in
|
||||
showingQualitySheet = true
|
||||
@@ -1125,6 +1130,7 @@ extension ExpandedPlayerSheet {
|
||||
isPortraitPanelVisible.toggle()
|
||||
}
|
||||
navigationCoordinator?.isPortraitPanelVisible = isPortraitPanelVisible
|
||||
appEnvironment?.settingsManager.detailsPanelLastVisible = isPortraitPanelVisible
|
||||
// Re-enable controls after animation completes (0.35s)
|
||||
// Controls will still be hidden (forceInitialHidden) until user taps
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
|
||||
|
||||
@@ -35,6 +35,26 @@ struct ExpandedPlayerSheet: View {
|
||||
/// Temporarily hide controls during fullscreen transition to avoid animation glitch
|
||||
@State var hideControlsDuringTransition: Bool = false
|
||||
|
||||
/// Resolves the preset's default panel visibility for the portrait panel
|
||||
/// from the cached settings, so creators of this view can seed the initial
|
||||
/// state BEFORE the first frame — applying it in onAppear animates a
|
||||
/// visible top-to-center video jump during player expansion.
|
||||
@MainActor
|
||||
static func initialPortraitPanelVisibility(settingsManager: SettingsManager?) -> Bool {
|
||||
switch PanelSettings.cached.effectiveDefaultVisibility {
|
||||
case .hidden:
|
||||
return false
|
||||
case .visible:
|
||||
return true
|
||||
case .remember:
|
||||
return settingsManager?.detailsPanelLastVisible ?? false
|
||||
}
|
||||
}
|
||||
|
||||
init(initialPortraitPanelVisible: Bool = true) {
|
||||
_isPortraitPanelVisible = State(initialValue: initialPortraitPanelVisible)
|
||||
}
|
||||
|
||||
// MARK: - Panel Drag State
|
||||
|
||||
/// Current drag offset when dismissing panel (positive = dragging down)
|
||||
@@ -194,6 +214,8 @@ struct ExpandedPlayerSheet: View {
|
||||
isAutoplayCancelled: $isAutoplayCancelled,
|
||||
pendingScrollToTopOnHeightChange: $pendingScrollToTopOnHeightChange,
|
||||
playerControlsLayout: $playerControlsLayout,
|
||||
isPortraitPanelVisible: $isPortraitPanelVisible,
|
||||
isInWideScreenLayout: isInWideScreenLayout,
|
||||
stopAutoplayCountdown: stopAutoplayCountdown,
|
||||
startAutoplayCountdown: startAutoplayCountdown,
|
||||
startPreloadingComments: startPreloadingComments,
|
||||
@@ -399,10 +421,23 @@ struct ExpandedPlayerSheet: View {
|
||||
// state from a previous session). Uses the cached settings;
|
||||
// loadPlayerControlsLayout re-applies the authoritative value.
|
||||
if navigationCoordinator?.hasAppliedPanelDefaultVisibility != true {
|
||||
applyPanelDefaultVisibility(
|
||||
let visible = applyPanelDefaultVisibility(
|
||||
PanelSettings.cached,
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
#if os(iOS) || os(macOS)
|
||||
LoggingService.shared.logPlayer("[ExpandedPlayerSheet] onAppear provisional apply: visible=\(visible), state=\(isPortraitPanelVisible), wideScreen=\(wideScreen)")
|
||||
// No animation: this is the opening state, not a user
|
||||
// toggle — animating it here slides the video mid-expand.
|
||||
var transaction = Transaction()
|
||||
transaction.disablesAnimations = true
|
||||
withTransaction(transaction) {
|
||||
isPortraitPanelVisible = visible
|
||||
}
|
||||
if !wideScreen {
|
||||
navigationCoordinator?.isPortraitPanelVisible = visible
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -794,6 +829,8 @@ private struct PlayerEventHandlersModifier: ViewModifier {
|
||||
@Binding var isAutoplayCancelled: Bool
|
||||
@Binding var pendingScrollToTopOnHeightChange: Bool
|
||||
@Binding var playerControlsLayout: PlayerControlsLayout
|
||||
@Binding var isPortraitPanelVisible: Bool
|
||||
let isInWideScreenLayout: Bool
|
||||
|
||||
let stopAutoplayCountdown: () -> Void
|
||||
let startAutoplayCountdown: () -> Void
|
||||
@@ -914,10 +951,21 @@ private struct PlayerEventHandlersModifier: ViewModifier {
|
||||
// Apply the preset's default panel visibility once per expanded
|
||||
// player session, now that the authoritative settings are loaded.
|
||||
if navigationCoordinator?.hasAppliedPanelDefaultVisibility != true {
|
||||
applyPanelDefaultVisibility(
|
||||
let visible = applyPanelDefaultVisibility(
|
||||
layout.effectivePanelSettings,
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
#if os(iOS) || os(macOS)
|
||||
LoggingService.shared.logPlayer("[ExpandedPlayerSheet] authoritative apply: visible=\(visible), state=\(isPortraitPanelVisible), wideScreen=\(isInWideScreenLayout)")
|
||||
var transaction = Transaction()
|
||||
transaction.disablesAnimations = true
|
||||
withTransaction(transaction) {
|
||||
isPortraitPanelVisible = visible
|
||||
}
|
||||
if !isInWideScreenLayout {
|
||||
navigationCoordinator?.isPortraitPanelVisible = visible
|
||||
}
|
||||
#endif
|
||||
navigationCoordinator?.hasAppliedPanelDefaultVisibility = true
|
||||
}
|
||||
}
|
||||
@@ -926,18 +974,25 @@ private struct PlayerEventHandlersModifier: ViewModifier {
|
||||
|
||||
/// Applies the preset's default details panel visibility for a fresh
|
||||
/// panel mount. "Hidden" mirrors the historical reset (unpinned too);
|
||||
/// the other modes leave the pinned state as persisted.
|
||||
/// the other modes leave the pinned state as persisted. Returns the
|
||||
/// resolved visibility so callers can mirror it into the portrait
|
||||
/// panel state, which lives in view @State rather than settings.
|
||||
@MainActor
|
||||
private func applyPanelDefaultVisibility(_ settings: PanelSettings, settingsManager: SettingsManager?) {
|
||||
guard let settingsManager else { return }
|
||||
@discardableResult
|
||||
private func applyPanelDefaultVisibility(_ settings: PanelSettings, settingsManager: SettingsManager?) -> Bool {
|
||||
guard let settingsManager else { return true }
|
||||
switch settings.effectiveDefaultVisibility {
|
||||
case .hidden:
|
||||
settingsManager.landscapeDetailsPanelVisible = false
|
||||
settingsManager.landscapeDetailsPanelPinned = false
|
||||
return false
|
||||
case .visible:
|
||||
settingsManager.landscapeDetailsPanelVisible = true
|
||||
return true
|
||||
case .remember:
|
||||
settingsManager.landscapeDetailsPanelVisible = settingsManager.detailsPanelLastVisible
|
||||
let lastVisible = settingsManager.detailsPanelLastVisible
|
||||
settingsManager.landscapeDetailsPanelVisible = lastVisible
|
||||
return lastVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -769,7 +769,13 @@ final class ExpandedPlayerWindowManager {
|
||||
let statusBarController = StatusBarVisibilityController()
|
||||
|
||||
// Create the expanded player view with status bar controller in environment
|
||||
let expandedView = ExpandedPlayerSheet()
|
||||
// Seed the portrait panel state before the first frame so the preset's
|
||||
// default visibility doesn't animate a video position jump on expand.
|
||||
let initialPanelVisible = ExpandedPlayerSheet.initialPortraitPanelVisibility(
|
||||
settingsManager: appEnvironment.settingsManager
|
||||
)
|
||||
LoggingService.shared.logPlayer("[ExpandedPlayerWindowManager] show: initialPortraitPanelVisible=\(initialPanelVisible), defaultVisibility=\(PanelSettings.cached.effectiveDefaultVisibility)")
|
||||
let expandedView = ExpandedPlayerSheet(initialPortraitPanelVisible: initialPanelVisible)
|
||||
.appEnvironment(appEnvironment)
|
||||
.environment(\.statusBarVisibilityController, statusBarController)
|
||||
|
||||
|
||||
@@ -850,6 +850,7 @@ extension ExpandedPlayerWindowManager: NSWindowDelegate {
|
||||
/// its player window renders, and removes the perceptible "dead gap" between the
|
||||
/// click and the window appearing.
|
||||
private struct ExpandedPlayerWindowRoot: View {
|
||||
@Environment(\.appEnvironment) private var appEnvironment
|
||||
@State private var showFullPlayer = false
|
||||
|
||||
var body: some View {
|
||||
@@ -859,7 +860,11 @@ private struct ExpandedPlayerWindowRoot: View {
|
||||
Color.black
|
||||
|
||||
if showFullPlayer {
|
||||
ExpandedPlayerSheet()
|
||||
ExpandedPlayerSheet(
|
||||
initialPortraitPanelVisible: ExpandedPlayerSheet.initialPortraitPanelVisibility(
|
||||
settingsManager: appEnvironment?.settingsManager
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ProgressView()
|
||||
.controlSize(.large)
|
||||
|
||||
Reference in New Issue
Block a user