From f5e82dd2b0dba22e00f8428f8a3cc8dc5f1d21f8 Mon Sep 17 00:00:00 2001 From: DHR60 Date: Sun, 27 Jul 2025 18:34:30 +0800 Subject: [PATCH] Add Detour Feature --- v2rayN/ServiceLib/Models/CustomConfigItem.cs | 2 + v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 74 +++++--- v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx | 10 +- v2rayN/ServiceLib/Resx/ResUI.hu.resx | 10 +- v2rayN/ServiceLib/Resx/ResUI.resx | 10 +- v2rayN/ServiceLib/Resx/ResUI.ru.resx | 10 +- v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 10 +- v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx | 10 +- .../CoreConfig/CoreConfigSingboxService.cs | 132 +++++++-------- .../CoreConfig/CoreConfigV2rayService.cs | 160 +++++++++--------- .../ViewModels/CustomConfigViewModel.cs | 46 ++--- .../Views/CustomConfigWindow.axaml | 48 ++++++ .../Views/CustomConfigWindow.axaml.cs | 4 + v2rayN/v2rayN/Views/CustomConfigWindow.xaml | 54 ++++++ .../v2rayN/Views/CustomConfigWindow.xaml.cs | 4 + 15 files changed, 369 insertions(+), 215 deletions(-) diff --git a/v2rayN/ServiceLib/Models/CustomConfigItem.cs b/v2rayN/ServiceLib/Models/CustomConfigItem.cs index 23999af5..3d4b6453 100644 --- a/v2rayN/ServiceLib/Models/CustomConfigItem.cs +++ b/v2rayN/ServiceLib/Models/CustomConfigItem.cs @@ -13,4 +13,6 @@ public class CustomConfigItem public ECoreType CoreType { get; set; } public string? Config { get; set; } public string? TunConfig { get; set; } + public bool? AddProxyOnly { get; set; } = false; + public string? ProxyDetour { get; set; } } diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 0dbf61ec..dffc4a32 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -2247,6 +2247,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Do Not Add Non-Proxy Protocol Outbound 的本地化字符串。 + /// + public static string TbAddProxyProtocolOutboundOnly { + get { + return ResourceManager.GetString("TbAddProxyProtocolOutboundOnly", resourceCulture); + } + } + /// /// 查找类似 Address 的本地化字符串。 /// @@ -2382,24 +2391,6 @@ namespace ServiceLib.Resx { } } - /// - /// 查找类似 Enable Custom DNS 的本地化字符串。 - /// - public static string TbCustomDNSEnable { - get { - return ResourceManager.GetString("TbCustomDNSEnable", resourceCulture); - } - } - - /// - /// 查找类似 Custom DNS Enabled, This Page's Settings Invalid 的本地化字符串。 - /// - public static string TbCustomDNSEnabledPageInvalid { - get { - return ResourceManager.GetString("TbCustomDNSEnabledPageInvalid", resourceCulture); - } - } - /// /// 查找类似 Enable Custom Config 的本地化字符串。 /// @@ -2418,6 +2409,24 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Enable Custom DNS 的本地化字符串。 + /// + public static string TbCustomDNSEnable { + get { + return ResourceManager.GetString("TbCustomDNSEnable", resourceCulture); + } + } + + /// + /// 查找类似 Custom DNS Enabled, This Page's Settings Invalid 的本地化字符串。 + /// + public static string TbCustomDNSEnabledPageInvalid { + get { + return ResourceManager.GetString("TbCustomDNSEnabledPageInvalid", resourceCulture); + } + } + /// /// 查找类似 Display GUI 的本地化字符串。 /// @@ -2761,7 +2770,7 @@ namespace ServiceLib.Resx { } /// - /// 查找类似 Override Outbound Config, routing.balancers and routing.rules.outboundTag Only 的本地化字符串。 + /// 查找类似 Add Outbound Config Only, routing.balancers and routing.rules.outboundTag 的本地化字符串。 /// public static string TbRayCustomConfigDesc { get { @@ -2895,6 +2904,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Add Outbound and Endpoint Config Only 的本地化字符串。 + /// + public static string TbSBCustomConfigDesc { + get { + return ResourceManager.GetString("TbSBCustomConfigDesc", resourceCulture); + } + } + /// /// 查找类似 sing-box Direct Resolution Strategy 的本地化字符串。 /// @@ -2958,15 +2976,6 @@ namespace ServiceLib.Resx { } } - /// - /// 查找类似 Override Outbound And Endpoint Config Only 的本地化字符串。 - /// - public static string TbSBCustomConfigDesc { - get { - return ResourceManager.GetString("TbSBCustomConfigDesc", resourceCulture); - } - } - /// /// 查找类似 Encryption method (security) 的本地化字符串。 /// @@ -3750,6 +3759,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Set Upstream Proxy Tag 的本地化字符串。 + /// + public static string TbSetUpstreamProxyDetour { + get { + return ResourceManager.GetString("TbSetUpstreamProxyDetour", resourceCulture); + } + } + /// /// 查找类似 Short Id 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx index 8872bc5b..c13241a9 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx @@ -1483,9 +1483,15 @@ sing-box Custom Config - Override Outbound Config, routing.balancers and routing.rules.outboundTag Only + Add Outbound Config Only, routing.balancers and routing.rules.outboundTag - Override Outbound And Endpoint Config Only + Add Outbound and Endpoint Config Only + + + Do Not Add Non-Proxy Protocol Outbound + + + Set Upstream Proxy Tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx index 534512e0..85eeaa3c 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx @@ -1483,9 +1483,15 @@ sing-box Custom Config - Override Outbound Config, routing.balancers and routing.rules.outboundTag Only + Add Outbound Config Only, routing.balancers and routing.rules.outboundTag - Override Outbound And Endpoint Config Only + Add Outbound and Endpoint Config Only + + + Do Not Add Non-Proxy Protocol Outbound + + + Set Upstream Proxy Tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 10c9ff93..b8c73807 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1483,9 +1483,15 @@ sing-box Custom Config - Override Outbound Config, routing.balancers and routing.rules.outboundTag Only + Add Outbound Config Only, routing.balancers and routing.rules.outboundTag - Override Outbound And Endpoint Config Only + Add Outbound and Endpoint Config Only + + + Do Not Add Non-Proxy Protocol Outbound + + + Set Upstream Proxy Tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx index 4e2b7108..093e24de 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx @@ -1483,9 +1483,15 @@ sing-box Custom Config - Override Outbound Config, routing.balancers and routing.rules.outboundTag Only + Add Outbound Config Only, routing.balancers and routing.rules.outboundTag - Override Outbound And Endpoint Config Only + Add Outbound and Endpoint Config Only + + + Do Not Add Non-Proxy Protocol Outbound + + + Set Upstream Proxy Tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 67640a2c..cf62c182 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1480,9 +1480,15 @@ sing-box 自定义配置 - 仅覆盖出站配置,routing.balancers 和 routing.rules.outboundTag + 仅添加出站配置,routing.balancers 和 routing.rules.outboundTag - 仅覆盖出站和端点配置 + 仅添加出站和端点配置 + + + 不添加非代理协议出站 + + + 设置上游代理 tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx index 46226857..91fdcd74 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx @@ -1480,9 +1480,15 @@ sing-box Custom Config - Override Outbound Config, routing.balancers and routing.rules.outboundTag Only + Add Outbound Config Only, routing.balancers and routing.rules.outboundTag - Override Outbound And Endpoint Config Only + Add Outbound and Endpoint Config Only + + + Do Not Add Non-Proxy Protocol Outbound + + + Set Upstream Proxy Tag \ No newline at end of file diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs index 3494dcf0..7e9574fa 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigSingboxService.cs @@ -86,43 +86,7 @@ public class CoreConfigSingboxService ret.Success = true; var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box); - var customConfigItem = customConfig.Config; - if (_config.TunModeItem.EnableTun) - { - customConfigItem = customConfig.TunConfig; - } - if (customConfig.Enabled && (!customConfigItem.IsNullOrEmpty())) - { - var customConfigNode = JsonNode.Parse(customConfigItem); - if (customConfigNode != null) - { - if (customConfigNode["outbounds"] is JsonArray customOutboundsNode) - { - if (JsonNode.Parse(JsonUtils.Serialize(singboxConfig.outbounds)) is JsonArray newOutbounds) - { - foreach (var outbound in newOutbounds) - { - customOutboundsNode.Add(outbound?.DeepClone()); - } - } - } - if (customConfigNode["endpoints"] is JsonArray customEndpointsNode) - { - if (singboxConfig.endpoints != null && JsonNode.Parse(JsonUtils.Serialize(singboxConfig.endpoints)) is JsonArray newEndpoints) - { - foreach (var endpoint in newEndpoints) - { - customEndpointsNode.Add(endpoint?.DeepClone()); - } - } - } - ret.Data = JsonUtils.Serialize(customConfigNode); - } - } - else - { - ret.Data = JsonUtils.Serialize(singboxConfig); - } + ret.Data = await ApplyCustomConfig(customConfig, singboxConfig); return ret; } catch (Exception ex) @@ -476,43 +440,7 @@ public class CoreConfigSingboxService ret.Success = true; var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box); - var customConfigItem = customConfig.Config; - if (_config.TunModeItem.EnableTun) - { - customConfigItem = customConfig.TunConfig; - } - if (customConfig.Enabled && (!customConfigItem.IsNullOrEmpty())) - { - var customConfigNode = JsonNode.Parse(customConfigItem); - if (customConfigNode != null) - { - if (customConfigNode["outbounds"] is JsonArray customOutboundsNode) - { - if (JsonNode.Parse(JsonUtils.Serialize(singboxConfig.outbounds)) is JsonArray newOutbounds) - { - foreach (var outbound in newOutbounds) - { - customOutboundsNode.Add(outbound?.DeepClone()); - } - } - } - if (customConfigNode["endpoints"] is JsonArray customEndpointsNode) - { - if (singboxConfig.endpoints != null && JsonNode.Parse(JsonUtils.Serialize(singboxConfig.endpoints)) is JsonArray newEndpoints) - { - foreach (var endpoint in newEndpoints) - { - customEndpointsNode.Add(endpoint?.DeepClone()); - } - } - } - ret.Data = JsonUtils.Serialize(customConfigNode); - } - } - else - { - ret.Data = JsonUtils.Serialize(singboxConfig); - } + ret.Data = await ApplyCustomConfig(customConfig, singboxConfig); return ret; } catch (Exception ex) @@ -2277,5 +2205,61 @@ public class CoreConfigSingboxService return 0; } + private async Task ApplyCustomConfig(CustomConfigItem customConfig, SingboxConfig singboxConfig) + { + var customConfigItem = customConfig.Config; + if (_config.TunModeItem.EnableTun) + { + customConfigItem = customConfig.TunConfig; + } + + if (!customConfig.Enabled || customConfigItem.IsNullOrEmpty()) + { + return JsonUtils.Serialize(singboxConfig); + } + + var customConfigNode = JsonNode.Parse(customConfigItem); + if (customConfigNode == null) + { + return JsonUtils.Serialize(singboxConfig); + } + + // Process outbounds + var customOutboundsNode = customConfigNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray(); + foreach (var outbound in singboxConfig.outbounds) + { + if (outbound.type.ToLower() is "direct" or "block") + { + if (customConfig.AddProxyOnly == true) + { + continue; + } + } + else if (outbound.detour.IsNullOrEmpty() && (!customConfig.ProxyDetour.IsNullOrEmpty())) + { + outbound.detour = customConfig.ProxyDetour; + } + customOutboundsNode.Add(JsonUtils.DeepCopy(outbound)); + } + customConfigNode["outbounds"] = customOutboundsNode; + + // Process endpoints + if (singboxConfig.endpoints != null && singboxConfig.endpoints.Count > 0) + { + var customEndpointsNode = customConfigNode["endpoints"] is JsonArray endpoints ? endpoints : new JsonArray(); + foreach (var endpoint in singboxConfig.endpoints) + { + if (endpoint.detour.IsNullOrEmpty() && (!customConfig.ProxyDetour.IsNullOrEmpty())) + { + endpoint.detour = customConfig.ProxyDetour; + } + customEndpointsNode.Add(JsonUtils.DeepCopy(endpoint)); + } + customConfigNode["endpoints"] = customEndpointsNode; + } + + return await Task.FromResult(JsonUtils.Serialize(customConfigNode)); + } + #endregion private gen function } diff --git a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs index 2c0e53d3..b332381d 100644 --- a/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs +++ b/v2rayN/ServiceLib/Services/CoreConfig/CoreConfigV2rayService.cs @@ -71,28 +71,7 @@ public class CoreConfigV2rayService ret.Success = true; var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray); - if (customConfig.Enabled && (!customConfig.Config.IsNullOrEmpty())) - { - var customConfigNode = JsonNode.Parse(customConfig.Config); - if (customConfigNode != null) - { - if (customConfigNode["outbounds"] is JsonArray customOutboundsNode) - { - if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.outbounds)) is JsonArray newOutbounds) - { - foreach (var outbound in newOutbounds) - { - customOutboundsNode.Add(outbound?.DeepClone()); - } - } - } - ret.Data = JsonUtils.Serialize(customConfigNode); - } - } - else - { - ret.Data = JsonUtils.Serialize(v2rayConfig); - } + ret.Data = await ApplyCustomConfig(customConfig, v2rayConfig); return ret; } catch (Exception ex) @@ -223,64 +202,7 @@ public class CoreConfigV2rayService ret.Success = true; var customConfig = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray); - if (customConfig.Enabled && (!customConfig.Config.IsNullOrEmpty())) - { - var customConfigNode = JsonNode.Parse(customConfig.Config); - if (customConfigNode != null) - { - var rulesNode = customConfigNode["routing"]?["rules"]; - if (rulesNode != null) - { - foreach (var rule in rulesNode.AsArray()) - { - if (rule["outboundTag"]?.GetValue() == Global.ProxyTag) - { - rule["outboundTag"] = null; - rule["balancerTag"] = balancer.tag; - } - } - } - - // Ensure routing node exists - if (customConfigNode["routing"] == null) - { - customConfigNode["routing"] = new JsonObject(); - } - - // Handle balancers - append instead of override - if (customConfigNode["routing"]["balancers"] is JsonArray customBalancersNode) - { - if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers) - { - foreach (var balancerNode in newBalancers) - { - customBalancersNode.Add(balancerNode?.DeepClone()); - } - } - } - else - { - customConfigNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)); - } - - // append outbounds instead of override - if (customConfigNode["outbounds"] is JsonArray customOutboundsNode) - { - if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.outbounds)) is JsonArray newOutbounds) - { - foreach (var outbound in newOutbounds) - { - customOutboundsNode.Add(outbound?.DeepClone()); - } - } - } - ret.Data = JsonUtils.Serialize(customConfigNode); - } - } - else - { - ret.Data = JsonUtils.Serialize(v2rayConfig); - } + ret.Data = await ApplyCustomConfig(customConfig, v2rayConfig, true); return ret; } catch (Exception ex) @@ -1921,5 +1843,83 @@ public class CoreConfigV2rayService return await Task.FromResult(0); } + private async Task ApplyCustomConfig(CustomConfigItem customConfig, V2rayConfig v2rayConfig, bool handleBalancerAndRules = false) + { + if (!customConfig.Enabled || customConfig.Config.IsNullOrEmpty()) + { + return JsonUtils.Serialize(v2rayConfig); + } + + var customConfigNode = JsonNode.Parse(customConfig.Config); + if (customConfigNode == null) + { + return JsonUtils.Serialize(v2rayConfig); + } + + // Handle balancer and rules modifications (for multiple load scenarios) + if (handleBalancerAndRules && v2rayConfig.routing?.balancers?.Count > 0) + { + var balancer = v2rayConfig.routing.balancers.First(); + + // Modify existing rules in custom config + var rulesNode = customConfigNode["routing"]?["rules"]; + if (rulesNode != null) + { + foreach (var rule in rulesNode.AsArray()) + { + if (rule["outboundTag"]?.GetValue() == Global.ProxyTag) + { + rule.AsObject().Remove("outboundTag"); + rule["balancerTag"] = balancer.tag; + } + } + } + + // Ensure routing node exists + if (customConfigNode["routing"] == null) + { + customConfigNode["routing"] = new JsonObject(); + } + + // Handle balancers - append instead of override + if (customConfigNode["routing"]["balancers"] is JsonArray customBalancersNode) + { + if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers) + { + foreach (var balancerNode in newBalancers) + { + customBalancersNode.Add(balancerNode?.DeepClone()); + } + } + } + else + { + customConfigNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)); + } + } + + // Handle outbounds - append instead of override + var customOutboundsNode = customConfigNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray(); + foreach (var outbound in v2rayConfig.outbounds) + { + if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom") + { + if (customConfig.AddProxyOnly == true) + { + continue; + } + } + else if ((outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == true) && (!customConfig.ProxyDetour.IsNullOrEmpty())) + { + outbound.streamSettings ??= new StreamSettings4Ray(); + outbound.streamSettings.sockopt ??= new Sockopt4Ray(); + outbound.streamSettings.sockopt.dialerProxy = customConfig.ProxyDetour; + } + customOutboundsNode.Add(JsonUtils.DeepCopy(outbound)); + } + + return await Task.FromResult(JsonUtils.Serialize(customConfigNode)); + } + #endregion private gen function } diff --git a/v2rayN/ServiceLib/ViewModels/CustomConfigViewModel.cs b/v2rayN/ServiceLib/ViewModels/CustomConfigViewModel.cs index 74527d24..75d7d5be 100644 --- a/v2rayN/ServiceLib/ViewModels/CustomConfigViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/CustomConfigViewModel.cs @@ -22,6 +22,18 @@ public class CustomConfigViewModel : MyReactiveObject [Reactive] public string CustomTunConfig4Singbox { get; set; } + [Reactive] + public bool AddProxyOnly4Ray { get; set; } + + [Reactive] + public bool AddProxyOnly4Singbox { get; set; } + + [Reactive] + public string ProxyDetour4Ray { get; set; } + + [Reactive] + public string ProxyDetour4Singbox { get; set; } + public ReactiveCommand SaveCmd { get; } #endregion Reactive @@ -41,11 +53,15 @@ public class CustomConfigViewModel : MyReactiveObject var item = await AppHandler.Instance.GetCustomConfigItem(ECoreType.Xray); EnableCustomConfig4Ray = item?.Enabled ?? false; CustomConfig4Ray = item?.Config ?? string.Empty; + AddProxyOnly4Ray = item?.AddProxyOnly ?? false; + ProxyDetour4Ray = item?.ProxyDetour ?? string.Empty; var item2 = await AppHandler.Instance.GetCustomConfigItem(ECoreType.sing_box); EnableCustomConfig4Singbox = item2?.Enabled ?? false; CustomConfig4Singbox = item2?.Config ?? string.Empty; CustomTunConfig4Singbox = item2?.TunConfig ?? string.Empty; + AddProxyOnly4Singbox = item2?.AddProxyOnly ?? false; + ProxyDetour4Singbox = item2?.ProxyDetour ?? string.Empty; } private async Task SaveSettingAsync() @@ -66,10 +82,10 @@ public class CustomConfigViewModel : MyReactiveObject item.Enabled = EnableCustomConfig4Ray; item.Config = null; - if (CustomConfig4Ray.IsNotEmpty()) - { - item.Config = CustomConfig4Ray; - } + item.Config = CustomConfig4Ray; + + item.AddProxyOnly = AddProxyOnly4Ray; + item.ProxyDetour = ProxyDetour4Ray; await ConfigHandler.SaveCustomConfigItem(_config, item); return true; @@ -82,25 +98,13 @@ public class CustomConfigViewModel : MyReactiveObject item.Config = null; item.TunConfig = null; - var hasChanges = false; + item.Config = CustomConfig4Singbox; + item.TunConfig = CustomTunConfig4Singbox; - if (CustomConfig4Singbox.IsNotEmpty()) - { - item.Config = CustomConfig4Singbox; - hasChanges = true; - } - - if (CustomTunConfig4Singbox.IsNotEmpty()) - { - item.TunConfig = CustomTunConfig4Singbox; - hasChanges = true; - } - - if (hasChanges) - { - await ConfigHandler.SaveCustomConfigItem(_config, item); - } + item.AddProxyOnly = AddProxyOnly4Singbox; + item.ProxyDetour = ProxyDetour4Singbox; + await ConfigHandler.SaveCustomConfigItem(_config, item); return true; } } diff --git a/v2rayN/v2rayN.Desktop/Views/CustomConfigWindow.axaml b/v2rayN/v2rayN.Desktop/Views/CustomConfigWindow.axaml index 97e89631..fcfedfe7 100644 --- a/v2rayN/v2rayN.Desktop/Views/CustomConfigWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/CustomConfigWindow.axaml @@ -59,6 +59,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + { this.Bind(ViewModel, vm => vm.EnableCustomConfig4Ray, v => v.rayCustomConfigEnable.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomConfig4Ray, v => v.rayCustomConfig.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableCustomConfig4Singbox, v => v.sbCustomConfigEnable.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomConfig4Singbox, v => v.sbCustomConfig.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomTunConfig4Singbox, v => v.sbCustomTunConfig.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); diff --git a/v2rayN/v2rayN/Views/CustomConfigWindow.xaml b/v2rayN/v2rayN/Views/CustomConfigWindow.xaml index 99a99a28..3ec9b725 100644 --- a/v2rayN/v2rayN/Views/CustomConfigWindow.xaml +++ b/v2rayN/v2rayN/Views/CustomConfigWindow.xaml @@ -71,6 +71,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v2rayN/v2rayN/Views/CustomConfigWindow.xaml.cs b/v2rayN/v2rayN/Views/CustomConfigWindow.xaml.cs index 57258759..6fe48dc9 100644 --- a/v2rayN/v2rayN/Views/CustomConfigWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/CustomConfigWindow.xaml.cs @@ -21,9 +21,13 @@ public partial class CustomConfigWindow { this.Bind(ViewModel, vm => vm.EnableCustomConfig4Ray, v => v.rayCustomConfigEnable.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomConfig4Ray, v => v.rayCustomConfig.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableCustomConfig4Singbox, v => v.sbCustomConfigEnable.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomConfig4Singbox, v => v.sbCustomConfig.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CustomTunConfig4Singbox, v => v.sbCustomTunConfig.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); });