// // PhotoLibraryWriter.swift // Focale // // Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // // Writes captures into the system photo library via PHAssetCreationRequest. // No parallel library, no private sandbox (CLAUDE.md §4). The user can // uninstall tomorrow and lose nothing. // import Foundation import Photos actor PhotoLibraryWriter { /// PhotoKit runs change blocks on its own queue; this box carries the /// created identifier out of the @Sendable block without giving the /// block any actor isolation (a Swift 6 runtime crash otherwise). private final class IdentifierBox: @unchecked Sendable { var value: String? } /// Saves a capture and returns the new asset's localIdentifier — /// the key the whole index is built on. func save(_ photo: CapturedPhoto) async throws -> String { let box = IdentifierBox() let change: @Sendable () -> Void = { let request = PHAssetCreationRequest.forAsset() if let processed = photo.processedData { request.addResource(with: .photo, data: processed, options: nil) if let raw = photo.rawData { let options = PHAssetResourceCreationOptions() request.addResource(with: .alternatePhoto, data: raw, options: options) } } else if let raw = photo.rawData { request.addResource(with: .photo, data: raw, options: nil) } box.value = request.placeholderForCreatedAsset?.localIdentifier } try await PHPhotoLibrary.shared().performChanges(change) guard let localIdentifier = box.value else { throw CaptureError.captureFailed } return localIdentifier } }