mirror of
https://github.com/yattee/yattee.git
synced 2026-10-24 13:42:54 +00:00
Let activation know the accounts before it repairs the selection
Foreground activation started identity resolution, the deletion repair and the CloudKit fetch as three things racing each other. With a tombstone for the selected account already on disk and a sibling login on the same server whose status had not been read back yet, the repair ran against `checking` — which it will not repair onto — and landed on local. It commits, so the status refresh arriving a moment later changed nothing: the selection no longer named an account for a second repair to act on. The steps now run as one sequence in both platform paths, because each one is what makes the next correct: the identity says whose accounts these are, the status refresh says which of them this device can use, the repair reads those statuses, and the fetch goes last so a deletion it delivers repairs against the same refreshed picture.
This commit is contained in:
@@ -288,24 +288,10 @@ struct YatteeApp: App {
|
||||
// Refresh media source password status (Keychain state can change in background)
|
||||
appEnvironment.mediaSourcesManager.refreshPasswordStoredStatus()
|
||||
|
||||
// Retry a credential identity scope that never resolved (e.g.
|
||||
// launched offline) - account credentials stay unavailable until it does
|
||||
// Identity, statuses, deletion repair and the fetch, in that
|
||||
// order — each one is what makes the next one correct.
|
||||
Task {
|
||||
await appEnvironment.credentialIdentityScope.resolveIfNeeded()
|
||||
// A credential can arrive over iCloud Keychain without the
|
||||
// scope moving, so statuses are recomputed unconditionally.
|
||||
appEnvironment.refreshAccountStatuses()
|
||||
}
|
||||
|
||||
// Repair a context whose account was deleted on another device
|
||||
// while this one was in the background. Only a deletion moves
|
||||
// it — an account that merely has not synced yet is left alone.
|
||||
appEnvironment.dataContextValidator.correctIfContextRemoved()
|
||||
SubscriptionFeedCache.shared.warmIfNeeded(using: appEnvironment)
|
||||
|
||||
// Fetch remote CloudKit changes (catches missed push notifications)
|
||||
Task {
|
||||
await appEnvironment.cloudKitSync.fetchRemoteChanges()
|
||||
await resumeAccountState()
|
||||
}
|
||||
|
||||
// Start periodic polling as fallback for missed push notifications
|
||||
@@ -346,29 +332,15 @@ struct YatteeApp: App {
|
||||
// Refresh media source password status (Keychain state can change in background)
|
||||
appEnvironment.mediaSourcesManager.refreshPasswordStoredStatus()
|
||||
|
||||
// Retry a credential identity scope that never resolved (e.g.
|
||||
// launched offline) - account credentials stay unavailable until it does
|
||||
// Identity, statuses, deletion repair and the fetch, in that
|
||||
// order — each one is what makes the next one correct.
|
||||
Task {
|
||||
await appEnvironment.credentialIdentityScope.resolveIfNeeded()
|
||||
// A credential can arrive over iCloud Keychain without the
|
||||
// scope moving, so statuses are recomputed unconditionally.
|
||||
appEnvironment.refreshAccountStatuses()
|
||||
await resumeAccountState()
|
||||
}
|
||||
|
||||
// Repair a context whose account was deleted on another device
|
||||
// while this one was in the background. Only a deletion moves
|
||||
// it — an account that merely has not synced yet is left alone.
|
||||
appEnvironment.dataContextValidator.correctIfContextRemoved()
|
||||
SubscriptionFeedCache.shared.warmIfNeeded(using: appEnvironment)
|
||||
|
||||
// Check clipboard for external video URLs
|
||||
checkClipboardForExternalURL()
|
||||
|
||||
// Fetch remote CloudKit changes (catches missed push notifications)
|
||||
Task {
|
||||
await appEnvironment.cloudKitSync.fetchRemoteChanges()
|
||||
}
|
||||
|
||||
// Start periodic polling as fallback for missed push notifications
|
||||
appEnvironment.cloudKitSync.startForegroundPolling()
|
||||
}
|
||||
@@ -435,6 +407,39 @@ struct YatteeApp: App {
|
||||
#endif
|
||||
}
|
||||
|
||||
/// The part of foreground activation that has to happen in order.
|
||||
///
|
||||
/// Every step here decides what the next one is allowed to see, so these
|
||||
/// run as one sequence rather than as tasks racing each other:
|
||||
///
|
||||
/// 1. The identity names whose accounts and credentials are in play at all.
|
||||
/// 2. The status refresh says which of those this device can actually use.
|
||||
/// 3. Only then may a tombstone move the selection — the repair prefers a
|
||||
/// signed-in login on the same server, and a sibling whose status is
|
||||
/// still being determined is one it would skip, landing on local
|
||||
/// instead. The repair commits, so there is no second chance at it.
|
||||
/// 4. The fetch goes last for the same reason: a deletion it delivers
|
||||
/// repairs the context as it applies, off the statuses read above.
|
||||
private func resumeAccountState() async {
|
||||
// Retry a credential identity scope that never resolved (e.g.
|
||||
// launched offline) - account credentials stay unavailable until it does
|
||||
await appEnvironment.credentialIdentityScope.resolveIfNeeded()
|
||||
|
||||
// A credential can arrive over iCloud Keychain without the
|
||||
// scope moving, so statuses are recomputed unconditionally.
|
||||
appEnvironment.refreshAccountStatuses()
|
||||
|
||||
// Repair a context whose account was deleted on another device
|
||||
// while this one was in the background. Only a deletion moves
|
||||
// it — an account that merely has not synced yet is left alone.
|
||||
appEnvironment.dataContextValidator.correctIfContextRemoved()
|
||||
|
||||
SubscriptionFeedCache.shared.warmIfNeeded(using: appEnvironment)
|
||||
|
||||
// Fetch remote CloudKit changes (catches missed push notifications)
|
||||
await appEnvironment.cloudKitSync.fetchRemoteChanges()
|
||||
}
|
||||
|
||||
private func registerBackgroundTasksIfNeeded() {
|
||||
guard !backgroundTasksRegistered else { return }
|
||||
backgroundTasksRegistered = true
|
||||
|
||||
Reference in New Issue
Block a user