import SwiftUI import AppKit import OnyxDesign import OnyxWidgetKit import OSLog private let log = Logger(subsystem: "com.scarriffleservices.onyx", category: "AirDrop") /// Der Weg zur Empfängerauswahl. public enum AirDrop { /// Öffnet AirDrop mit den übergebenen Dateien. /// /// - Returns: ob AirDrop überhaupt zur Verfügung stand. @MainActor @discardableResult public static func send(_ urls: [URL]) -> Bool { guard !urls.isEmpty else { return false } guard let service = NSSharingService(named: .sendViaAirDrop) else { log.error("AirDrop steht nicht zur Verfügung") return false } guard service.canPerform(withItems: urls) else { log.error("AirDrop kann diese Auswahl nicht senden") return false } service.perform(withItems: urls) return true } } /// Eine Fläche, auf die man Dateien fallen lässt, um sie zu verschicken. public struct AirDropView: View { @State private var isTargeted = false @State private var failed = false public init() {} public var body: some View { VStack(spacing: 6) { Image(systemName: "shareplay") .font(.system(size: 20, weight: .light)) .foregroundStyle(isTargeted ? Onyx.Color.accent : Onyx.Color.textTertiary) Text(failed ? "airdrop.unavailable" : "airdrop.hint", bundle: .module) .font(Onyx.Font.caption) .foregroundStyle(failed ? Onyx.Color.warning : Onyx.Color.textSecondary) .multilineTextAlignment(.center) .fixedSize(horizontal: false, vertical: true) } .frame(maxWidth: .infinity, maxHeight: .infinity) .background { RoundedRectangle(cornerRadius: 10, style: .continuous) .strokeBorder(isTargeted ? Onyx.Color.accent : Onyx.Color.hairline, style: StrokeStyle(lineWidth: 1, dash: [4, 3])) } // Derselbe Weg wie in der Ablage: auch hier kommen Anhänge als // Versprechen an, nicht als fertige Datei. .contentShape(.rect) .onFileDrop(isTargeted: $isTargeted) { urls in failed = !AirDrop.send(urls) } .animation(Onyx.Motion.value, value: isTargeted) } } // MARK: - Widget public struct AirDropWidget: OnyxWidget { public let id = "airdrop" public var displayName: String { String(localized: "airdrop.name", bundle: .module) } public let symbolName = "shareplay" public let supportedSizes: [WidgetSize] = [.small, .medium] public init() {} public func makeView(size: WidgetSize) -> AnyView { AnyView(AirDropView()) } }