iOS/Sources/Shared/Intents/GetCameraImageIntentHandler...

114 lines
4.3 KiB
Swift

import Foundation
import Intents
import MobileCoreServices
import PromiseKit
import UIKit
class GetCameraImageIntentHandler: NSObject, GetCameraImageIntentHandling {
typealias Intent = GetCameraImageIntent
func resolveServer(for intent: Intent, with completion: @escaping (IntentServerResolutionResult) -> Void) {
if let server = Current.servers.server(for: intent) {
completion(.success(with: .init(server: server)))
} else {
completion(.needsValue())
}
}
func provideServerOptions(for intent: Intent, with completion: @escaping ([IntentServer]?, Error?) -> Void) {
completion(IntentServer.all, nil)
}
func provideServerOptionsCollection(
for intent: Intent,
with completion: @escaping (INObjectCollection<IntentServer>?, Error?) -> Void
) {
completion(.init(items: IntentServer.all), nil)
}
func resolveCameraID(
for intent: Intent,
with completion: @escaping (INStringResolutionResult) -> Void
) {
if let cameraID = intent.cameraID, cameraID.hasPrefix("camera.") {
Current.Log.info("using given \(cameraID)")
completion(.success(with: cameraID))
} else {
Current.Log.info("loading values due to no camera id")
completion(.needsValue())
}
}
func provideCameraIDOptions(
for intent: Intent,
with completion: @escaping ([String]?, Error?) -> Void
) {
guard let server = Current.servers.server(for: intent),
let connection = Current.api(for: server)?.connection else {
completion(nil, PickAServerError.error)
return
}
connection.caches.states.once().promise.map(\.all)
.filterValues { $0.domain == "camera" }
.mapValues(\.entityId)
.sortedValues()
.done { completion($0, nil) }
.catch { completion(nil, $0) }
}
func provideCameraIDOptionsCollection(
for intent: Intent,
with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void
) {
provideCameraIDOptions(for: intent) { identifiers, error in
completion(identifiers.flatMap { .init(items: $0.map { $0 as NSString }) }, error)
}
}
func handle(intent: Intent, completion: @escaping (GetCameraImageIntentResponse) -> Void) {
guard let server = Current.servers.server(for: intent), let api = Current.api(for: server) else {
completion(
.failure(
error: "No server provided, active URL: \(String(describing: Current.servers.server(for: intent)?.info.connection.activeURL()?.absoluteString))"
)
)
return
}
if let cameraID = intent.cameraID {
Current.Log.verbose("Getting camera frame for \(cameraID)")
api.GetCameraImage(cameraEntityID: cameraID).done { frame in
Current.Log.verbose("Successfully got camera image during shortcut")
guard let pngData = frame.pngData() else {
Current.Log.error("Image data could not be converted to PNG")
completion(.failure(error: "Image could not be converted to PNG"))
return
}
let resp = GetCameraImageIntentResponse(code: .success, userActivity: nil)
resp.cameraImage = INFile(
data: pngData,
filename: "\(cameraID)_still.png",
typeIdentifier: kUTTypePNG as String
)
resp.cameraID = cameraID
completion(resp)
}.catch { error in
Current.Log.error("Error when getting camera image in shortcut \(error)")
let resp = GetCameraImageIntentResponse(code: .failure, userActivity: nil)
resp.error = "Error during api.GetCameraImage: \(error.localizedDescription)"
completion(resp)
}
} else {
Current.Log.error("Unable to unwrap intent.cameraID")
let resp = GetCameraImageIntentResponse(code: .failure, userActivity: nil)
resp.error = "Unable to unwrap intent.cameraID"
completion(resp)
}
}
}