@@ -68,6 +68,8 @@ struct HomeView: View {
6868 @State private var connectionTimeoutTask : DispatchWorkItem ? = nil
6969 @State private var wifiConnected = false
7070 @State private var wifiMonitor : NWPathMonitor ? = nil
71+ @State private var isCellularActive = false
72+ @State private var cellularMonitor : NWPathMonitor ? = nil
7173 @State private var isSchedulingInitialSetup = false
7274 @AppStorage ( " cachedAppNamesData " ) private var cachedAppNamesData : Data ?
7375 @AppStorage ( " autoStartVPN " ) private var autoStartVPN = true
@@ -89,6 +91,9 @@ struct HomeView: View {
8991 !ddiMounted &&
9092 !heartbeatOK
9193 }
94+ private var shouldPromptForWiFi : Bool {
95+ pairingFileLikelyInvalid && !wifiConnected && isCellularActive
96+ }
9297
9398 private let pairingFileURL = URL . documentsDirectory. appendingPathComponent ( " pairingFile.plist " )
9499
@@ -146,6 +151,7 @@ struct HomeView: View {
146151 . onAppear {
147152 scheduleInitialSetupWork ( )
148153 startWiFiMonitoring ( )
154+ startCellularMonitoring ( )
149155 if autoStartVPN && tunnel. tunnelStatus == . disconnected {
150156 TunnelManager . shared. startVPN ( )
151157 }
@@ -163,6 +169,7 @@ struct HomeView: View {
163169 connectionTimeoutTask? . cancel ( )
164170 connectionTimeoutTask = nil
165171 stopWiFiMonitoring ( )
172+ stopCellularMonitoring ( )
166173 hasAutoStartedConnectionCheck = false
167174 }
168175 . onReceive ( timer) { _ in
@@ -370,7 +377,13 @@ struct HomeView: View {
370377 . font ( . headline. weight ( . semibold) )
371378 . foregroundStyle ( . primary)
372379
373- if primaryActionTitle == " New Pairing File Needed " {
380+ if shouldPromptForWiFi {
381+ statusBadge (
382+ icon: " wifi.slash " ,
383+ text: " Wi-Fi required " ,
384+ color: . orange
385+ )
386+ } else if pairingFileLikelyInvalid {
374387 statusBadge (
375388 icon: " xmark.octagon.fill " ,
376389 text: " Pairing file expired " ,
@@ -515,6 +528,24 @@ struct HomeView: View {
515528 wifiMonitor = nil
516529 }
517530
531+ private func startCellularMonitoring( ) {
532+ guard cellularMonitor == nil else { return }
533+ let monitor = NWPathMonitor ( requiredInterfaceType: . cellular)
534+ cellularMonitor = monitor
535+ monitor. pathUpdateHandler = { path in
536+ DispatchQueue . main. async {
537+ isCellularActive = path. status == . satisfied
538+ }
539+ }
540+ monitor. start ( queue: DispatchQueue . global ( qos: . utility) )
541+ }
542+
543+ private func stopCellularMonitoring( ) {
544+ cellularMonitor? . cancel ( )
545+ cellularMonitor = nil
546+ isCellularActive = false
547+ }
548+
518549 private var pairingStatusDescription : String {
519550 if isValidatingPairingFile { return " Validating pairing file… " }
520551 if pairingFileExists {
@@ -528,7 +559,7 @@ struct HomeView: View {
528559
529560 private var wifiStatusDescription : String {
530561 if isConnectionCheckRunning { return " Checking Wi-Fi status… " }
531- return wifiConnected ? " Wi-Fi connected and ready. " : " Connect to Wi-Fi on the same network as your trusted computer . "
562+ return wifiConnected ? " Wi-Fi connected and ready. " : " Connect to Wi-Fi. "
532563 }
533564
534565 private var isConnectionCheckRunning : Bool {
@@ -736,6 +767,7 @@ struct HomeView: View {
736767 private var primaryActionTitle : String {
737768 if isValidatingPairingFile { return " Validating… " }
738769 if !pairingFileExists { return pairingFilePresentOnDisk ? " Import New Pairing File " : " Import Pairing File " }
770+ if shouldPromptForWiFi { return " Connect to Wi-Fi " }
739771 if pairingFileLikelyInvalid { return " New Pairing File Needed " }
740772 if !ddiMounted { return " Mount Developer Disk Image " }
741773 return " Connect by App "
@@ -744,6 +776,7 @@ struct HomeView: View {
744776 private var primaryActionIcon : String {
745777 if isValidatingPairingFile { return " hourglass " }
746778 if !pairingFileExists { return pairingFilePresentOnDisk ? " arrow.clockwise " : " doc.badge.plus " }
779+ if shouldPromptForWiFi { return " wifi.slash " }
747780 if pairingFileLikelyInvalid { return " arrow.clockwise " }
748781 if !ddiMounted { return " externaldrive " }
749782 return " cable.connector.horizontal "
@@ -1140,7 +1173,15 @@ struct HomeView: View {
11401173 private func primaryActionTapped( ) {
11411174 guard !isValidatingPairingFile else { return }
11421175 if pairingFileLikelyInvalid {
1143- isShowingPairingFilePicker = true
1176+ if shouldPromptForWiFi {
1177+ showAlert (
1178+ title: " Wi-Fi Required " ,
1179+ message: " Connect to Wi-Fi. " ,
1180+ showOk: true
1181+ ) { _ in }
1182+ } else {
1183+ isShowingPairingFilePicker = true
1184+ }
11441185 return
11451186 }
11461187 if pairingFileExists {
0 commit comments