TeraMediaAccessStore.swift (2289B)
1 import Foundation 2 3 /// Read-only capability observation and explicit intake, scoped to one account. 4 @MainActor 5 final class TeraMediaAccessStore { 6 private(set) var support = TeraAddMediaSupport.unavailable { 7 didSet { changed() } 8 } 9 10 var changed: () -> Void = {} 11 private let media: (any TeraAddMediaHandling)? 12 private var generation = TeraSessionGeneration.initial 13 14 init(media: (any TeraAddMediaHandling)?) { 15 self.media = media 16 } 17 18 func accept(_ support: TeraAddMediaSupport) { 19 self.support = support 20 } 21 22 func invalidate() { 23 generation = generation.invalidated() 24 } 25 26 func inspect() async throws -> TeraAddMediaSupport { 27 try await media?.support() ?? .unavailable 28 } 29 30 func prepare(limit: Int, capture: Bool) async throws -> [TeraPreparedMedia] { 31 guard limit > 0, let media else { throw TeraComposerAcknowledgment.unconfirmed } 32 if capture { 33 return try await [self.capture()] 34 } 35 let requested = generation 36 let result = try await media.importImages(limit: limit) 37 try ensureCurrent(requested) 38 return result 39 } 40 41 func recheck() async { 42 invalidate() 43 let requested = generation 44 let result = try? await media?.support() 45 guard requested == generation, generation.isActive, !Task.isCancelled else { return } 46 support = result ?? .unavailable 47 } 48 49 func capture() async throws -> TeraPreparedMedia { 50 let requested = generation 51 guard let media else { throw TeraComposerAcknowledgment.unconfirmed } 52 let capabilities = try await media.support() 53 try ensureCurrent(requested) 54 support = capabilities 55 guard support.camera else { 56 throw TeraRuntimeFailure.local(operation: "add.media.camera", code: "ios.camera.unavailable", 57 safeMessage: support.cameraAccess.guidance) 58 } 59 do { 60 let result = try await media.captureImage() 61 try ensureCurrent(requested) 62 return result 63 } catch { 64 let refreshed = try? await media.support() 65 try ensureCurrent(requested) 66 support = refreshed ?? .unavailable 67 throw error 68 } 69 } 70 71 private func ensureCurrent(_ requested: TeraSessionGeneration) throws { 72 guard generation == requested, generation.isActive, !Task.isCancelled else { throw CancellationError() } 73 } 74 }