Bladeren bron

Fix header clipping in full screen with hidden title bar.

Add fullscreen-only top inset so sidebar and content headers stay visible without changing windowed layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 maand geleden
bovenliggende
commit
87d6ac4202

+ 3 - 0
Reddit App/Utilities/AppWindow.swift

@@ -5,4 +5,7 @@ enum AppWindow {
     static let height: CGFloat = 720
     static let minWidth: CGFloat = width
     static let minHeight: CGFloat = height
+
+    /// Extra top inset when the window is in macOS full screen (hidden title bar has no safe area there).
+    static let fullScreenTopInset: CGFloat = 28
 }

+ 109 - 0
Reddit App/Views/Components/WindowFullScreenObserver.swift

@@ -0,0 +1,109 @@
+import AppKit
+import SwiftUI
+
+struct WindowFullScreenObserver: NSViewRepresentable {
+    @Binding var isFullScreen: Bool
+
+    func makeCoordinator() -> Coordinator {
+        Coordinator(isFullScreen: $isFullScreen)
+    }
+
+    func makeNSView(context: Context) -> WindowObservationView {
+        let view = WindowObservationView()
+        view.onWindowChange = { [weak coordinator = context.coordinator] window in
+            coordinator?.observe(window: window)
+        }
+        return view
+    }
+
+    func updateNSView(_ nsView: WindowObservationView, context: Context) {
+        context.coordinator.observe(window: nsView.window)
+    }
+
+    final class Coordinator {
+        @Binding private var isFullScreen: Bool
+        private var observers: [NSObjectProtocol] = []
+        private weak var observedWindow: NSWindow?
+
+        init(isFullScreen: Binding<Bool>) {
+            _isFullScreen = isFullScreen
+        }
+
+        func observe(window: NSWindow?) {
+            guard window !== observedWindow else {
+                if let window {
+                    updateFullScreenState(for: window)
+                }
+                return
+            }
+
+            removeObservers()
+            observedWindow = window
+
+            guard let window else {
+                isFullScreen = false
+                return
+            }
+
+            updateFullScreenState(for: window)
+
+            let center = NotificationCenter.default
+            observers = [
+                center.addObserver(
+                    forName: NSWindow.didEnterFullScreenNotification,
+                    object: window,
+                    queue: .main
+                ) { [weak self] _ in
+                    self?.updateFullScreenState(for: window)
+                },
+                center.addObserver(
+                    forName: NSWindow.didExitFullScreenNotification,
+                    object: window,
+                    queue: .main
+                ) { [weak self] _ in
+                    self?.updateFullScreenState(for: window)
+                },
+            ]
+        }
+
+        private func updateFullScreenState(for window: NSWindow) {
+            isFullScreen = window.styleMask.contains(.fullScreen)
+        }
+
+        private func removeObservers() {
+            observers.forEach { NotificationCenter.default.removeObserver($0) }
+            observers.removeAll()
+        }
+
+        deinit {
+            removeObservers()
+        }
+    }
+}
+
+final class WindowObservationView: NSView {
+    var onWindowChange: ((NSWindow?) -> Void)?
+
+    override func viewDidMoveToWindow() {
+        super.viewDidMoveToWindow()
+        onWindowChange?(window)
+    }
+}
+
+private struct FullScreenTopInsetModifier: ViewModifier {
+    @State private var isFullScreen = false
+
+    func body(content: Content) -> some View {
+        content
+            .padding(.top, isFullScreen ? AppWindow.fullScreenTopInset : 0)
+            .background {
+                WindowFullScreenObserver(isFullScreen: $isFullScreen)
+            }
+    }
+}
+
+extension View {
+    func fullScreenTopInsetWhenNeeded() -> some View {
+        modifier(FullScreenTopInsetModifier())
+    }
+}

+ 1 - 0
Reddit App/Views/FrontPageView.swift

@@ -29,6 +29,7 @@ struct FrontPageView: View {
                 mainContent
                     .frame(maxWidth: .infinity, maxHeight: .infinity)
             }
+            .fullScreenTopInsetWhenNeeded()
             .environment(\.requirePremiumAccess, {
                 if subscriptions.hasPremiumAccess { return true }
                 viewModel.showPaywall()