mirror of
https://github.com/yattee/yattee.git
synced 2026-10-29 07:57:17 +00:00
Bind results to the account and identity they were requested for
Fetched account records are staged under the identity the fetch began under, not whichever is current when they arrive — the engine's fetch spans several delegate events and the Apple account can move between them, which would have filed one identity's accounts under another's. Subscription fetches are fenced against context switches, not only against a provider being discarded. Providers are deliberately kept across a switch — each is one account's cache — so an earlier account's fetch could finish afterwards and put its channels on screen while unsubscribes went to the account now selected. The subscriptions view reloads when the *effective* context moves, which a credential arriving, expiring or being rejected does without the stored context changing at all. Feed requests report what they learn about the account, like every other authenticated call: a credential that expired during a feed-only refresh kept looking signed in, and the fallback never engaged. The classification behind that verdict now exists once, on AccountsManager, rather than in each provider.
This commit is contained in:
@@ -22,6 +22,9 @@ struct SubscriptionsView: View {
|
||||
@State private var feedCache = SubscriptionFeedCache.shared
|
||||
@State private var subscriptions: [Subscription] = []
|
||||
@State private var subscriptionsLoaded = false
|
||||
/// The effective context the visible subscriptions were loaded for, so a
|
||||
/// status change that does not move it does not force a reload.
|
||||
@State private var loadedContext: DataContext?
|
||||
@State private var selectedChannelID: String? = nil
|
||||
@State private var errorMessage: String?
|
||||
@State private var watchEntriesMap: [String: WatchEntry] = [:]
|
||||
@@ -507,15 +510,17 @@ struct SubscriptionsView: View {
|
||||
// switching between them would change nothing here and this
|
||||
// view would keep showing the first account's subscriptions
|
||||
// while writes went to the second.
|
||||
//
|
||||
// Status changes count too, through the *effective* context:
|
||||
// a credential arriving or being rejected moves reads
|
||||
// between the account and local without the stored context
|
||||
// moving at all.
|
||||
.onReceive(NotificationCenter.default.publisher(for: .dataContextDidChange)) { _ in
|
||||
feedCache.handleAccountChange()
|
||||
subscriptions = []
|
||||
subscriptionsLoaded = false
|
||||
Task {
|
||||
guard let appEnvironment else { return }
|
||||
await loadSubscriptionsAsync()
|
||||
await feedCache.refresh(using: appEnvironment)
|
||||
}
|
||||
reloadForContextChange()
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .accountStatusesDidChange)) { _ in
|
||||
guard appEnvironment?.dataContextValidator.effectiveContext != loadedContext else { return }
|
||||
reloadForContextChange()
|
||||
}
|
||||
.task(id: instanceConfigurationID) {
|
||||
LoggingService.shared.debug("SubscriptionsView task triggered, instanceConfigurationID: \(instanceConfigurationID)", category: .general)
|
||||
@@ -1333,9 +1338,28 @@ struct SubscriptionsView: View {
|
||||
|
||||
/// Loads subscriptions asynchronously from the current provider.
|
||||
/// For Invidious, this fetches from the API and creates temporary Subscription objects for UI.
|
||||
/// Drops what is on screen and reloads it for whatever context is current.
|
||||
private func reloadForContextChange() {
|
||||
loadedContext = appEnvironment?.dataContextValidator.effectiveContext
|
||||
feedCache.handleAccountChange()
|
||||
subscriptions = []
|
||||
subscriptionsLoaded = false
|
||||
|
||||
Task {
|
||||
guard let appEnvironment else { return }
|
||||
await loadSubscriptionsAsync()
|
||||
await feedCache.refresh(using: appEnvironment)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadSubscriptionsAsync() async {
|
||||
guard let subscriptionService, let appEnvironment else { return }
|
||||
|
||||
// Recorded on every load, not only on a context change: the first load
|
||||
// of a session has to establish what is on screen, or the first status
|
||||
// change would look like a move and reload for nothing.
|
||||
loadedContext = appEnvironment.dataContextValidator.effectiveContext
|
||||
|
||||
// For local account, just load from DataManager (fast)
|
||||
if appEnvironment.accountsManager.currentContext.isLocal {
|
||||
subscriptions = dataManager?.subscriptions() ?? []
|
||||
|
||||
Reference in New Issue
Block a user