mirror of
https://github.com/2dust/v2rayN.git
synced 2025-12-23 15:22:43 +00:00
Compare commits
3 commits
91bca3a7ae
...
10358064dc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10358064dc | ||
|
|
6a19896915 | ||
|
|
07e173eab1 |
29 changed files with 346 additions and 162 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.15.4</Version>
|
<Version>7.15.5</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,110 @@ public class Utils
|
||||||
return userHostsMap;
|
return userHostsMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parse a possibly non-standard URL into scheme, domain, port, and path.
|
||||||
|
/// If parsing fails, the entire input is returned as domain, and others are empty or zero.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">Input URL or string</param>
|
||||||
|
/// <returns>(domain, scheme, port, path)</returns>
|
||||||
|
public static (string domain, string scheme, int port, string path) ParseUrl(string url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(url))
|
||||||
|
{
|
||||||
|
return ("", "", 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. First, try to parse using the standard Uri class.
|
||||||
|
if (Uri.TryCreate(url, UriKind.Absolute, out var uri) && !string.IsNullOrEmpty(uri.Host))
|
||||||
|
{
|
||||||
|
var scheme = uri.Scheme;
|
||||||
|
var domain = uri.Host;
|
||||||
|
var port = uri.IsDefaultPort ? 0 : uri.Port;
|
||||||
|
var path = uri.PathAndQuery;
|
||||||
|
return (domain, scheme, port, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try to handle more general cases with a regular expression, including non-standard schemes.
|
||||||
|
// This regex captures the scheme (optional), authority (host+port), and path (optional).
|
||||||
|
var match = Regex.Match(url, @"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):/{2,})?([^/?#]+)([^?#]*)?.*$");
|
||||||
|
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
var scheme = match.Groups[1].Value;
|
||||||
|
var authority = match.Groups[2].Value;
|
||||||
|
var path = match.Groups[3].Value;
|
||||||
|
|
||||||
|
// Remove userinfo from the authority part.
|
||||||
|
var atIndex = authority.LastIndexOf('@');
|
||||||
|
if (atIndex > 0)
|
||||||
|
{
|
||||||
|
authority = authority.Substring(atIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var (domain, port) = ParseAuthority(authority);
|
||||||
|
|
||||||
|
// If the parsed domain is empty, it means the authority part is malformed, so trigger the fallback.
|
||||||
|
if (!string.IsNullOrEmpty(domain))
|
||||||
|
{
|
||||||
|
return (domain, scheme, port, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. If all of the above fails, execute the final fallback strategy.
|
||||||
|
return (url, "", 0, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper function to parse domain and port from the authority part, with correct handling for IPv6.
|
||||||
|
/// </summary>
|
||||||
|
private static (string domain, int port) ParseAuthority(string authority)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(authority))
|
||||||
|
{
|
||||||
|
return ("", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var port = 0;
|
||||||
|
var domain = authority;
|
||||||
|
|
||||||
|
// Handle IPv6 addresses, e.g., "[2001:db8::1]:443"
|
||||||
|
if (authority.StartsWith("[") && authority.Contains("]"))
|
||||||
|
{
|
||||||
|
int closingBracketIndex = authority.LastIndexOf(']');
|
||||||
|
if (closingBracketIndex < authority.Length - 1 && authority[closingBracketIndex + 1] == ':')
|
||||||
|
{
|
||||||
|
// Port exists
|
||||||
|
var portStr = authority.Substring(closingBracketIndex + 2);
|
||||||
|
if (int.TryParse(portStr, out var portNum))
|
||||||
|
{
|
||||||
|
port = portNum;
|
||||||
|
}
|
||||||
|
domain = authority.Substring(0, closingBracketIndex + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No port
|
||||||
|
domain = authority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Handle IPv4 or domain names
|
||||||
|
{
|
||||||
|
var lastColonIndex = authority.LastIndexOf(':');
|
||||||
|
// Ensure there are digits after the colon and that this colon is not part of an IPv6 address.
|
||||||
|
if (lastColonIndex > 0 && lastColonIndex < authority.Length - 1 && authority.Substring(lastColonIndex + 1).All(char.IsDigit))
|
||||||
|
{
|
||||||
|
var portStr = authority.Substring(lastColonIndex + 1);
|
||||||
|
if (int.TryParse(portStr, out var portNum))
|
||||||
|
{
|
||||||
|
port = portNum;
|
||||||
|
domain = authority.Substring(0, lastColonIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (domain, port);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion 转换函数
|
#endregion 转换函数
|
||||||
|
|
||||||
#region 数据检查
|
#region 数据检查
|
||||||
|
|
|
||||||
|
|
@ -112,10 +112,8 @@ public static class ConfigHandler
|
||||||
config.ConstItem ??= new ConstItem();
|
config.ConstItem ??= new ConstItem();
|
||||||
|
|
||||||
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
||||||
if (config.SimpleDNSItem.GlobalFakeIp is null)
|
config.SimpleDNSItem.GlobalFakeIp ??= true;
|
||||||
{
|
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
||||||
config.SimpleDNSItem.GlobalFakeIp = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
|
|
@ -2273,6 +2271,7 @@ public static class ConfigHandler
|
||||||
BlockBindingQuery = true,
|
BlockBindingQuery = true,
|
||||||
DirectDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
|
DirectDNS = Global.DomainDirectDNSAddress.FirstOrDefault(),
|
||||||
RemoteDNS = Global.DomainRemoteDNSAddress.FirstOrDefault(),
|
RemoteDNS = Global.DomainRemoteDNSAddress.FirstOrDefault(),
|
||||||
|
BootstrapDNS = Global.DomainPureIPDNSAddress.FirstOrDefault(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,7 @@ public class SimpleDNSItem
|
||||||
public bool? BlockBindingQuery { get; set; }
|
public bool? BlockBindingQuery { get; set; }
|
||||||
public string? DirectDNS { get; set; }
|
public string? DirectDNS { get; set; }
|
||||||
public string? RemoteDNS { get; set; }
|
public string? RemoteDNS { get; set; }
|
||||||
|
public string? BootstrapDNS { get; set; }
|
||||||
public string? RayStrategy4Freedom { get; set; }
|
public string? RayStrategy4Freedom { get; set; }
|
||||||
public string? SingboxStrategy4Direct { get; set; }
|
public string? SingboxStrategy4Direct { get; set; }
|
||||||
public string? SingboxStrategy4Proxy { get; set; }
|
public string? SingboxStrategy4Proxy { get; set; }
|
||||||
|
|
|
||||||
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
18
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
|
@ -2517,6 +2517,24 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Bootstrap DNS 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbBootstrapDNS {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbBootstrapDNS", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Resolve DNS server domains, requires IP 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbBootstrapDNSTips {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbBootstrapDNSTips", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Browse 的本地化字符串。
|
/// 查找类似 Browse 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1590,4 +1590,10 @@
|
||||||
<data name="TbRuleTypeTips" xml:space="preserve">
|
<data name="TbRuleTypeTips" xml:space="preserve">
|
||||||
<value>You can set separate rules for Routing and DNS, or select "ALL" to apply to both</value>
|
<value>You can set separate rules for Routing and DNS, or select "ALL" to apply to both</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1590,4 +1590,10 @@
|
||||||
<data name="TbRuleType" xml:space="preserve">
|
<data name="TbRuleType" xml:space="preserve">
|
||||||
<value>Rule Type</value>
|
<value>Rule Type</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1590,4 +1590,10 @@
|
||||||
<data name="TbRuleType" xml:space="preserve">
|
<data name="TbRuleType" xml:space="preserve">
|
||||||
<value>Rule Type</value>
|
<value>Rule Type</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1590,4 +1590,10 @@
|
||||||
<data name="TbRuleType" xml:space="preserve">
|
<data name="TbRuleType" xml:space="preserve">
|
||||||
<value>Rule Type</value>
|
<value>Rule Type</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1587,4 +1587,10 @@
|
||||||
<data name="TbRuleTypeTips" xml:space="preserve">
|
<data name="TbRuleTypeTips" xml:space="preserve">
|
||||||
<value>可对 Routing 和 DNS 单独设定规则,ALL 则都生效</value>
|
<value>可对 Routing 和 DNS 单独设定规则,ALL 则都生效</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>解析 DNS 服务器域名,需指定为 IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -1587,4 +1587,10 @@
|
||||||
<data name="TbRuleTypeTips" xml:space="preserve">
|
<data name="TbRuleTypeTips" xml:space="preserve">
|
||||||
<value>可对 Routing 和 DNS 单独设定规则,ALL 则都生效</value>
|
<value>可对 Routing 和 DNS 单独设定规则,ALL 则都生效</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbBootstrapDNS" xml:space="preserve">
|
||||||
|
<value>Bootstrap DNS</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbBootstrapDNSTips" xml:space="preserve">
|
||||||
|
<value>Resolve DNS server domains, requires IP</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -138,12 +138,7 @@ public partial class CoreConfigSingboxService
|
||||||
|
|
||||||
private async Task<Server4Sbox> GenDnsDomains(SingboxConfig singboxConfig, SimpleDNSItem? simpleDNSItem)
|
private async Task<Server4Sbox> GenDnsDomains(SingboxConfig singboxConfig, SimpleDNSItem? simpleDNSItem)
|
||||||
{
|
{
|
||||||
var finalDnsAddress = "local";
|
var finalDns = ParseDnsAddress(simpleDNSItem.BootstrapDNS);
|
||||||
if (_config.TunModeItem.EnableTun)
|
|
||||||
{
|
|
||||||
finalDnsAddress = "dhcp://auto";
|
|
||||||
}
|
|
||||||
var finalDns = ParseDnsAddress(finalDnsAddress);
|
|
||||||
finalDns.tag = Global.SingboxLocalDNSTag;
|
finalDns.tag = Global.SingboxLocalDNSTag;
|
||||||
singboxConfig.dns ??= new Dns4Sbox();
|
singboxConfig.dns ??= new Dns4Sbox();
|
||||||
singboxConfig.dns.servers ??= new List<Server4Sbox>();
|
singboxConfig.dns.servers ??= new List<Server4Sbox>();
|
||||||
|
|
@ -459,15 +454,19 @@ public partial class CoreConfigSingboxService
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addressFirst.StartsWith("dhcp://", StringComparison.OrdinalIgnoreCase))
|
var (domain, scheme, port, path) = Utils.ParseUrl(addressFirst);
|
||||||
|
|
||||||
|
if (scheme.Equals("dhcp", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var interface_name = addressFirst.Substring(7);
|
|
||||||
server.type = "dhcp";
|
server.type = "dhcp";
|
||||||
server.Interface = interface_name == "auto" ? null : interface_name;
|
if ((!domain.IsNullOrEmpty()) && domain != "auto")
|
||||||
|
{
|
||||||
|
server.server = domain;
|
||||||
|
}
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!addressFirst.Contains("://"))
|
if (scheme.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
// udp dns
|
// udp dns
|
||||||
server.type = "udp";
|
server.type = "udp";
|
||||||
|
|
@ -475,63 +474,19 @@ public partial class CoreConfigSingboxService
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
//server.type = scheme.ToLower();
|
||||||
|
// remove "+local" suffix
|
||||||
|
// TODO: "+local" suffix decide server.detour = "direct" ?
|
||||||
|
server.type = scheme.Replace("+local", "", StringComparison.OrdinalIgnoreCase).ToLower();
|
||||||
|
server.server = domain;
|
||||||
|
if (port != 0)
|
||||||
{
|
{
|
||||||
var protocolEndIndex = addressFirst.IndexOf("://", StringComparison.Ordinal);
|
server.server_port = port;
|
||||||
server.type = addressFirst.Substring(0, protocolEndIndex).ToLower();
|
|
||||||
|
|
||||||
var uri = new Uri(addressFirst);
|
|
||||||
server.server = uri.Host;
|
|
||||||
|
|
||||||
if (!uri.IsDefaultPort)
|
|
||||||
{
|
|
||||||
server.server_port = uri.Port;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((server.type == "https" || server.type == "h3") && !string.IsNullOrEmpty(uri.AbsolutePath) && uri.AbsolutePath != "/")
|
|
||||||
{
|
|
||||||
server.path = uri.AbsolutePath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (UriFormatException)
|
if ((server.type == "https" || server.type == "h3") && !string.IsNullOrEmpty(path) && path != "/")
|
||||||
{
|
{
|
||||||
var protocolEndIndex = addressFirst.IndexOf("://", StringComparison.Ordinal);
|
server.path = path;
|
||||||
if (protocolEndIndex > 0)
|
|
||||||
{
|
|
||||||
server.type = addressFirst.Substring(0, protocolEndIndex).ToLower();
|
|
||||||
var remaining = addressFirst.Substring(protocolEndIndex + 3);
|
|
||||||
|
|
||||||
var portIndex = remaining.IndexOf(':');
|
|
||||||
var pathIndex = remaining.IndexOf('/');
|
|
||||||
|
|
||||||
if (portIndex > 0)
|
|
||||||
{
|
|
||||||
server.server = remaining.Substring(0, portIndex);
|
|
||||||
var portPart = pathIndex > portIndex
|
|
||||||
? remaining.Substring(portIndex + 1, pathIndex - portIndex - 1)
|
|
||||||
: remaining.Substring(portIndex + 1);
|
|
||||||
|
|
||||||
if (int.TryParse(portPart, out var parsedPort))
|
|
||||||
{
|
|
||||||
server.server_port = parsedPort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pathIndex > 0)
|
|
||||||
{
|
|
||||||
server.server = remaining.Substring(0, pathIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
server.server = remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathIndex > 0 && (server.type == "https" || server.type == "h3"))
|
|
||||||
{
|
|
||||||
server.path = remaining.Substring(pathIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,35 @@ public partial class CoreConfigV2rayService
|
||||||
var expectedIPs = new List<string>();
|
var expectedIPs = new List<string>();
|
||||||
var regionNames = new HashSet<string>();
|
var regionNames = new HashSet<string>();
|
||||||
|
|
||||||
|
var bootstrapDNSAddress = ParseDnsAddresses(simpleDNSItem?.BootstrapDNS, Global.DomainPureIPDNSAddress.FirstOrDefault());
|
||||||
|
var dnsServerDomains = new List<string>();
|
||||||
|
|
||||||
|
foreach (var dns in directDNSAddress)
|
||||||
|
{
|
||||||
|
var (domain, _, _, _) = Utils.ParseUrl(dns);
|
||||||
|
if (domain == "localhost")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Utils.IsDomain(domain))
|
||||||
|
{
|
||||||
|
dnsServerDomains.Add($"full:{domain}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var dns in remoteDNSAddress)
|
||||||
|
{
|
||||||
|
var (domain, _, _, _) = Utils.ParseUrl(dns);
|
||||||
|
if (domain == "localhost")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Utils.IsDomain(domain))
|
||||||
|
{
|
||||||
|
dnsServerDomains.Add($"full:{domain}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dnsServerDomains = dnsServerDomains.Distinct().ToList();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs))
|
if (!string.IsNullOrEmpty(simpleDNSItem?.DirectExpectedIPs))
|
||||||
{
|
{
|
||||||
expectedIPs = simpleDNSItem.DirectExpectedIPs
|
expectedIPs = simpleDNSItem.DirectExpectedIPs
|
||||||
|
|
@ -217,6 +246,10 @@ public partial class CoreConfigV2rayService
|
||||||
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||||
AddDnsServers(directDNSAddress, directGeositeList);
|
AddDnsServers(directDNSAddress, directGeositeList);
|
||||||
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
|
AddDnsServers(directDNSAddress, expectedDomainList, expectedIPs);
|
||||||
|
if (dnsServerDomains.Count > 0)
|
||||||
|
{
|
||||||
|
AddDnsServers(bootstrapDNSAddress, dnsServerDomains);
|
||||||
|
}
|
||||||
|
|
||||||
var useDirectDns = rules?.LastOrDefault() is { } lastRule
|
var useDirectDns = rules?.LastOrDefault() is { } lastRule
|
||||||
&& lastRule.OutboundTag == Global.DirectTag
|
&& lastRule.OutboundTag == Global.DirectTag
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ public class DNSSettingViewModel : MyReactiveObject
|
||||||
[Reactive] public bool? BlockBindingQuery { get; set; }
|
[Reactive] public bool? BlockBindingQuery { get; set; }
|
||||||
[Reactive] public string? DirectDNS { get; set; }
|
[Reactive] public string? DirectDNS { get; set; }
|
||||||
[Reactive] public string? RemoteDNS { get; set; }
|
[Reactive] public string? RemoteDNS { get; set; }
|
||||||
|
[Reactive] public string? BootstrapDNS { get; set; }
|
||||||
[Reactive] public string? RayStrategy4Freedom { get; set; }
|
[Reactive] public string? RayStrategy4Freedom { get; set; }
|
||||||
[Reactive] public string? SingboxStrategy4Direct { get; set; }
|
[Reactive] public string? SingboxStrategy4Direct { get; set; }
|
||||||
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
|
[Reactive] public string? SingboxStrategy4Proxy { get; set; }
|
||||||
|
|
@ -68,6 +69,7 @@ public class DNSSettingViewModel : MyReactiveObject
|
||||||
BlockBindingQuery = item.BlockBindingQuery;
|
BlockBindingQuery = item.BlockBindingQuery;
|
||||||
DirectDNS = item.DirectDNS;
|
DirectDNS = item.DirectDNS;
|
||||||
RemoteDNS = item.RemoteDNS;
|
RemoteDNS = item.RemoteDNS;
|
||||||
|
BootstrapDNS = item.BootstrapDNS;
|
||||||
RayStrategy4Freedom = item.RayStrategy4Freedom;
|
RayStrategy4Freedom = item.RayStrategy4Freedom;
|
||||||
SingboxStrategy4Direct = item.SingboxStrategy4Direct;
|
SingboxStrategy4Direct = item.SingboxStrategy4Direct;
|
||||||
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
|
SingboxStrategy4Proxy = item.SingboxStrategy4Proxy;
|
||||||
|
|
@ -97,6 +99,7 @@ public class DNSSettingViewModel : MyReactiveObject
|
||||||
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
_config.SimpleDNSItem.BlockBindingQuery = BlockBindingQuery;
|
||||||
_config.SimpleDNSItem.DirectDNS = DirectDNS;
|
_config.SimpleDNSItem.DirectDNS = DirectDNS;
|
||||||
_config.SimpleDNSItem.RemoteDNS = RemoteDNS;
|
_config.SimpleDNSItem.RemoteDNS = RemoteDNS;
|
||||||
|
_config.SimpleDNSItem.BootstrapDNS = BootstrapDNS;
|
||||||
_config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom;
|
_config.SimpleDNSItem.RayStrategy4Freedom = RayStrategy4Freedom;
|
||||||
_config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
|
_config.SimpleDNSItem.SingboxStrategy4Direct = SingboxStrategy4Direct;
|
||||||
_config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
|
_config.SimpleDNSItem.SingboxStrategy4Proxy = SingboxStrategy4Proxy;
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,6 @@
|
||||||
Name="v2rayN"
|
Name="v2rayN"
|
||||||
x:DataType="vms:StatusBarViewModel"
|
x:DataType="vms:StatusBarViewModel"
|
||||||
RequestedThemeVariant="Default">
|
RequestedThemeVariant="Default">
|
||||||
<Application.Styles>
|
|
||||||
<semi:SemiTheme />
|
|
||||||
<semi:AvaloniaEditSemiTheme />
|
|
||||||
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
|
||||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
|
||||||
<dialogHost:DialogHostStyles />
|
|
||||||
</Application.Styles>
|
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
|
@ -23,6 +16,13 @@
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
<Application.Styles>
|
||||||
|
<semi:SemiTheme />
|
||||||
|
<semi:AvaloniaEditSemiTheme />
|
||||||
|
<StyleInclude Source="Assets/GlobalStyles.axaml" />
|
||||||
|
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||||
|
<dialogHost:DialogHostStyles />
|
||||||
|
</Application.Styles>
|
||||||
|
|
||||||
<TrayIcon.Icons>
|
<TrayIcon.Icons>
|
||||||
<TrayIcons>
|
<TrayIcons>
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
<Style Selector="PathIcon">
|
<Style Selector="PathIcon">
|
||||||
<Setter Property="Width" Value="16" />
|
<Setter Property="Width" Value="16" />
|
||||||
<Setter Property="Height" Value="16" />
|
<Setter Property="Height" Value="16" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style Selector="TextBox">
|
<Style Selector="TextBox">
|
||||||
|
|
@ -26,4 +27,12 @@
|
||||||
<Style Selector="TabControl">
|
<Style Selector="TabControl">
|
||||||
<Setter Property="Theme" Value="{StaticResource LineTabControl}" />
|
<Setter Property="Theme" Value="{StaticResource LineTabControl}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Button.IconButton">
|
||||||
|
<Setter Property="Width" Value="{StaticResource IconButtonWidth}" />
|
||||||
|
<Setter Property="Height" Value="{StaticResource IconButtonHeight}" />
|
||||||
|
<Setter Property="MinWidth" Value="{StaticResource IconButtonWidth}" />
|
||||||
|
<Setter Property="Theme" Value="{DynamicResource BorderlessButton}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
</Styles>
|
</Styles>
|
||||||
|
|
|
||||||
|
|
@ -607,12 +607,14 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnExtra"
|
x:Name="btnExtra"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
Classes="IconButton"
|
||||||
Height="{StaticResource IconButtonHeight}"
|
Margin="{StaticResource MarginLr8}">
|
||||||
Margin="{StaticResource MarginLr8}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconMore}" >
|
||||||
|
<PathIcon.RenderTransform>
|
||||||
|
<RotateTransform Angle="90" />
|
||||||
|
</PathIcon.RenderTransform>
|
||||||
|
</PathIcon>
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,14 @@
|
||||||
<TextBlock Margin="{StaticResource Margin4}" Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
<TextBlock Margin="{StaticResource Margin4}" Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
Width="{StaticResource IconButtonWidth}"
|
Classes="IconButton"
|
||||||
Height="{StaticResource IconButtonHeight}"
|
Margin="{StaticResource MarginLr8}">
|
||||||
MinWidth="{StaticResource IconButtonWidth}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconMore}" >
|
||||||
|
<PathIcon.RenderTransform>
|
||||||
|
<RotateTransform Angle="90" />
|
||||||
|
</PathIcon.RenderTransform>
|
||||||
|
</PathIcon>
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
|
|
|
||||||
|
|
@ -27,27 +27,21 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnConnectionCloseAll"
|
x:Name="btnConnectionCloseAll"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
Classes="IconButton Success"
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Classes="Success"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_delete}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconClose}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAutofitColumnWidth"
|
x:Name="btnAutofitColumnWidth"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
Classes="IconButton Success"
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Classes="Success"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_fit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconExpand}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,27 +50,21 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="menuProxiesReload"
|
x:Name="menuProxiesReload"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesReload}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesReload}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_refresh}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconRefresh}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="menuProxiesDelaytest"
|
x:Name="menuProxiesDelaytest"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesDelaytest}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesDelaytest}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_ping}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconBolt}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,52 +89,73 @@
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbBootstrapDNS}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbBootstrapDNS"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
IsEditable="True" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbBootstrapDNSTips}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
|
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRayFreedomDNSStrategy"
|
x:Name="cmbRayFreedomDNSStrategy"
|
||||||
Grid.Row="3"
|
Grid.Row="4"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
PlaceholderText="Default" />
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
|
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSBDirectDNSStrategy"
|
x:Name="cmbSBDirectDNSStrategy"
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
PlaceholderText="Default" />
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
|
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSBRemoteDNSStrategy"
|
x:Name="cmbSBRemoteDNSStrategy"
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
PlaceholderText="Default" />
|
PlaceholderText="Default" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
|
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togAddCommonHosts"
|
x:Name="togAddCommonHosts"
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
|
|
@ -35,6 +36,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,22 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnCopy"
|
x:Name="btnCopy"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Click="menuMsgViewCopyAll_Click"
|
Click="menuMsgViewCopyAll_Click"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewCopyAll}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewCopyAll}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_copy}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconCopy}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnClear"
|
x:Name="btnClear"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
Margin="{StaticResource MarginLr8}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Click="menuMsgViewClear_Click"
|
Click="menuMsgViewClear_Click"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewClear}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewClear}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_delete}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconDelete}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,11 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAutofitColumnWidth"
|
x:Name="btnAutofitColumnWidth"
|
||||||
Width="32"
|
Margin="{StaticResource MarginLr4}"
|
||||||
Height="32"
|
Classes="IconButton Success"
|
||||||
Margin="8,0"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_fit}" />
|
<PathIcon Data="{StaticResource SemiIconExpand}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,39 +32,30 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnEditSub"
|
x:Name="btnEditSub"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr4}"
|
Margin="{StaticResource MarginLr4}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubEdit}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuSubEdit}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_edit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconEdit}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAddSub"
|
x:Name="btnAddSub"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr4}"
|
Margin="{StaticResource MarginLr4}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubAdd}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuSubAdd}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_add}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconPlus}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAutofitColumnWidth"
|
x:Name="btnAutofitColumnWidth"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr4}"
|
Margin="{StaticResource MarginLr4}"
|
||||||
Classes="Success"
|
Classes="IconButton Success"
|
||||||
Theme="{DynamicResource BorderlessButton}"
|
|
||||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_fit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconExpand}" />
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,15 @@
|
||||||
<Button
|
<Button
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Width="{StaticResource IconButtonWidth}"
|
Classes="IconButton"
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
Margin="{StaticResource MarginLr8}">
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconMore}" >
|
||||||
|
<PathIcon.RenderTransform>
|
||||||
|
<RotateTransform Angle="90" />
|
||||||
|
</PathIcon.RenderTransform>
|
||||||
|
</PathIcon>
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@
|
||||||
</Style>
|
</Style>
|
||||||
</UserControl.Styles>
|
</UserControl.Styles>
|
||||||
|
|
||||||
<Button
|
<Button Margin="{StaticResource MarginLr8}" Classes="IconButton">
|
||||||
Width="{StaticResource IconButtonWidth}"
|
|
||||||
Height="{StaticResource IconButtonHeight}"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
|
||||||
Theme="{DynamicResource BorderlessButton}">
|
|
||||||
<Button.Content>
|
<Button.Content>
|
||||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
<PathIcon Data="{StaticResource SemiIconMore}">
|
||||||
|
<PathIcon.RenderTransform>
|
||||||
|
<RotateTransform Angle="90" />
|
||||||
|
</PathIcon.RenderTransform>
|
||||||
|
</PathIcon>
|
||||||
</Button.Content>
|
</Button.Content>
|
||||||
<Button.Flyout>
|
<Button.Flyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
|
|
|
||||||
|
|
@ -115,10 +115,34 @@
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbBootstrapDNS}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbBootstrapDNS"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="300"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbBootstrapDNSTips}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
|
Text="{x:Static resx:ResUI.TbXrayFreedomStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRayFreedomDNSStrategy"
|
x:Name="cmbRayFreedomDNSStrategy"
|
||||||
Grid.Row="3"
|
Grid.Row="4"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
|
@ -126,7 +150,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -134,7 +158,7 @@
|
||||||
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
|
Text="{x:Static resx:ResUI.TbSBDirectResolveStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSBDirectDNSStrategy"
|
x:Name="cmbSBDirectDNSStrategy"
|
||||||
Grid.Row="4"
|
Grid.Row="5"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
|
@ -142,7 +166,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -150,7 +174,7 @@
|
||||||
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
|
Text="{x:Static resx:ResUI.TbSBRemoteResolveStrategy}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbSBRemoteDNSStrategy"
|
x:Name="cmbSBRemoteDNSStrategy"
|
||||||
Grid.Row="5"
|
Grid.Row="6"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
|
|
@ -158,7 +182,7 @@
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
|
@ -166,7 +190,7 @@
|
||||||
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
|
Text="{x:Static resx:ResUI.TbAddCommonDNSHosts}" />
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
x:Name="togAddCommonHosts"
|
x:Name="togAddCommonHosts"
|
||||||
Grid.Row="6"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ public partial class DNSSettingWindow
|
||||||
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
cmbSBRemoteDNSStrategy.ItemsSource = Global.SingboxDomainStrategy4Out;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy4Freedoms;
|
||||||
|
|
@ -33,6 +34,7 @@ public partial class DNSSettingWindow
|
||||||
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.BlockBindingQuery, v => v.togBlockBindingQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectDNS, v => v.cmbDirectDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RemoteDNS, v => v.cmbRemoteDNS.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.RayStrategy4Freedom, v => v.cmbRayFreedomDNSStrategy.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Direct, v => v.cmbSBDirectDNSStrategy.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SingboxStrategy4Proxy, v => v.cmbSBRemoteDNSStrategy.Text).DisposeWith(disposables);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue