From 02023cf382990758f33c92f2bf67d3d156770c94 Mon Sep 17 00:00:00 2001 From: psavarmattas Date: Fri, 14 Aug 2026 16:08:44 +0100 Subject: [PATCH] fix(reader): force menu rebuild so toggle checkmarks reflect state Viewer Insights (and likely Subscribed/Full Width, same mechanism) kept showing the pre-toggle checkmark in the overflow menu until the whole view was torn down and rebuilt (navigate away and back) - SwiftUI's macOS Menu doesn't reliably re-evaluate a Toggle's checkmark against updated @Observable state on its own. Keying the Menu's .id() to every toggle-backed state it displays forces a fresh rebuild whenever any of them change. --- .../Collections/DocumentReaderView.swift | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Outpost/Features/Collections/DocumentReaderView.swift b/Outpost/Features/Collections/DocumentReaderView.swift index fedb00d..4b6c6d5 100644 --- a/Outpost/Features/Collections/DocumentReaderView.swift +++ b/Outpost/Features/Collections/DocumentReaderView.swift @@ -127,6 +127,13 @@ struct DocumentReaderView: View { } label: { Image(systemName: "ellipsis.circle") } + // SwiftUI's macOS `Menu` doesn't reliably re-evaluate a + // `Toggle`'s checkmark against updated @Observable state on + // its own — without a fresh `.id()` per state combination, + // toggling Subscribed/Viewer Insights/Full Width kept + // showing the pre-toggle checkmark until the whole view was + // torn down and rebuilt (e.g. navigating away and back). + .id(menuIdentity) } } .task { await viewModel.loadFullContent() } @@ -205,6 +212,19 @@ struct DocumentReaderView: View { } } + /// Every toggle-backed piece of state shown as a checkmark inside + /// `menuContent` — see the `.id()` comment on the `Menu` above. + private var menuIdentity: String { + [ + starStore.isStarred(documentId: viewModel.documentId), + viewModel.isSubscribed, + viewModel.isPinned, + viewModel.isInsightsEnabled ?? false, + viewModel.isFullWidth, + viewModel.isEditing + ].map(String.init).joined(separator: "-") + } + @ViewBuilder private var viewerAvatars: some View { if !viewModel.viewers.isEmpty {