ios: fix chat list subscription status indicator stuck at empty "%"

The toolbar-hosted indicator held its subscription totals in @State and refreshed them via a 1s poll; the toolbar rebuilds frequently, recreating the view and resetting the @State totals to the empty "share unknown" state. Move the totals into a dedicated SubsStatusModel observable (a shared singleton, like ChannelRelaysModel/ConnectProgressManager) so they survive view recreation, instead of binding poll state into the widely-observed ChatModel. The poll publishes only on change (SMPServerSubs is now Equatable), so the indicator does not re-render every idle second.
This commit is contained in:
Narasimha-sc
2026-06-20 17:02:33 +00:00
parent 602f17ecfa
commit edd82a767e
3 changed files with 24 additions and 7 deletions
+1 -1
View File
@@ -2382,7 +2382,7 @@ struct ServerSessions: Codable {
var hasSess: Bool { ssConnected > 0 }
}
struct SMPServerSubs: Codable {
struct SMPServerSubs: Codable, Equatable {
var ssActive: Int
var ssPending: Int
+18
View File
@@ -359,6 +359,24 @@ class ChannelRelaysModel: ObservableObject {
}
}
// Subscription totals for the chat list status indicator. Kept in a dedicated
// observable (not on ChatModel) so they survive the toolbar-hosted indicator
// being recreated on frequent toolbar rebuilds, without waking ChatModel's many
// observers on every poll tick.
class SubsStatusModel: ObservableObject {
static let shared = SubsStatusModel()
@Published var totalSubs: SMPServerSubs = SMPServerSubs.newSMPServerSubs
@Published var hasSession: Bool = false
func update(_ totalSubs: SMPServerSubs, _ hasSession: Bool) {
// only publish on change - avoid re-rendering the indicator on every idle poll tick
if self.totalSubs != totalSubs || self.hasSession != hasSession {
self.totalSubs = totalSubs
self.hasSession = hasSession
}
}
}
// Spec: spec/state.md#ChatModel
final class ChatModel: ObservableObject {
@Published var onboardingStage: OnboardingStage?
@@ -559,8 +559,8 @@ struct ChatListView: View {
}
struct SubsStatusIndicator: View {
@State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs
@State private var hasSess: Bool = false
// Totals live on a dedicated observable so they survive this view being recreated on frequent toolbar rebuilds
@ObservedObject private var subsModel = SubsStatusModel.shared
@State private var task: Task<Void, Never>?
@State private var showServersSummary = false
@@ -572,9 +572,9 @@ struct SubsStatusIndicator: View {
} label: {
HStack(spacing: 4) {
Text("Chats").foregroundStyle(Color.primary).fixedSize().font(.headline)
SubscriptionStatusIndicatorView(subs: subs, hasSess: hasSess)
SubscriptionStatusIndicatorView(subs: subsModel.totalSubs, hasSess: subsModel.hasSession)
if showSubscriptionPercentage {
SubscriptionStatusPercentageView(subs: subs, hasSess: hasSess)
SubscriptionStatusPercentageView(subs: subsModel.totalSubs, hasSess: subsModel.hasSession)
}
}
}
@@ -598,8 +598,7 @@ struct SubsStatusIndicator: View {
do {
let (subs, hasSess) = try await getAgentSubsTotal()
await MainActor.run {
self.subs = subs
self.hasSess = hasSess
SubsStatusModel.shared.update(subs, hasSess)
}
} catch let error {
logger.error("getSubsTotal error: \(responseError(error))")