import Foundation #if canImport(SwiftUI) import SwiftUI #endif #if canImport(CoreGraphics) import CoreGraphics #endif #if canImport(UIKit) import UIKit #endif #if canImport(AppKit) import AppKit #endif #if canImport(UIKit) extension UIDevice { static var appSafeAreaTop: CGFloat { let scenes = UIApplication.shared.connectedScenes .compactMap { $0 as? UIWindowScene } let windows = scenes.flatMap { $0.windows } if let maxTop = windows.map({ $0.safeAreaInsets.top }).max(), maxTop > 0 { return maxTop } if let fallbackMaxTop = UIApplication.shared.windows.map({ $0.safeAreaInsets.top }).max(), fallbackMaxTop > 0 { return fallbackMaxTop } return 0 } } #else struct UIDevice { static let topNotch: CGFloat = 0.0 static let bottomNotch: CGFloat = 0.0 static let appSafeAreaTop: CGFloat = 0.0 var modelName: String { "mac" } } enum UIKeyboardType: Int { case `default` = 0 case asciiCapable = 1 case numbersAndPunctuation = 2 case URL = 3 case numberPad = 4 case phonePad = 10 case namePhonePad = 9 case emailAddress = 7 case decimalPad = 8 case twitter = 12 case webSearch = 13 case asciiCapableNumberPad = 14 } extension View { @ViewBuilder func keyboardType(_ type: UIKeyboardType) -> some View { self } } #endif func appReadClipboardText() -> String? { #if canImport(UIKit) return UIPasteboard.general.string #elseif canImport(AppKit) return NSPasteboard.general.string(forType: .string) #else return nil #endif } func appWriteClipboardText(_ value: String) { #if canImport(UIKit) UIPasteboard.general.string = value #elseif canImport(AppKit) NSPasteboard.general.clearContents() NSPasteboard.general.setString(value, forType: .string) #else _ = value #endif } extension View { @ViewBuilder func appInlineNavigationTitle() -> some View { #if os(macOS) self #else self .navigationBarTitleDisplayMode(.inline) .modifier(AppRoundedBackButtonModifier()) #endif } @ViewBuilder func appHiddenNavigationBar() -> some View { #if os(macOS) self #else self .toolbar(.hidden, for: .navigationBar) .toolbarBackground(.hidden, for: .navigationBar) #endif } @ViewBuilder func appTopBarTrailingToolbar(@ViewBuilder content: () -> Content) -> some View { #if os(macOS) self.toolbar { ToolbarItem { content() } } #else self.toolbar { ToolbarItem(placement: .topBarTrailing) { content() } } #endif } @ViewBuilder func appContentShape(_ shape: S) -> some View { self.contentShape(shape) } @ViewBuilder func appBottomSafeAreaInset(@ViewBuilder content: () -> Content) -> some View { self.safeAreaInset(edge: .bottom) { content() } } @ViewBuilder func appLayoutPriority(_ value: Double) -> some View { self.layoutPriority(value) } @ViewBuilder func appNamedCoordinateSpace(_ name: String) -> some View { self.coordinateSpace(name: name) } } #if !os(macOS) private struct AppRoundedBackButtonModifier: ViewModifier { @Environment(\.dismiss) private var dismiss func body(content: Content) -> some View { content .navigationBarBackButtonHidden(true) .toolbar { ToolbarItem(placement: .topBarLeading) { Button(action: { dismiss() }) { Image(systemName: "chevron.left") .font(.system(size: 24, weight: .semibold)) .foregroundStyle(AppColors.textPrimary) .frame(width: 52, height: 52) .background(AppColors.surface) .clipShape(Circle()) .shadow(color: .black.opacity(0.06), radius: 8, y: 2) } .buttonStyle(.plain) } } } } #endif