field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

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 }