import Foundation import SwiftUI import CoreGraphics import 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 } } func appReadClipboardText() -> String? { UIPasteboard.general.string } func appWriteClipboardText(_ value: String) { UIPasteboard.general.string = value } extension View { @ViewBuilder func appInlineNavigationTitle() -> some View { self .navigationBarTitleDisplayMode(.inline) .modifier(AppRoundedBackButtonModifier()) } @ViewBuilder func appHiddenNavigationBar() -> some View { self .toolbar(.hidden, for: .navigationBar) .toolbarBackground(.hidden, for: .navigationBar) } @ViewBuilder func appTopBarTrailingToolbar(@ViewBuilder content: () -> Content) -> some View { self.toolbar { ToolbarItem(placement: .topBarTrailing) { content() } } } @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) } } 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) } } } }