From efa608888431f554e588047c5842dd6f51609f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 9 Mar 2026 13:17:48 +0800 Subject: [PATCH] Fix widget toggle not disabling On Demand before stopping VPN Store wasOnDemandEnabled flag in providerConfiguration so the widget can restore On Demand state on next start. Clear the flag when On Demand is explicitly disabled in settings or when starting from the main app. --- .../Views/Log/LogViewModel.swift | 2 +- Library/Network/ExtensionProfile.swift | 19 ++++++++++++++++++ WidgetExtension/WidgetTunnelControl.swift | 20 ++++++++++++++++++- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/ApplicationLibrary/Views/Log/LogViewModel.swift b/ApplicationLibrary/Views/Log/LogViewModel.swift index 4bf34ca..884da54 100644 --- a/ApplicationLibrary/Views/Log/LogViewModel.swift +++ b/ApplicationLibrary/Views/Log/LogViewModel.swift @@ -179,7 +179,7 @@ public class LogViewModel: BaseViewModel { public init(commandClient: CommandClient, searchText: String = "") { self.commandClient = commandClient self.searchText = searchText - self.isSearching = !searchText.isEmpty + isSearching = !searchText.isEmpty super.init() dataModel = LogDataModel(commandClient: commandClient, viewModel: self) } diff --git a/Library/Network/ExtensionProfile.swift b/Library/Network/ExtensionProfile.swift index 2a51960..b3b52bc 100644 --- a/Library/Network/ExtensionProfile.swift +++ b/Library/Network/ExtensionProfile.swift @@ -114,6 +114,14 @@ public class ExtensionProfile: ObservableObject { public func updateOnDemand(enabled: Bool, useDefaultRules: Bool) async throws { guard let manager else { return } manager.isOnDemandEnabled = enabled + if !enabled { + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + var config = proto.providerConfiguration ?? [:] + if config.removeValue(forKey: "wasOnDemandEnabled") != nil { + proto.providerConfiguration = config + } + } + } await setOnDemandRules(useDefaultRules: useDefaultRules) try await manager.saveToPreferences() } @@ -141,6 +149,12 @@ public class ExtensionProfile: ObservableObject { manager.isOnDemandEnabled = true await setOnDemandRules(useDefaultRules: alwaysOn) } + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + var config = proto.providerConfiguration ?? [:] + if config.removeValue(forKey: "wasOnDemandEnabled") != nil { + proto.providerConfiguration = config + } + } #if !os(tvOS) if let protocolConfiguration = manager.protocolConfiguration { let includeAllNetworks = await SharedPreferences.includeAllNetworks.get() @@ -239,6 +253,11 @@ public class ExtensionProfile: ObservableObject { } guard let manager else { return } if manager.isOnDemandEnabled { + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + var config = proto.providerConfiguration ?? [:] + config["wasOnDemandEnabled"] = true + proto.providerConfiguration = config + } manager.isOnDemandEnabled = false try await manager.saveToPreferences() } diff --git a/WidgetExtension/WidgetTunnelControl.swift b/WidgetExtension/WidgetTunnelControl.swift index 453ebb0..eddc985 100644 --- a/WidgetExtension/WidgetTunnelControl.swift +++ b/WidgetExtension/WidgetTunnelControl.swift @@ -51,8 +51,17 @@ enum WidgetTunnelControl { if started { if manager.isEnabled == false { manager.isEnabled = true - try await manager.saveToPreferences() } + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol, + let config = proto.providerConfiguration, + config["wasOnDemandEnabled"] as? Bool == true + { + var newConfig = config + newConfig.removeValue(forKey: "wasOnDemandEnabled") + proto.providerConfiguration = newConfig + manager.isOnDemandEnabled = true + } + try await manager.saveToPreferences() do { try manager.connection.startVPNTunnel() } catch { @@ -60,6 +69,15 @@ enum WidgetTunnelControl { throw error } } else { + if manager.isOnDemandEnabled { + if let proto = manager.protocolConfiguration as? NETunnelProviderProtocol { + var config = proto.providerConfiguration ?? [:] + config["wasOnDemandEnabled"] = true + proto.providerConfiguration = config + } + manager.isOnDemandEnabled = false + try await manager.saveToPreferences() + } manager.connection.stopVPNTunnel() } }