Fix clipped top controls and stale top padding in corner fullscreen

The fullscreen video layer extends up into the status bar strip and is
shifted with an offset; `.clipped()` came after the offset, so it clipped
to the unshifted frame and cut the top strip (title row, avatar) off. Clip
before the offset instead.

The player controls read the main window's safe area only on geometry
changes. With the corner layout keeping its geometry fixed across the
status bar hide, the value went stale and the controls kept the status bar
height as top padding in fullscreen. Refresh it when the status bar
visibility changes, with a few delayed re-reads to cover the fade.
This commit is contained in:
Arkadiusz Fal
2026-09-25 09:05:12 +02:00
parent 95124d87bb
commit f4204105eb
2 changed files with 18 additions and 1 deletions

View File

@@ -141,6 +141,7 @@ struct PlayerControlsView: View {
@State private var playNextTapCount = 0
/// Track safe area to force re-render when it changes
@State private var currentSafeArea: UIEdgeInsets = .zero
@Environment(\.statusBarVisibilityController) private var statusBarController
/// Active player controls layout from preset (passed from parent to avoid flashing during view recreation)
var activeLayout: PlayerControlsLayout = .default
/// Animation trigger for seek backward button
@@ -268,6 +269,18 @@ struct PlayerControlsView: View {
// Update safe area when geometry changes (rotation)
currentSafeArea = windowSafeArea
}
.onChange(of: statusBarController?.isHidden) { _, _ in
// The window safe area follows the status bar fade with a delay.
// Corner layout keeps its geometry fixed across the toggle, so
// no geometry change refreshes the value — poll a few times
// instead of keeping a stale status bar height as top padding.
currentSafeArea = windowSafeArea
for delay in [0.15, 0.4, 0.8] {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
currentSafeArea = windowSafeArea
}
}
}
.onChange(of: activeLayout.effectiveGesturesSettings.panscanGesture.snapToEnds, initial: true) { _, newValue in
// Sync panscan snap setting to navigation coordinator (initial: true ensures sync on first render)
appEnvironment?.navigationCoordinator.shouldSnapPanscan = newValue