import UIKit /// Device-level safe area lookup modeled after GKNavigationBarSwift. /// Reads the real safe area from the key window so correct values are /// available even before a view has been laid out in the hierarchy. /// Must be called on the main thread. public enum RDEPUBSafeArea { /// Minimum text margins applied when the device safe area on an edge is /// smaller (e.g. no notch / no home indicator). These are aesthetic /// paddings, not approximations of the safe area itself. public static let minimumVerticalTextMargin: CGFloat = 20 public static let minimumHorizontalTextMargin: CGFloat = 16 public static func keyWindow() -> UIWindow? { let scenes = UIApplication.shared.connectedScenes .compactMap { $0 as? UIWindowScene } if let window = scenes .filter({ $0.activationState == .foregroundActive }) .flatMap({ $0.windows }) .first(where: { $0.isKeyWindow }) { return window } if let window = scenes .flatMap({ $0.windows }) .first(where: { $0.isKeyWindow }) { return window } return UIApplication.shared.delegate?.window ?? nil } public static func insets() -> UIEdgeInsets { if let window = keyWindow() { return window.safeAreaInsets } // No key window yet (early launch): create a detached window to read // the device safe area, same fallback as GKNavigationBarSwift. let window = UIWindow(frame: UIScreen.main.bounds) if window.safeAreaInsets.bottom <= 0 { window.rootViewController = UIViewController() } return window.safeAreaInsets } /// Prefers insets measured from a view already installed in the hierarchy; /// falls back to the key-window insets when the view is not laid out yet /// and reports .zero. public static func resolve(_ measuredInsets: UIEdgeInsets?) -> UIEdgeInsets { if let measuredInsets, measuredInsets != .zero { return measuredInsets } return insets() } /// Default reflowable content insets derived from the live device safe /// area instead of hard-coded heights. public static func defaultReflowableContentInsets() -> UIEdgeInsets { let safe = insets() return UIEdgeInsets( top: max(safe.top, minimumVerticalTextMargin), left: max(safe.left, minimumHorizontalTextMargin), bottom: max(safe.bottom, minimumVerticalTextMargin), right: max(safe.right, minimumHorizontalTextMargin) ) } }