From 987ebf9690008a12ea7a90fddab34e8640360290 Mon Sep 17 00:00:00 2001 From: Trey t Date: Sun, 12 Apr 2026 10:08:30 -0500 Subject: [PATCH] fix: Save to Collection button not responding without user interaction The Save to Collection button on the identification screen would remain disabled after plant identification completed, requiring the user to tap a prediction row before it would enable. This was caused by an @Observable + @State tracking issue where computed properties in SwiftUI view modifiers don't always trigger re-renders when the underlying observable changes. Replaced the empty .onChange workaround with a local @State property (saveEnabled) that is explicitly updated when selectedPrediction or saveState changes, ensuring the button state always reflects the current ViewModel state. Fixes #1 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Identification/IdentificationView.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/PlantGuide/Presentation/Scenes/Identification/IdentificationView.swift b/PlantGuide/Presentation/Scenes/Identification/IdentificationView.swift index 5e1c2a6..2bb6194 100644 --- a/PlantGuide/Presentation/Scenes/Identification/IdentificationView.swift +++ b/PlantGuide/Presentation/Scenes/Identification/IdentificationView.swift @@ -19,6 +19,11 @@ struct IdentificationView: View { /// Tracks whether we've announced results to avoid duplicate announcements @State private var hasAnnouncedResults = false + /// Local state to reliably drive the save button's enabled/disabled state. + /// Works around an @Observable + @State tracking issue where computed + /// properties in view modifiers don't always trigger re-renders. + @State private var saveEnabled = false + // MARK: - Scaled Metrics for Dynamic Type @ScaledMetric(relativeTo: .body) private var closeIconSize: CGFloat = 16 @@ -76,8 +81,10 @@ struct IdentificationView: View { announceStateChange(from: oldValue, to: newValue) } .onChange(of: viewModel.selectedPrediction?.id) { _, _ in - // Force view update when selection changes - // This ensures SwiftUI tracks @Observable property changes correctly + saveEnabled = viewModel.canSaveToCollection + } + .onChange(of: viewModel.saveState) { _, _ in + saveEnabled = viewModel.canSaveToCollection } .accessibilityIdentifier(AccessibilityIdentifiers.Identification.identificationView) .alert("Plant Saved!", isPresented: .init( @@ -406,12 +413,12 @@ struct IdentificationView: View { .padding(.vertical, 14) .background( RoundedRectangle(cornerRadius: 12) - .fill(viewModel.canSaveToCollection ? Color.accentColor : Color.gray) + .fill(saveEnabled ? Color.accentColor : Color.gray) ) } - .disabled(!viewModel.canSaveToCollection) + .disabled(!saveEnabled) .accessibilityLabel(viewModel.saveState == .saving ? "Saving plant" : "Save to Collection") - .accessibilityHint(viewModel.canSaveToCollection ? "Saves the selected plant to your collection" : "Select a plant first") + .accessibilityHint(saveEnabled ? "Saves the selected plant to your collection" : "Select a plant first") .accessibilityIdentifier(AccessibilityIdentifiers.Identification.saveToCollectionButton) } .padding(.horizontal, 20) -- 2.49.1