diff --git a/NearDrop/AppDelegate.swift b/NearDrop/AppDelegate.swift index 6981937..67c798c 100644 --- a/NearDrop/AppDelegate.swift +++ b/NearDrop/AppDelegate.swift @@ -85,29 +85,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele UNUserNotificationCenter.current().delegate = self -// let monitor = NWPathMonitor() -// monitor.pathUpdateHandler = { path in -// if path.status == .satisfied { -// if path.supportsIPv4 && !path.supportsIPv6 { -// log("Detected IPv4-only network.") -// self.performDeviceToDeviceCheck() -// } else if !path.supportsIPv4 && path.supportsIPv6 { -// log("IPv6-only network, likely iPhone hotspot. Skipping device-to-device check.") -// } else if path.supportsIPv4 && path.supportsIPv6 { -// log("Detected Dual stack network.") -// self.performDeviceToDeviceCheck() -// } else { -// log("Detected no IP support") -// } -// } else { -// log("Network unavailable") -// } -// -// monitor.cancel() -// } -// -// let queue = DispatchQueue(label: "NetworkMonitor") -// monitor.start(queue: queue) + let monitor = NWPathMonitor() + monitor.pathUpdateHandler = { path in + if path.status == .satisfied { + if path.supportsIPv4 && !path.supportsIPv6 { + log("Detected IPv4-only network.") + self.performDeviceToDeviceCheck() + } else if !path.supportsIPv4 && path.supportsIPv6 { + log("IPv6-only network, likely iPhone hotspot. Skipping device-to-device check.") + } else if path.supportsIPv4 && path.supportsIPv6 { + log("Detected Dual stack network.") + self.performDeviceToDeviceCheck() + } else { + log("Detected no IP support") + } + } else { + log("Network unavailable") + } + + monitor.cancel() + } + + let queue = DispatchQueue(label: "NetworkMonitor") + monitor.start(queue: queue) } func performDeviceToDeviceCheck() { @@ -117,7 +117,20 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele log("✅ Device-to-device likely allowed (peer responded on LAN).") self.apIsolationAlertWindow?.close() } else { - self.openAlert(type: .ApIsolation) + + log("❌ First check failed. Retrying in 10 seconds...") + + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + scanner.scan { allowed in + if allowed { + log("✅ Device-to-device likely allowed (peer responded on LAN).") + self.apIsolationAlertWindow?.close() + } else { + log("❌ Second check failed. Informing user...") + self.openAlert(type: .ApIsolation) + } + } + } } } } @@ -209,7 +222,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele switch type { case .ApIsolation: apIsolationAlertWindow = alertWindow - alertWindow.contentView = NSHostingView(rootView: ApIsolationIssueView()) + alertWindow.contentView = NSHostingView(rootView: ApIsolationIssueView(closeView: { self.apIsolationAlertWindow?.close() })) case .NetworkFilter: networkFilterAlertWindow = alertWindow alertWindow.contentView = NSHostingView(rootView: NetworkFilterIssueView()) diff --git a/NearDrop/IssueViews/ApIsolationIssueView.swift b/NearDrop/IssueViews/ApIsolationIssueView.swift index c5905dc..5787078 100644 --- a/NearDrop/IssueViews/ApIsolationIssueView.swift +++ b/NearDrop/IssueViews/ApIsolationIssueView.swift @@ -13,12 +13,38 @@ import Network struct ApIsolationIssueView: View { @Environment(\.colorScheme) var colorScheme + let closeView : () -> Void + + let scanner = DeviceToDeviceHeuristicScanner() var body: some View { IssueView(image: .router, header: "ApIsolationHeader".localized(), description: "ApIsolationDescription".localized(), actionLabel: "ApIsolationAction".localized()) { await openRouterSettingsPage() } + .onAppear { + checkIfApIsolationStillEnabled() + } + } + + func checkIfApIsolationStillEnabled() { + scanner.scan { isConnectionAllowed in + if isConnectionAllowed { + + log("AP Isolation is no longer enabled. Exiting...") + + DispatchQueue.main.async { + closeView() + } + } + else { + log("AP Isolation is still enabled. Checking again in 10 seconds...") + + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + checkIfApIsolationStillEnabled() + } + } + } } } @@ -121,7 +147,7 @@ func isHostReachable(_ host: String) -> Bool { #Preview { - ApIsolationIssueView() + ApIsolationIssueView(closeView: {}) .frame(width: issueViewWidth, height: issueViewHeight) } diff --git a/NearDrop/SelfTest/ApIsolationTester.swift b/NearDrop/SelfTest/ApIsolationTester.swift index a520168..d896f36 100644 --- a/NearDrop/SelfTest/ApIsolationTester.swift +++ b/NearDrop/SelfTest/ApIsolationTester.swift @@ -11,7 +11,6 @@ import Network class DeviceToDeviceHeuristicScanner { private let scanQueue = DispatchQueue(label: "DeviceToDeviceScanQueue") private var reachableIPs = [String]() - private var scannedCount = 0 private var totalToScan = 0 private var completion: ((Bool) -> Void)? @@ -30,10 +29,8 @@ class DeviceToDeviceHeuristicScanner { } // Timeout fallback - DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) { - if self.scannedCount < self.totalToScan { - self.finish() - } + DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) { + self.finish() } } @@ -45,11 +42,10 @@ class DeviceToDeviceHeuristicScanner { switch state { case .ready: self.reachableIPs.append(ip) + self.finish() connection.cancel() - self.hostFinished() case .failed, .cancelled: connection.cancel() - self.hostFinished() default: break } @@ -58,15 +54,9 @@ class DeviceToDeviceHeuristicScanner { connection.start(queue: scanQueue) } - private func hostFinished() { - scannedCount += 1 - if scannedCount == totalToScan { - finish() - } - } - private func finish() { completion?(reachableIPs.count > 0) + completion = nil } /// Attempts to detect the local subnet prefix (e.g., "192.168.0") diff --git a/NearDrop/WelcomeScreen.swift b/NearDrop/WelcomeScreen.swift index 0f812c2..222a08f 100644 --- a/NearDrop/WelcomeScreen.swift +++ b/NearDrop/WelcomeScreen.swift @@ -93,9 +93,6 @@ struct WelcomeScreen: View { case .troubleshooting: TutorialView(title: "Troubleshooting", text: "TroubleshootingDescription", showsLicense: false, openIAP: openPlusScreen) - .onAppear { - checkForNetworkIssues() - } case .app: TutorialView(title: "AndroidApp", text: "AndroidAppDescription", showsLicense: false, showsBetaJoinButton: true, openIAP: openPlusScreen)