Let temporary account states recover on their own

"Could not be reached" now expires after a minute. It stops reads from
going to the server at all, so nothing could ever discover that the
server came back — and a timeout during an outage produces no
connectivity change to react to either. The credential is untouched
throughout; the next request settles it either way.

A rejection is remembered against the credential that earned it. Signing
in again on another device replaces that secret under the same key, and
preserving the rejection regardless left the newly synced credential
unusable with no way to prove otherwise.

An account that syncs ahead of its credential — the ordinary case on a
new device, since iCloud Keychain delivers on its own schedule and
announces nothing — is re-checked for a couple of minutes instead of
sitting at "sign in required" until something unrelated happens. It
gives up rather than polling forever: on tvOS the wait is permanent by
design.

The feed cache no longer restores a purged account's videos from disk if
the load was already in flight when the purge happened, and no longer
leaves its loading flag set afterwards — which blocked the replacement
refresh and left the new account on an empty feed.
This commit is contained in:
Arkadiusz Fal
2026-08-27 22:20:53 +02:00
parent e094770047
commit 46db43c9b5
4 changed files with 147 additions and 14 deletions

View File

@@ -129,8 +129,21 @@ final class SubscriptionFeedCache {
return
}
diskCacheLoaded = true
let generation = accountGeneration
if let cacheData = await FeedCache.shared.load() {
// The identity or the login can change while this is awaiting the
// disk. Applying what it brings back would restore the previous
// account's private feed on top of a cache that was deliberately
// emptied.
guard generation == accountGeneration else {
LoggingService.shared.info(
"Discarding a disk feed that belongs to the previous login",
category: .general
)
return
}
videos = cacheData.videos
lastUpdated = cacheData.lastUpdated
hasLoadedOnce = true
@@ -222,6 +235,11 @@ final class SubscriptionFeedCache {
accountGeneration += 1
clear()
feedLoadState = .idle
// The request that was running belongs to the previous account and its
// result is now fenced out, so it must not go on blocking the
// replacement — the new account would sit on an empty feed until
// something else asked for a refresh.
isLoading = false
}
/// Which account's data the running request belongs to.