TeraProductStores.swift (3357B)
1 import Foundation 2 3 @MainActor 4 final class TeraProductStores { 5 let today: TeraTodayStore 6 let add: TeraAddStore 7 let search: TeraSearchStore 8 let me: TeraMeStore 9 let settings: TeraSettingsStore 10 let media: TeraMediaStore 11 let visibility: TeraVisibilityStore 12 private var generation = TeraSessionGeneration.initial 13 private var startupTask: Task<Void, Never>? 14 15 init( 16 runtimeClient: TeraRuntimeClient, 17 addMedia: (any TeraAddMediaHandling)? = nil 18 ) { 19 today = TeraTodayStore(runtimeClient: runtimeClient) 20 add = TeraAddStore(runtimeClient: runtimeClient, media: addMedia) 21 search = TeraSearchStore(runtimeClient: runtimeClient) 22 me = TeraMeStore(runtimeClient: runtimeClient) 23 settings = TeraSettingsStore(runtimeClient: runtimeClient) 24 media = TeraMediaStore(runtimeClient: runtimeClient) 25 visibility = TeraVisibilityStore(runtimeClient: runtimeClient) 26 visibility.willChange = { [today] in today.invalidateVisibility() } 27 visibility.didChange = { [today] in await today.reload(refreshProjection: false) } 28 today.mediaWillChange = { [media] previous, current, context in 29 media.reconcileVisibility(previous: previous, current: current, context: context) 30 } 31 today.scopeWillChange = { [search, me, media] context in 32 search.stop() 33 search.configure(context: context) 34 me.stop() 35 me.configure(context: context) 36 media.reset() 37 } 38 } 39 40 deinit { 41 startupTask?.cancel() 42 } 43 44 func configure(snapshot: TeraRuntimeSnapshot) { 45 let wasStarting = startupTask != nil 46 cancelStartup() 47 if wasStarting { 48 today.stop() 49 add.suspend() 50 } 51 today.configure(snapshot: snapshot) 52 add.configure(snapshot: snapshot) 53 search.stop() 54 search.configure(context: today.selectedContext) 55 me.stop() 56 me.configure(context: today.selectedContext) 57 settings.configure(snapshot: snapshot) 58 media.configure(snapshot: snapshot) 59 visibility.configure(snapshot: snapshot) 60 } 61 62 func start() { 63 guard startupTask == nil, generation.isActive, !Task.isCancelled else { return } 64 generation = generation.invalidated() 65 guard generation.isActive else { return } 66 let requested = generation 67 startupTask = Task { [weak self, today, add] in 68 async let todayStart: Void = today.start() 69 async let addStart: Void = add.start() 70 _ = await (todayStart, addStart) 71 self?.finishStartup(requested, cancelled: Task.isCancelled) 72 } 73 } 74 75 func resume() async { 76 guard !Task.isCancelled else { return } 77 start() 78 guard let task = startupTask else { return } 79 await withTaskCancellationHandler { await task.value } onCancel: { task.cancel() } 80 } 81 82 private func finishStartup(_ requested: TeraSessionGeneration, cancelled: Bool) { 83 guard generation == requested else { return } 84 startupTask = nil 85 if cancelled { 86 today.stop() 87 add.suspend() 88 } 89 } 90 91 func suspend() { 92 cancelStartup() 93 today.stop() 94 add.suspend() 95 search.stop() 96 me.stop() 97 settings.stop() 98 media.reset() 99 } 100 101 func stop() { 102 visibility.stop() 103 cancelStartup() 104 today.stop() 105 add.stop() 106 search.stop() 107 me.stop() 108 settings.stop() 109 media.reset() 110 } 111 112 private func cancelStartup() { 113 generation = generation.invalidated() 114 startupTask?.cancel() 115 startupTask = nil 116 } 117 }