krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

v4.5.0: DomainDig/RootTabView.swift · raw

  1import SwiftUI
  2
  3private enum RootTab: Hashable {
  4    case dashboard
  5    case audit
  6    case history
  7    case inspect
  8    case settings
  9}
 10
 11struct RootTabView: View {
 12    @Bindable var viewModel: DomainViewModel
 13    @State private var purchaseService = PurchaseService.shared
 14    @State private var intentRouter = DomainDigIntentRouter.shared
 15    @State private var detailDomain: TrackedDomain?
 16    @State private var selectedTab: RootTab = FeatureAccessService.currentTier == .free ? .inspect : .dashboard
 17
 18    var body: some View {
 19        let _ = purchaseService.currentTier
 20
 21        TabView(selection: $selectedTab) {
 22            NavigationStack {
 23                DashboardView(viewModel: viewModel)
 24            }
 25            .tabItem {
 26                Label("Dashboard", systemImage: "square.grid.2x2")
 27            }
 28            .tag(RootTab.dashboard)
 29
 30            NavigationStack {
 31                AuditListView(viewModel: viewModel)
 32            }
 33            .tabItem {
 34                Label("Audit", systemImage: "checklist")
 35            }
 36            .tag(RootTab.audit)
 37
 38            NavigationStack {
 39                HistoryView(viewModel: viewModel)
 40            }
 41            .tabItem {
 42                Label("History", systemImage: "clock.arrow.trianglehead.counterclockwise.rotate.90")
 43            }
 44            .tag(RootTab.history)
 45
 46            ContentView(viewModel: viewModel)
 47                .tabItem {
 48                    Label("Inspect", systemImage: "magnifyingglass")
 49                }
 50                .tag(RootTab.inspect)
 51
 52            NavigationStack {
 53                SettingsView(viewModel: viewModel)
 54            }
 55            .tabItem {
 56                Label("Settings", systemImage: "gearshape")
 57            }
 58            .tag(RootTab.settings)
 59        }
 60        .sheet(isPresented: Binding(
 61            get: { viewModel.isPaywallPresented },
 62            set: { viewModel.isPaywallPresented = $0 }
 63        )) {
 64            PaywallView()
 65        }
 66        .alert(item: Binding(
 67            get: { viewModel.upgradePrompt },
 68            set: { viewModel.upgradePrompt = $0 }
 69        )) { prompt in
 70            Alert(
 71                title: Text(prompt.title),
 72                message: Text(prompt.message),
 73                primaryButton: .default(Text("Open Paywall")) {
 74                    viewModel.upgradePrompt = nil
 75                    viewModel.isPaywallPresented = true
 76                },
 77                secondaryButton: .cancel(Text("Continue")) {
 78                    viewModel.upgradePrompt = nil
 79                }
 80            )
 81        }
 82        .onChange(of: purchaseService.currentTier) { _, newValue in
 83            if newValue != .free, selectedTab == .inspect, viewModel.trackedDomains.isEmpty == false {
 84                selectedTab = .dashboard
 85            }
 86        }
 87        .sheet(item: $detailDomain) { trackedDomain in
 88            NavigationStack {
 89                TrackedDomainDetailView(viewModel: viewModel, trackedDomain: trackedDomain)
 90            }
 91        }
 92        .onOpenURL { url in
 93            guard let action = DomainDigDeepLink.action(from: url) else { return }
 94            perform(action)
 95        }
 96        .onChange(of: intentRouter.pendingAction) { _, action in
 97            consume(action)
 98        }
 99        .task {
100            consume(intentRouter.pendingAction)
101        }
102    }
103
104    private func consume(_ action: DomainDigDeepLink.Action?) {
105        guard let action else { return }
106        intentRouter.pendingAction = nil
107        perform(action)
108    }
109
110    private func perform(_ action: DomainDigDeepLink.Action) {
111        switch action {
112        case let .inspect(domain):
113            viewModel.domain = domain
114            selectedTab = .inspect
115            viewModel.run()
116        case let .watch(domain):
117            // On success show the dashboard (where tracked domains live); on
118            // failure stay put so the upgrade/paywall alert surfaces in place.
119            if viewModel.trackDomain(domain: domain, availabilityStatus: nil) {
120                selectedTab = .dashboard
121            }
122        case let .detail(domain):
123            // Open the tracked domain's detail (e.g. from a widget tap). If it is
124            // no longer tracked, fall back to inspecting it.
125            if let tracked = viewModel.trackedDomains.first(
126                where: { $0.domain.caseInsensitiveCompare(domain) == .orderedSame }
127            ) {
128                detailDomain = tracked
129            } else {
130                perform(.inspect(domain))
131            }
132        case .sweep:
133            selectedTab = .dashboard
134            viewModel.refreshAllTrackedDomains()
135        }
136    }
137}