TipsArchive.swift (2368B)
1 import SwiftUI 2 3 /// Read-only list of every tip, reached from `Settings → Tips`. Each tip is 4 /// rendered with the same `AnnouncementBanner` chrome it gets on the Game List, 5 /// stacked in a plain scroll view so the banners float on the background rather 6 /// than nesting inside grouped `Form` rows. The archive shows every tip 7 /// regardless of whether it has been dismissed on the Game List, and offers a 8 /// way back in if the user previously chose "Never show me tips". 9 struct TipsArchive: View { 10 @Environment(TipStore.self) private var tips 11 @Environment(AnnouncementCenter.self) private var announcements 12 13 var body: some View { 14 ScrollView { 15 LazyVStack(spacing: 12) { 16 Toggle("Show Tips", isOn: Binding( 17 get: { !tips.isDisabled }, 18 set: { tips.isDisabled = !$0 } 19 )) 20 .padding(.horizontal, 16) 21 .padding(.vertical, 11) 22 // The inset-grouped "section" fill, so the toggle reads like a 23 // Settings row rather than floating on the bare background. 24 .background( 25 Color(.secondarySystemGroupedBackground), 26 in: RoundedRectangle(cornerRadius: 10, style: .continuous) 27 ) 28 .padding(.bottom, 4) 29 30 ForEach(tips.visibleTips) { tip in 31 AnnouncementBanner( 32 announcement: tip.archiveAnnouncement(), 33 showsIcon: false, 34 onDismiss: nil 35 ) 36 } 37 } 38 .padding() 39 } 40 .background(Color(.systemGroupedBackground)) 41 .navigationTitle("Tips") 42 .navigationBarTitleDisplayMode(.inline) 43 .onDisappear { 44 // Leaving the archive with tips turned off clears any tip still 45 // showing on the Game List. This only un-displays it — the tip 46 // isn't marked individually dismissed, so re-enabling later 47 // surfaces it again on the next cold launch. Toggling off then back 48 // on before leaving leaves the banner untouched. 49 guard tips.isDisabled, let tip = tips.firstUndismissedTip() else { return } 50 announcements.dismiss(id: Tip.announcementID(for: tip.id)) 51 } 52 } 53 }