TeraSubmissionInventory.swift (2080B)
1 import Foundation 2 3 /// One bounded page and one reader; continuation replaces, never accumulates. 4 @MainActor 5 final class TeraSubmissionInventory: ObservableObject { 6 @Published private(set) var entries: [TeraSubmissionEntry] = [] 7 @Published private(set) var cursor: String? 8 @Published private(set) var message: String? 9 @Published private(set) var isLoading = false 10 private let client: TeraRuntimeClient 11 private var scope: TeraComposerScope? 12 private var generation = TeraSessionGeneration.initial 13 private var worker: Task<Void, Never>? 14 private var pending: String?? 15 16 init(client: TeraRuntimeClient) { 17 self.client = client 18 } 19 20 deinit { worker?.cancel() } 21 22 func configure(scope: TeraComposerScope) { 23 guard self.scope != scope else { return } 24 stop() 25 self.scope = scope 26 entries = [] 27 cursor = nil 28 message = nil 29 } 30 31 func stop() { 32 generation = generation.invalidated() 33 pending = nil 34 worker?.cancel() 35 } 36 37 func start() { 38 pending = .some(nil); schedule() 39 } 40 41 func more() { 42 guard !isLoading, let cursor else { return } 43 pending = .some(cursor) 44 schedule() 45 } 46 47 private func schedule() { 48 guard worker == nil, let next = pending, let scope, generation.isActive else { return } 49 pending = nil 50 isLoading = true 51 let requested = generation 52 worker = Task { [weak self] in 53 guard let self else { return } 54 do { 55 let page = try await client.listSubmissions(scope: scope, limit: 100, cursor: next) 56 guard generation == requested, !Task.isCancelled else { return finish() } 57 guard page.scope == scope, page.entries.count <= 100 else { throw TeraComposerAcknowledgment.unconfirmed } 58 entries = page.entries 59 cursor = page.nextCursor 60 message = nil 61 } catch { 62 if generation == requested, !Task.isCancelled { 63 message = "Saved submissions could not be listed. Keep editing and retry the list." 64 } 65 } 66 finish() 67 } 68 } 69 70 private func finish() { 71 worker = nil 72 isLoading = false 73 schedule() 74 } 75 }