| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- // LoopFollow
- // MainTabView.swift
- import SwiftUI
- struct MainTabView: View {
- @ObservedObject private var selectedTab = Observable.shared.selectedTabIndex
- @ObservedObject private var appearanceMode = Storage.shared.appearanceMode
- @ObservedObject private var homePosition = Storage.shared.homePosition
- @ObservedObject private var alarmsPosition = Storage.shared.alarmsPosition
- @ObservedObject private var remotePosition = Storage.shared.remotePosition
- @ObservedObject private var nightscoutPosition = Storage.shared.nightscoutPosition
- @ObservedObject private var snoozerPosition = Storage.shared.snoozerPosition
- @ObservedObject private var statisticsPosition = Storage.shared.statisticsPosition
- @ObservedObject private var treatmentsPosition = Storage.shared.treatmentsPosition
- @State private var showTelemetryConsent = false
- private var orderedItems: [TabItem] {
- Storage.shared.orderedTabBarItems()
- }
- var body: some View {
- TabView(selection: $selectedTab.value) {
- ForEach(Array(orderedItems.prefix(4).enumerated()), id: \.element) { index, item in
- tabContent(for: item)
- .tabItem {
- Label(item.displayName, systemImage: item.icon)
- }
- .tag(index)
- }
- NavigationStack {
- MoreMenuView()
- }
- .tabItem {
- Label("Menu", systemImage: "line.3.horizontal")
- }
- .tag(4)
- }
- .preferredColorScheme(appearanceMode.value.colorScheme)
- .onAppear {
- // Start the data pipeline as soon as the UI appears, independent of
- // tab layout. Without this, a user who moves Home into the Menu would
- // have no MainViewController — and therefore no data fetching, alarms,
- // or background audio — until they manually opened Home. Tying it to
- // onAppear (not app launch) keeps it off the BG-only refresh path.
- MainViewController.bootstrap()
- // One-time consent prompt. Previously presented by SceneDelegate,
- // which was removed in the storyboard→SwiftUI migration; without
- // this, fresh installs stay permanently undecided and telemetry
- // never sends. The storage flag keeps it to a single appearance.
- if !Storage.shared.telemetryConsentDecisionMade.value {
- showTelemetryConsent = true
- }
- }
- .sheet(isPresented: $showTelemetryConsent) {
- // User must explicitly choose — no swipe-to-dismiss.
- TelemetryConsentView()
- .interactiveDismissDisabled(true)
- }
- }
- @ViewBuilder
- private func tabContent(for item: TabItem) -> some View {
- switch item {
- case .home:
- HomeContentView()
- case .alarms:
- AlarmsContainerView()
- case .remote:
- RemoteContentView()
- case .nightscout:
- NightscoutContentView()
- case .snoozer:
- SnoozerView()
- case .treatments:
- TreatmentsView()
- case .stats:
- NavigationStack {
- AggregatedStatsContentView(mainViewController: MainViewController.shared)
- }
- }
- }
- }
|