diff --git a/FuelBoard/ContentView.swift b/FuelBoard/ContentView.swift index 700b440..558fd04 100644 --- a/FuelBoard/ContentView.swift +++ b/FuelBoard/ContentView.swift @@ -5,7 +5,7 @@ import WidgetKit /// The single floating notification banner. Network/offline state and tip /// outcomes all funnel through ONE style and render via the same chrome in /// ContentView — never pushing layout, always overlaid. -enum AppBanner: Equatable { +enum AppBanner: Hashable { case offlineDump(date: String) case connectionProblem case tip(TipStore.TipOutcome) @@ -491,6 +491,10 @@ struct ContentView: View { // main content so it doesn't cover or block the list/pill // beneath it. floatingBanner(banner) + // Key by value so ANY change (tip→network, tip→nil) + // runs the removal transition (fade/slide-out) instead + // of silently swapping content in place. + .id(banner) .padding(.top, geo.safeAreaInsets.top + 10) .transition(.asymmetric( insertion: .move(edge: .top).combined(with: .opacity), diff --git a/FuelBoard/SettingsView.swift b/FuelBoard/SettingsView.swift index 9582da5..3f0744f 100644 --- a/FuelBoard/SettingsView.swift +++ b/FuelBoard/SettingsView.swift @@ -604,7 +604,7 @@ final class TipStore: ObservableObject { ] /// A banner outcome: the exact copy to show plus its icon + tint. - struct TipOutcome: Equatable { + struct TipOutcome: Hashable { let message: String let icon: String let tint: Color