mirror of
https://github.com/2dust/v2rayN.git
synced 2026-10-30 17:15:00 +03:00
Compare commits
13 Commits
7.24.0
..
a37772f12b
| Author | SHA1 | Date | |
|---|---|---|---|
| a37772f12b | |||
| 531e0e9443 | |||
| 984c77f0c4 | |||
| b5e0be47a5 | |||
| 6df0e6de1b | |||
| 2b5328665f | |||
| 4584ecc5c9 | |||
| d9dc2d7cf5 | |||
| 36f8565b7a | |||
| f55d8b2565 | |||
| 09ea4890a7 | |||
| 5cc2aaba13 | |||
| b8889bad86 |
@@ -1,3 +1,49 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
THIRD-PARTY CA CERTIFICATE DATA ATTRIBUTION
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This component includes CA certificate data obtained from third-party sources.
|
||||||
|
|
||||||
|
1. Common CA Database (CCADB)
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Website:
|
||||||
|
https://www.ccadb.org/
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites
|
||||||
|
|
||||||
|
License:
|
||||||
|
Community Data License Agreement – Permissive, Version 2.0 (CDLA-2.0 Permissive)
|
||||||
|
|
||||||
|
The names and trademarks of CCADB contributors may not be used to endorse or
|
||||||
|
promote products derived from this data without prior written permission.
|
||||||
|
|
||||||
|
License text:
|
||||||
|
https://cdla.dev/permissive-2-0/
|
||||||
|
|
||||||
|
|
||||||
|
2. Chromium Root Store
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Source:
|
||||||
|
Chromium Project
|
||||||
|
|
||||||
|
Data source:
|
||||||
|
https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT
|
||||||
|
|
||||||
|
License:
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
Copyright (c) The Chromium Authors
|
||||||
|
|
||||||
|
The Chromium Root Store data is distributed under the BSD 3-Clause License.
|
||||||
|
|
||||||
|
License text:
|
||||||
|
https://opensource.org/licenses/BSD-3-Clause
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -27,68 +73,23 @@ Console.WriteLine("\nAll done!");
|
|||||||
|
|
||||||
async Task ProcessMozillaAsync(string outputDir)
|
async Task ProcessMozillaAsync(string outputDir)
|
||||||
{
|
{
|
||||||
const string certdataUrl = "https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt";
|
const string certdataUrl = "https://ccadb.my.salesforce-sites.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites";
|
||||||
var outputFile = Path.Combine(outputDir, "mozilla_roots_pem");
|
var outputFile = Path.Combine(outputDir, "mozilla_roots_pem");
|
||||||
|
|
||||||
Console.WriteLine("Downloading Mozilla certdata.txt...");
|
Console.WriteLine("Downloading Mozilla certdata.txt...");
|
||||||
var content = await client.GetStringAsync(certdataUrl);
|
var content = await client.GetStringAsync(certdataUrl);
|
||||||
|
|
||||||
Console.WriteLine("Parsing MULTILINE_OCTAL to PEM...");
|
var pemMatches = Regex.Matches(content, @"(-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----)");
|
||||||
var pems = ParseMozillaCertData(content);
|
var pems = new List<string>();
|
||||||
|
foreach (Match m in pemMatches)
|
||||||
|
{
|
||||||
|
pems.Add(m.Groups[1].Value.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems));
|
await File.WriteAllTextAsync(outputFile, string.Join("\n\n", pems));
|
||||||
Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)");
|
Console.WriteLine($"Mozilla roots saved to: {outputFile} ({pems.Count} certificates)");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> ParseMozillaCertData(string text)
|
|
||||||
{
|
|
||||||
var pems = new List<string>();
|
|
||||||
|
|
||||||
var matches = Regex.Matches(text,
|
|
||||||
@"CKA_VALUE MULTILINE_OCTAL\s*([\s\S]*?)\s*END",
|
|
||||||
RegexOptions.Multiline);
|
|
||||||
|
|
||||||
foreach (Match m in matches)
|
|
||||||
{
|
|
||||||
var octalBlock = m.Groups[1].Value.Trim();
|
|
||||||
var der = OctalToBytes(octalBlock);
|
|
||||||
if (der.Length > 0)
|
|
||||||
{
|
|
||||||
var pem = ConvertToPem(der);
|
|
||||||
pems.Add(pem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pems;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] OctalToBytes(string octalBlock)
|
|
||||||
{
|
|
||||||
var bytes = new List<byte>();
|
|
||||||
var matches = Regex.Matches(octalBlock, @"\\(\d{1,3})");
|
|
||||||
foreach (Match m in matches)
|
|
||||||
{
|
|
||||||
bytes.Add((byte)Convert.ToInt32(m.Groups[1].Value, 8));
|
|
||||||
}
|
|
||||||
return bytes.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
string ConvertToPem(byte[] der)
|
|
||||||
{
|
|
||||||
var base64 = Convert.ToBase64String(der);
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("-----BEGIN CERTIFICATE-----\n");
|
|
||||||
|
|
||||||
for (int i = 0; i < base64.Length; i += 64)
|
|
||||||
{
|
|
||||||
var length = Math.Min(64, base64.Length - i);
|
|
||||||
sb.Append(base64.Substring(i, length));
|
|
||||||
sb.Append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append("-----END CERTIFICATE-----\n");
|
|
||||||
return sb.ToString().TrimEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task ProcessChromeAsync(string outputDir)
|
async Task ProcessChromeAsync(string outputDir)
|
||||||
{
|
{
|
||||||
const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT";
|
const string chromeCertsUrl = "https://chromium.googlesource.com/chromium/src/+/main/net/data/ssl/chrome_root_store/root_store.certs?format=TEXT";
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
||||||
|
|
||||||
- name: Setup .NET 10.0.1xx
|
- name: Setup .NET 10.0.1xx
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.1xx
|
dotnet-version: 10.0.1xx
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ jobs:
|
|||||||
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
dotnet --list-sdks 2>$null; $LASTEXITCODE=0
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '10.0.1xx'
|
dotnet-version: '10.0.1xx'
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
fetch-depth: '0'
|
fetch-depth: '0'
|
||||||
|
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v5.4.0
|
uses: actions/setup-dotnet@v6.0.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '8.0.x'
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
|||||||
@@ -597,7 +597,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
|
|||||||
PKGROOT="v2rayN-publish"
|
PKGROOT="v2rayN-publish"
|
||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
OUTPUT_DIR="${HOME}/debbuild"
|
OUTPUT_DIR="${HOME}/debbuild"
|
||||||
DOTNET_RISCV_VERSION="10.0.109"
|
DOTNET_RISCV_VERSION="10.0.110"
|
||||||
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
||||||
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
||||||
@@ -595,7 +595,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
+1
-1
@@ -609,7 +609,7 @@ package_binary() {
|
|||||||
write_desktop_file "$stage"
|
write_desktop_file "$stage"
|
||||||
write_maintainer_scripts "$debian_dir"
|
write_maintainer_scripts "$debian_dir"
|
||||||
|
|
||||||
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.2.0), coreutils (>= 9.5), bash (>= 5.2.26), libfreetype6 (>= 2.13)"
|
extra_depends="libc6 (>= 2.39), fontconfig (>= 2.15.0), desktop-file-utils (>= 0.26), xdg-utils (>= 1.1.3), coreutils (>= 9.4), bash (>= 5.2.21), libfreetype6 (>= 2.13)"
|
||||||
|
|
||||||
mkdir -p "$workdir/debian"
|
mkdir -p "$workdir/debian"
|
||||||
cat > "$workdir/debian/control" <<EOF
|
cat > "$workdir/debian/control" <<EOF
|
||||||
|
|||||||
@@ -513,9 +513,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ MIN_KERNEL="5.10"
|
|||||||
PKGROOT="v2rayN-publish"
|
PKGROOT="v2rayN-publish"
|
||||||
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
PROJECT_HINT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
||||||
RPM_TOPDIR="${HOME}/rpmbuild"
|
RPM_TOPDIR="${HOME}/rpmbuild"
|
||||||
DOTNET_RISCV_VERSION="10.0.109"
|
DOTNET_RISCV_VERSION="10.0.110"
|
||||||
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
DOTNET_RISCV_BASE="https://github.com/xujiegb/dotnet-riscv/releases/download"
|
||||||
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
DOTNET_RISCV_FILE="dotnet-sdk-${DOTNET_RISCV_VERSION}-linux-riscv64.tar.gz"
|
||||||
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
DOTNET_SDK_URL="${DOTNET_RISCV_BASE}/${DOTNET_RISCV_VERSION}/${DOTNET_RISCV_FILE}"
|
||||||
@@ -512,9 +512,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
+3
-3
@@ -501,9 +501,9 @@ Requires: cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|||||||
Requires: glibc >= 2.39
|
Requires: glibc >= 2.39
|
||||||
Requires: fontconfig >= 2.15.0
|
Requires: fontconfig >= 2.15.0
|
||||||
Requires: desktop-file-utils >= 0.26
|
Requires: desktop-file-utils >= 0.26
|
||||||
Requires: xdg-utils >= 1.2.0
|
Requires: xdg-utils >= 1.1.3
|
||||||
Requires: coreutils >= 9.5
|
Requires: coreutils >= 9.4
|
||||||
Requires: bash >= 5.2.26
|
Requires: bash >= 5.2.21
|
||||||
Requires: freetype >= 2.13
|
Requires: freetype >= 2.13
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.24.0</Version>
|
<Version>7.24.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ internal static class CoreConfigTestFactory
|
|||||||
},
|
},
|
||||||
WebDavItem = new WebDavItem(),
|
WebDavItem = new WebDavItem(),
|
||||||
CheckUpdateItem = new CheckUpdateItem(),
|
CheckUpdateItem = new CheckUpdateItem(),
|
||||||
Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Length = "100-200", Interval = "10-20" },
|
Fragment4RayItem = new Fragment4RayItem { Packets = "tlshello", Lengths = ["100-200"], Delays = ["10-20"] },
|
||||||
Inbound =
|
Inbound =
|
||||||
[
|
[
|
||||||
new InItem
|
new InItem
|
||||||
@@ -84,6 +84,7 @@ internal static class CoreConfigTestFactory
|
|||||||
ParallelQuery = false,
|
ParallelQuery = false,
|
||||||
Strategy4Freedom = Global.AsIs,
|
Strategy4Freedom = Global.AsIs,
|
||||||
Strategy4Proxy = Global.AsIs,
|
Strategy4Proxy = Global.AsIs,
|
||||||
|
Strategy4ProxyDial = Global.AsIs,
|
||||||
},
|
},
|
||||||
IndexId = string.Empty,
|
IndexId = string.Empty,
|
||||||
SubIndexId = string.Empty,
|
SubIndexId = string.Empty,
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ public class CoreConfigV2rayServiceTests
|
|||||||
|
|
||||||
var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom");
|
var directOutbound = cfg.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag && o.protocol == "freedom");
|
||||||
directOutbound.Should().NotBeNull();
|
directOutbound.Should().NotBeNull();
|
||||||
directOutbound!.settings.domainStrategy.Should().Be("UseIPv4");
|
directOutbound!.streamSettings.sockopt!.domainStrategy.Should().Be("UseIPv4");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -485,12 +485,17 @@ public class Utils
|
|||||||
|
|
||||||
public static string? DomainStrategy4Sbox(string? strategy)
|
public static string? DomainStrategy4Sbox(string? strategy)
|
||||||
{
|
{
|
||||||
|
if (strategy is null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return strategy switch
|
return strategy switch
|
||||||
{
|
{
|
||||||
not null when strategy.StartsWith("UseIPv4") => "prefer_ipv4",
|
_ when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
|
||||||
not null when strategy.StartsWith("UseIPv6") => "prefer_ipv6",
|
_ when strategy.StartsWith("UseIP") => "prefer_ipv4",
|
||||||
not null when strategy.StartsWith("ForceIPv4") => "ipv4_only",
|
_ when strategy.StartsWith("ForceIPv6") => "ipv6_only",
|
||||||
not null when strategy.StartsWith("ForceIPv6") => "ipv6_only",
|
_ when strategy.StartsWith("ForceIP") => "ipv4_only",
|
||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,7 +557,6 @@ public class Global
|
|||||||
"http",
|
"http",
|
||||||
"tls",
|
"tls",
|
||||||
"quic",
|
"quic",
|
||||||
"fakedns",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<int> TunMtus =
|
public static readonly List<int> TunMtus =
|
||||||
@@ -737,6 +736,12 @@ public class Global
|
|||||||
"reply",
|
"reply",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> FakeIPRanges =
|
||||||
|
[
|
||||||
|
"198.18.0.0/15",
|
||||||
|
"11.0.0.0/8",
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> RootCertProviders =
|
public static readonly List<string> RootCertProviders =
|
||||||
[
|
[
|
||||||
"system",
|
"system",
|
||||||
|
|||||||
@@ -115,10 +115,12 @@ public static class ConfigHandler
|
|||||||
config.ConstItem ??= new ConstItem();
|
config.ConstItem ??= new ConstItem();
|
||||||
|
|
||||||
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
config.SimpleDNSItem ??= InitBuiltinSimpleDNS();
|
||||||
|
config.SimpleDNSItem.FakeIPRange ??= Global.FakeIPRanges.FirstOrDefault();
|
||||||
config.SimpleDNSItem.GlobalFakeIp ??= true;
|
config.SimpleDNSItem.GlobalFakeIp ??= true;
|
||||||
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
||||||
config.SimpleDNSItem.ServeStale ??= false;
|
config.SimpleDNSItem.ServeStale ??= false;
|
||||||
config.SimpleDNSItem.ParallelQuery ??= false;
|
config.SimpleDNSItem.ParallelQuery ??= false;
|
||||||
|
config.SimpleDNSItem.EnableHappyEyeballs ??= false;
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
@@ -168,10 +170,24 @@ public static class ConfigHandler
|
|||||||
config.Fragment4RayItem ??= new()
|
config.Fragment4RayItem ??= new()
|
||||||
{
|
{
|
||||||
Packets = "tlshello",
|
Packets = "tlshello",
|
||||||
Length = "50-100",
|
|
||||||
Interval = "10-20",
|
|
||||||
MaxSplit = "0"
|
|
||||||
};
|
};
|
||||||
|
config.Fragment4RayItem.MaxSplit ??= "0";
|
||||||
|
|
||||||
|
config.HappyEyeballs4RayItem ??= new()
|
||||||
|
{
|
||||||
|
TryDelayMs = 250,
|
||||||
|
PrioritizeIPv6 = false,
|
||||||
|
Interleave = 1,
|
||||||
|
MaxConcurrentTry = 4,
|
||||||
|
};
|
||||||
|
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
|
||||||
|
{
|
||||||
|
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
|
||||||
|
}
|
||||||
|
if ((config.Fragment4RayItem.Delays ?? []).Count == 0)
|
||||||
|
{
|
||||||
|
config.Fragment4RayItem.Delays = [config.Fragment4RayItem.Interval ?? "10-20"];
|
||||||
|
}
|
||||||
config.GlobalHotkeys ??= [];
|
config.GlobalHotkeys ??= [];
|
||||||
|
|
||||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public class Config
|
|||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
public SimpleDNSItem SimpleDNSItem { get; set; }
|
public SimpleDNSItem SimpleDNSItem { get; set; }
|
||||||
|
public HappyEyeballs4RayItem HappyEyeballs4RayItem { get; set; }
|
||||||
|
|
||||||
#endregion other entities
|
#endregion other entities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,9 +249,14 @@ public class CheckUpdateItem
|
|||||||
public class Fragment4RayItem
|
public class Fragment4RayItem
|
||||||
{
|
{
|
||||||
public string? Packets { get; set; }
|
public string? Packets { get; set; }
|
||||||
|
public List<string>? Lengths { get; set; }
|
||||||
|
public List<string>? Delays { get; set; }
|
||||||
|
public string? MaxSplit { get; set; }
|
||||||
|
|
||||||
|
// For migration from old version, remove those properties in the future
|
||||||
public string? Length { get; set; }
|
public string? Length { get; set; }
|
||||||
public string? Interval { get; set; }
|
public string? Interval { get; set; }
|
||||||
public string? MaxSplit { get; set; }
|
// migration end
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -269,14 +274,26 @@ public class SimpleDNSItem
|
|||||||
public bool? AddCommonHosts { get; set; }
|
public bool? AddCommonHosts { get; set; }
|
||||||
public bool? FakeIP { get; set; }
|
public bool? FakeIP { get; set; }
|
||||||
public bool? GlobalFakeIp { get; set; }
|
public bool? GlobalFakeIp { get; set; }
|
||||||
|
public string? FakeIPRange { get; set; }
|
||||||
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? BootstrapDNS { get; set; }
|
||||||
public string? Strategy4Freedom { get; set; }
|
public string? Strategy4Freedom { get; set; }
|
||||||
public string? Strategy4Proxy { get; set; }
|
public string? Strategy4Proxy { get; set; }
|
||||||
|
public string? Strategy4ProxyDial { get; set; }
|
||||||
public bool? ServeStale { get; set; }
|
public bool? ServeStale { get; set; }
|
||||||
public bool? ParallelQuery { get; set; }
|
public bool? ParallelQuery { get; set; }
|
||||||
public string? Hosts { get; set; }
|
public string? Hosts { get; set; }
|
||||||
public string? DirectExpectedIPs { get; set; }
|
public string? DirectExpectedIPs { get; set; }
|
||||||
|
public bool? EnableHappyEyeballs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class HappyEyeballs4RayItem
|
||||||
|
{
|
||||||
|
public int? TryDelayMs { get; set; }
|
||||||
|
public bool? PrioritizeIPv6 { get; set; }
|
||||||
|
public int? Interleave { get; set; }
|
||||||
|
public int? MaxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ public class V2rayConfig
|
|||||||
{
|
{
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
public object dns { get; set; }
|
public object dns { get; set; }
|
||||||
|
public FakeDns4Ray? fakedns { get; set; }
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
public Routing4Ray routing { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
@@ -43,6 +44,12 @@ public class Log4Ray
|
|||||||
public string? loglevel { get; set; }
|
public string? loglevel { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class FakeDns4Ray
|
||||||
|
{
|
||||||
|
public string? ipPool { get; set; }
|
||||||
|
public long? poolSize { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Inbounds4Ray
|
public class Inbounds4Ray
|
||||||
{
|
{
|
||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
@@ -136,8 +143,6 @@ public class Outboundsettings4Ray
|
|||||||
|
|
||||||
public Response4Ray? response { get; set; }
|
public Response4Ray? response { get; set; }
|
||||||
|
|
||||||
public string? domainStrategy { get; set; }
|
|
||||||
|
|
||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
public string? secretKey { get; set; }
|
public string? secretKey { get; set; }
|
||||||
@@ -516,6 +521,8 @@ public class MaskSettings4Ray
|
|||||||
|
|
||||||
public string? length { get; set; }
|
public string? length { get; set; }
|
||||||
public string? delay { get; set; }
|
public string? delay { get; set; }
|
||||||
|
public List<string>? lengths { get; set; }
|
||||||
|
public List<string>? delays { get; set; }
|
||||||
public int? maxSplit { get; set; }
|
public int? maxSplit { get; set; }
|
||||||
|
|
||||||
// noise
|
// noise
|
||||||
@@ -547,15 +554,19 @@ public class AccountsItem4Ray
|
|||||||
|
|
||||||
public class Sockopt4Ray
|
public class Sockopt4Ray
|
||||||
{
|
{
|
||||||
|
public string? domainStrategy { get; set; }
|
||||||
|
|
||||||
public string? dialerProxy { get; set; }
|
public string? dialerProxy { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("interface")]
|
[JsonPropertyName("interface")]
|
||||||
public string? Interface { get; set; }
|
public string? Interface { get; set; }
|
||||||
|
public HappyEyeballs4Ray? happyEyeballs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FragmentItem4Ray
|
public class HappyEyeballs4Ray
|
||||||
{
|
{
|
||||||
public string? packets { get; set; }
|
public int? tryDelayMs { get; set; }
|
||||||
public string? length { get; set; }
|
public bool? prioritizeIPv6 { get; set; }
|
||||||
public string? interval { get; set; }
|
public int? interleave { get; set; }
|
||||||
|
public int? maxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+37
-1
@@ -3060,6 +3060,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Enable Happy Eyeballs 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballs {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballs", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballsTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballsTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 DNS via Bridge 的本地化字符串。
|
/// 查找类似 DNS via Bridge 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3088,7 +3106,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Applies globally by default, with built-in FakeIP filtering (sing-box only). 的本地化字符串。
|
/// 查找类似 Applies globally by default, and built-in FakeIP filtering is only built into sing-box. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbFakeIPTips {
|
public static string TbFakeIPTips {
|
||||||
get {
|
get {
|
||||||
@@ -3528,6 +3546,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Proxy Dial Resolution Strategy 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbProxyDialResolveStrategy {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbProxyDialResolveStrategy", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Not recommended; may cause routing loops. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbProxyDialResolveStrategyTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbProxyDialResolveStrategyTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Public Key 的本地化字符串。
|
/// 查找类似 Public Key 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
|||||||
@@ -1492,7 +1492,7 @@
|
|||||||
<value>Choisir une config.</value>
|
<value>Choisir une config.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Actif globalement par défaut, avec filtre FakeIP intégré ; ne fonctionne que dans sing-box</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Veuillez ajouter au moins une configuration</value>
|
<value>Veuillez ajouter au moins une configuration</value>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
|
|||||||
@@ -1495,7 +1495,7 @@
|
|||||||
<value>Pilih profil</value>
|
<value>Pilih profil</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Berlaku secara global secara default, dengan filter FakeIP bawaan (hanya sing-box).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Silakan tambahkan setidaknya satu konfigurasi.</value>
|
<value>Silakan tambahkan setidaknya satu konfigurasi.</value>
|
||||||
|
|||||||
@@ -1501,7 +1501,7 @@
|
|||||||
<value>Select Profile</value>
|
<value>Select Profile</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>Applies globally by default, with built-in FakeIP filtering (sing-box only).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Please Add At Least One Configuration</value>
|
<value>Please Add At Least One Configuration</value>
|
||||||
@@ -1830,4 +1830,16 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||||
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
|
<value>Only applies to the v2rayN GUI's downloads and network requests. Does not affect the core's certificate validation.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||||
|
<value>Proxy Dial Resolution Strategy</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
|
<value>Not recommended; may cause routing loops.</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>Enable Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1501,7 +1501,7 @@
|
|||||||
<value>Выбрать профиль</value>
|
<value>Выбрать профиль</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>По умолчанию применяется глобально, со встроенной фильтрацией FakeIP (только sing-box).</value>
|
<value>Applies globally by default, and built-in FakeIP filtering is only built into sing-box.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>Добавьте хотя бы одну конфигурацию</value>
|
<value>Добавьте хотя бы одну конфигурацию</value>
|
||||||
|
|||||||
@@ -1498,7 +1498,7 @@
|
|||||||
<value>选择配置</value>
|
<value>选择配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>默认全局生效,内置 FakeIP 过滤,仅在 sing-box 中生效</value>
|
<value>默认全局生效,仅在 sing-box 中内置 FakeIP 过滤。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>请至少添加一个配置</value>
|
<value>请至少添加一个配置</value>
|
||||||
@@ -1827,4 +1827,16 @@
|
|||||||
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
<data name="TbRootCertificateProviderTip" xml:space="preserve">
|
||||||
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
|
<value>仅用于 v2rayN 界面程序的下载及网络请求,不影响核心的证书验证。</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategy" xml:space="preserve">
|
||||||
|
<value>连接代理解析策略</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
|
<value>不建议开启,特殊情况可能回环。</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>启用 Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>需配合 UseIP 策略使用。启用后将同时尝试 IPv4 和 IPv6 连接,并自动选择更快可用的路径。</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1498,7 +1498,7 @@
|
|||||||
<value>選擇節點</value>
|
<value>選擇節點</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbFakeIPTips" xml:space="preserve">
|
<data name="TbFakeIPTips" xml:space="preserve">
|
||||||
<value>默認全域生效,內置 FakeIP 過濾,僅在 sing-box 中生效</value>
|
<value>默認全局生效,僅在 sing-box 中內置 FakeIP 過濾。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
<data name="PleaseAddAtLeastOneServer" xml:space="preserve">
|
||||||
<value>請至少添加一個節點</value>
|
<value>請至少添加一個節點</value>
|
||||||
|
|||||||
+2342
-3553
File diff suppressed because it is too large
Load Diff
@@ -137,12 +137,12 @@ public partial class CoreConfigSingboxService
|
|||||||
// fake ip
|
// fake ip
|
||||||
if (simpleDnsItem.FakeIP == true)
|
if (simpleDnsItem.FakeIP == true)
|
||||||
{
|
{
|
||||||
|
var fakeipRange = simpleDnsItem.FakeIPRange.IsNullOrEmpty() ? Global.FakeIPRanges.First() : simpleDnsItem.FakeIPRange;
|
||||||
var fakeip = new Server4Sbox
|
var fakeip = new Server4Sbox
|
||||||
{
|
{
|
||||||
tag = Global.SingboxFakeDNSTag,
|
tag = Global.SingboxFakeDNSTag,
|
||||||
type = "fakeip",
|
type = "fakeip",
|
||||||
inet4_range = "198.18.0.0/15",
|
inet4_range = fakeipRange,
|
||||||
inet6_range = "fc00::/18",
|
|
||||||
};
|
};
|
||||||
_coreConfig.dns.servers.Add(fakeip);
|
_coreConfig.dns.servers.Add(fakeip);
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ public partial class CoreConfigSingboxService
|
|||||||
_coreConfig.dns.rules.Add(new()
|
_coreConfig.dns.rules.Add(new()
|
||||||
{
|
{
|
||||||
server = Global.SingboxDirectDNSTag,
|
server = Global.SingboxDirectDNSTag,
|
||||||
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
|
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial),
|
||||||
domain = context.ProtectDomainList.ToList(),
|
domain = context.ProtectDomainList.ToList(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ public partial class CoreConfigSingboxService
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp == true)
|
if (simpleDnsItem.FakeIP == true && simpleDnsItem.GlobalFakeIp != false)
|
||||||
{
|
{
|
||||||
var fakeipFilterRule = JsonUtils.Deserialize<Rule4Sbox>(EmbedUtils.GetEmbedText(Global.SingboxFakeIPFilterFileName));
|
var fakeipFilterRule = JsonUtils.Deserialize<Rule4Sbox>(EmbedUtils.GetEmbedText(Global.SingboxFakeIPFilterFileName));
|
||||||
fakeipFilterRule.invert = true;
|
fakeipFilterRule.invert = true;
|
||||||
|
|||||||
@@ -417,11 +417,15 @@ public partial class CoreConfigSingboxService
|
|||||||
var tls = new Tls4Sbox()
|
var tls = new Tls4Sbox()
|
||||||
{
|
{
|
||||||
enabled = true,
|
enabled = true,
|
||||||
record_fragment = _config.CoreBasicItem.EnableFragment ? true : null,
|
|
||||||
server_name = serverName,
|
server_name = serverName,
|
||||||
insecure = _node.GetAllowInsecure(),
|
insecure = _node.GetAllowInsecure(),
|
||||||
alpn = _node.GetAlpn(),
|
alpn = _node.GetAlpn(),
|
||||||
};
|
};
|
||||||
|
if (_config.CoreBasicItem.EnableFragment == true)
|
||||||
|
{
|
||||||
|
tls.fragment = true;
|
||||||
|
tls.record_fragment = true;
|
||||||
|
}
|
||||||
if (_node.Fingerprint.IsNotEmpty())
|
if (_node.Fingerprint.IsNotEmpty())
|
||||||
{
|
{
|
||||||
tls.utls = new Utls4Sbox()
|
tls.utls = new Utls4Sbox()
|
||||||
|
|||||||
@@ -10,18 +10,27 @@ public partial class CoreConfigSingboxService
|
|||||||
var simpleDnsItem = context.SimpleDnsItem;
|
var simpleDnsItem = context.SimpleDnsItem;
|
||||||
|
|
||||||
var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
|
var defaultDomainResolverTag = Global.SingboxDirectDNSTag;
|
||||||
var directDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom);
|
var dialDnsStrategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4ProxyDial);
|
||||||
|
|
||||||
var rawDNSItem = context.RawDnsItem;
|
var rawDNSItem = context.RawDnsItem;
|
||||||
if (rawDNSItem is { Enabled: true })
|
if (rawDNSItem is { Enabled: true })
|
||||||
{
|
{
|
||||||
defaultDomainResolverTag = Global.SingboxLocalDNSTag;
|
defaultDomainResolverTag = Global.SingboxLocalDNSTag;
|
||||||
directDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom;
|
dialDnsStrategy = rawDNSItem.DomainStrategy4Freedom.IsNullOrEmpty() ? null : rawDNSItem.DomainStrategy4Freedom;
|
||||||
|
}
|
||||||
|
else if (!simpleDnsItem.Strategy4Freedom.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
var directOutbound = _coreConfig.outbounds.FirstOrDefault(o => o.tag == Global.DirectTag);
|
||||||
|
directOutbound?.domain_resolver = new()
|
||||||
|
{
|
||||||
|
server = defaultDomainResolverTag,
|
||||||
|
strategy = Utils.DomainStrategy4Sbox(simpleDnsItem.Strategy4Freedom),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_coreConfig.route.default_domain_resolver = new()
|
_coreConfig.route.default_domain_resolver = new()
|
||||||
{
|
{
|
||||||
server = defaultDomainResolverTag,
|
server = defaultDomainResolverTag,
|
||||||
strategy = directDnsStrategy
|
strategy = dialDnsStrategy
|
||||||
};
|
};
|
||||||
|
|
||||||
if (context.IsTunEnabled)
|
if (context.IsTunEnabled)
|
||||||
@@ -35,18 +44,21 @@ public partial class CoreConfigSingboxService
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lstDirectExe = BuildRoutingDirectExe();
|
var lstDirectExe = BuildRoutingDirectExe();
|
||||||
_coreConfig.route.rules.Add(new()
|
if (lstDirectExe.Count > 0)
|
||||||
{
|
{
|
||||||
port = [53],
|
_coreConfig.route.rules.Add(new()
|
||||||
action = "hijack-dns",
|
{
|
||||||
process_path = lstDirectExe
|
port = [53],
|
||||||
});
|
action = "hijack-dns",
|
||||||
|
process_path = lstDirectExe,
|
||||||
|
});
|
||||||
|
|
||||||
_coreConfig.route.rules.Add(new()
|
_coreConfig.route.rules.Add(new()
|
||||||
{
|
{
|
||||||
outbound = Global.DirectTag,
|
outbound = Global.DirectTag,
|
||||||
process_path = lstDirectExe
|
process_path = lstDirectExe,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ICMP Routing
|
// ICMP Routing
|
||||||
var icmpRouting = _config.TunModeItem.IcmpRouting ?? "";
|
var icmpRouting = _config.TunModeItem.IcmpRouting ?? "";
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public partial class CoreConfigV2rayService
|
|||||||
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
_coreConfig.routing.rules.Add(new RulesItem4Ray
|
||||||
{
|
{
|
||||||
type = "field",
|
type = "field",
|
||||||
inboundTag = new List<string> { Global.DnsTag },
|
inboundTag = [Global.DnsTag],
|
||||||
outboundTag = Global.ProxyTag,
|
outboundTag = Global.ProxyTag,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -43,11 +43,7 @@ public partial class CoreConfigV2rayService
|
|||||||
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
if (outbound != null)
|
if (outbound != null)
|
||||||
{
|
{
|
||||||
outbound.settings = new()
|
FillSockoptDomainStrategy(outbound, strategy4Freedom);
|
||||||
{
|
|
||||||
domainStrategy = strategy4Freedom,
|
|
||||||
userLevel = 0
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +60,22 @@ public partial class CoreConfigV2rayService
|
|||||||
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
|
.ForEach(outbound => outbound.targetStrategy = strategy4Proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var strategy4DialProxy = simpleDnsItem?.Strategy4ProxyDial ?? Global.AsIs;
|
||||||
|
//Outbound DialProxy domainStrategy
|
||||||
|
if (strategy4DialProxy.IsNotEmpty() && strategy4DialProxy != Global.AsIs)
|
||||||
|
{
|
||||||
|
var xraySupportConfigTypeNames = Global.XraySupportConfigType
|
||||||
|
.Select(x => x == EConfigType.Hysteria2 ? "hysteria" : Global.ProtocolTypes[x])
|
||||||
|
.ToHashSet();
|
||||||
|
_coreConfig.outbounds
|
||||||
|
.Where(t => xraySupportConfigTypeNames.Contains(t.protocol))
|
||||||
|
.ToList()
|
||||||
|
.ForEach(outbound =>
|
||||||
|
{
|
||||||
|
FillSockoptDomainStrategy(outbound, strategy4DialProxy);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
FillDnsServers(dnsItem);
|
FillDnsServers(dnsItem);
|
||||||
FillDnsHosts(dnsItem);
|
FillDnsHosts(dnsItem);
|
||||||
|
|
||||||
@@ -108,6 +120,33 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GenFakeDns()
|
||||||
|
{
|
||||||
|
var fakeipRange = _config.SimpleDNSItem.FakeIPRange.IsNullOrEmpty() ? Global.FakeIPRanges.First() : _config.SimpleDNSItem.FakeIPRange;
|
||||||
|
var poolSize = 65535L;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fakeipNetwork = IPNetwork2.Parse(fakeipRange);
|
||||||
|
var totalIPs = fakeipNetwork.Total;
|
||||||
|
// see https://github.com/XTLS/Xray-core/blob/6e3322d219140a025285ded1114fe17a5edb74d8/app/dns/fakedns/fake.go#L88
|
||||||
|
// if math.Log2(float64(lruSize)) >= float64(rooms) { return errors.New("LRU size is bigger than subnet size").AtError() }
|
||||||
|
totalIPs -= 1;
|
||||||
|
if (totalIPs > 0)
|
||||||
|
{
|
||||||
|
poolSize = (totalIPs >= long.MaxValue) ? long.MaxValue : (long)totalIPs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
_coreConfig.fakedns = new()
|
||||||
|
{
|
||||||
|
ipPool = fakeipRange,
|
||||||
|
poolSize = poolSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void FillDnsServers(Dns4Ray dnsItem)
|
private void FillDnsServers(Dns4Ray dnsItem)
|
||||||
{
|
{
|
||||||
var simpleDNSItem = context.SimpleDnsItem;
|
var simpleDNSItem = context.SimpleDnsItem;
|
||||||
@@ -234,6 +273,23 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
var directDnsTagIndex = 1;
|
var directDnsTagIndex = 1;
|
||||||
|
|
||||||
|
if (simpleDNSItem.FakeIP == true)
|
||||||
|
{
|
||||||
|
var fakeIPMatchDomain = new HashSet<string>(proxyDomainList);
|
||||||
|
fakeIPMatchDomain.UnionWith(proxyGeositeList);
|
||||||
|
if (simpleDNSItem.GlobalFakeIp != false)
|
||||||
|
{
|
||||||
|
fakeIPMatchDomain.UnionWith(directDomainList);
|
||||||
|
fakeIPMatchDomain.UnionWith(directGeositeList);
|
||||||
|
fakeIPMatchDomain.UnionWith(expectedDomainList);
|
||||||
|
}
|
||||||
|
if (fakeIPMatchDomain.Count > 0)
|
||||||
|
{
|
||||||
|
GenFakeDns();
|
||||||
|
AddDnsServers(["fakedns"], fakeIPMatchDomain.ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
AddDnsServers(remoteDNSAddress, proxyDomainList);
|
||||||
AddDnsServers(directDNSAddress, directDomainList, true);
|
AddDnsServers(directDNSAddress, directDomainList, true);
|
||||||
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
AddDnsServers(remoteDNSAddress, proxyGeositeList);
|
||||||
@@ -384,11 +440,9 @@ public partial class CoreConfigV2rayService
|
|||||||
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
if (outbound != null)
|
if (outbound != null)
|
||||||
{
|
{
|
||||||
outbound.settings = new()
|
outbound.streamSettings ??= new();
|
||||||
{
|
outbound.streamSettings.sockopt ??= new();
|
||||||
domainStrategy = domainStrategy4Freedom,
|
outbound.streamSettings.sockopt.domainStrategy = domainStrategy4Freedom;
|
||||||
userLevel = 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,4 +525,28 @@ public partial class CoreConfigV2rayService
|
|||||||
};
|
};
|
||||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FillSockoptDomainStrategy(Outbounds4Ray outbound, string? domainStrategy, bool skipHappyEyeballs = false)
|
||||||
|
{
|
||||||
|
if (domainStrategy.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outbound.streamSettings ??= new();
|
||||||
|
outbound.streamSettings.sockopt ??= new();
|
||||||
|
var sockopt = outbound.streamSettings.sockopt;
|
||||||
|
sockopt.domainStrategy = domainStrategy;
|
||||||
|
|
||||||
|
if (skipHappyEyeballs || _config.SimpleDNSItem.EnableHappyEyeballs != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var happyEyeballsItem = _config.HappyEyeballs4RayItem;
|
||||||
|
sockopt.happyEyeballs ??= new();
|
||||||
|
var happyEyeballs = sockopt.happyEyeballs;
|
||||||
|
happyEyeballs.tryDelayMs = happyEyeballsItem.TryDelayMs;
|
||||||
|
happyEyeballs.prioritizeIPv6 = happyEyeballsItem.PrioritizeIPv6;
|
||||||
|
happyEyeballs.interleave = happyEyeballsItem.Interleave;
|
||||||
|
happyEyeballs.maxConcurrentTry = happyEyeballsItem.MaxConcurrentTry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,16 @@ public partial class CoreConfigV2rayService
|
|||||||
inbound.sniffing.destOverride = inItem.DestOverride;
|
inbound.sniffing.destOverride = inItem.DestOverride;
|
||||||
inbound.sniffing.routeOnly = inItem.RouteOnly;
|
inbound.sniffing.routeOnly = inItem.RouteOnly;
|
||||||
|
|
||||||
|
if (_config.SimpleDNSItem.FakeIP == true)
|
||||||
|
{
|
||||||
|
// Ensure destOverride contains "fakedns" if FakeIP is enabled
|
||||||
|
inbound.sniffing.destOverride ??= [];
|
||||||
|
if (!inbound.sniffing.destOverride.Contains("fakedns"))
|
||||||
|
{
|
||||||
|
inbound.sniffing.destOverride.Add("fakedns");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return inbound;
|
return inbound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -865,21 +865,10 @@ public partial class CoreConfigV2rayService
|
|||||||
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
|
&& (n.streamSettings?.sockopt?.dialerProxy?.IsNullOrEmpty() ?? true))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var (fragmentMask, noiseMask) = BuildFragmentsMasks();
|
var fragmentMask = BuildFragmentsMasks();
|
||||||
|
|
||||||
foreach (var outbound in actOutboundWithTlsList)
|
foreach (var outbound in actOutboundWithTlsList)
|
||||||
{
|
{
|
||||||
//var packets = configPackets;
|
|
||||||
//if (outbound.streamSettings.security == Global.StreamSecurityReality
|
|
||||||
// && packets == "tlshello")
|
|
||||||
//{
|
|
||||||
// packets = "1-3";
|
|
||||||
//}
|
|
||||||
//else if (outbound.streamSettings.security == Global.StreamSecurity
|
|
||||||
// && packets != "tlshello")
|
|
||||||
//{
|
|
||||||
// packets = "tlshello";
|
|
||||||
//}
|
|
||||||
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
|
var finalMaskJsonObj = JsonUtils.ParseJson(JsonUtils.Serialize(outbound.streamSettings?.finalmask)) as JsonObject ?? new JsonObject();
|
||||||
// tcp fragment
|
// tcp fragment
|
||||||
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
|
var tcpFinalmaskList = finalMaskJsonObj["tcp"] as JsonArray ?? [];
|
||||||
@@ -888,13 +877,6 @@ public partial class CoreConfigV2rayService
|
|||||||
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
|
tcpFinalmaskList.Add(JsonUtils.SerializeToNode(fragmentMask));
|
||||||
finalMaskJsonObj["tcp"] = tcpFinalmaskList;
|
finalMaskJsonObj["tcp"] = tcpFinalmaskList;
|
||||||
}
|
}
|
||||||
// udp noise
|
|
||||||
var udpFinalmaskList = finalMaskJsonObj["udp"] as JsonArray ?? [];
|
|
||||||
if (udpFinalmaskList.Count == 0)
|
|
||||||
{
|
|
||||||
udpFinalmaskList.Add(JsonUtils.SerializeToNode(noiseMask));
|
|
||||||
finalMaskJsonObj["udp"] = udpFinalmaskList;
|
|
||||||
}
|
|
||||||
// write back
|
// write back
|
||||||
outbound.streamSettings.finalmask = finalMaskJsonObj;
|
outbound.streamSettings.finalmask = finalMaskJsonObj;
|
||||||
}
|
}
|
||||||
@@ -902,7 +884,7 @@ public partial class CoreConfigV2rayService
|
|||||||
|
|
||||||
private void ApplyFinalFragment()
|
private void ApplyFinalFragment()
|
||||||
{
|
{
|
||||||
var (fragmentMask, noiseMask) = BuildFragmentsMasks();
|
var fragmentMask = BuildFragmentsMasks();
|
||||||
var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList();
|
var actOutboundList = _coreConfig.outbounds.Where(n => n.tag.StartsWith(Global.ProxyTag)).ToList();
|
||||||
|
|
||||||
var fragmentFreedom = new Outbounds4Ray()
|
var fragmentFreedom = new Outbounds4Ray()
|
||||||
@@ -914,9 +896,8 @@ public partial class CoreConfigV2rayService
|
|||||||
finalmask = new Finalmask4Ray
|
finalmask = new Finalmask4Ray
|
||||||
{
|
{
|
||||||
tcp = [fragmentMask],
|
tcp = [fragmentMask],
|
||||||
udp = [noiseMask],
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var outbound in actOutboundList)
|
foreach (var outbound in actOutboundList)
|
||||||
@@ -934,13 +915,22 @@ public partial class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Mask4Ray tcpFragment, Mask4Ray udpNoise) BuildFragmentsMasks()
|
private Mask4Ray BuildFragmentsMasks()
|
||||||
{
|
{
|
||||||
var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello";
|
var configPackets = _config.Fragment4RayItem?.Packets.NullIfEmpty() ?? "tlshello";
|
||||||
var configLength = _config.Fragment4RayItem?.Length.NullIfEmpty() ?? "50-100";
|
var configLengths = _config.Fragment4RayItem?.Lengths ?? [];
|
||||||
var configDelay = _config.Fragment4RayItem?.Interval.NullIfEmpty() ?? "10-20";
|
var configDelays = _config.Fragment4RayItem?.Delays ?? [];
|
||||||
var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0";
|
var configMaxSplit = _config.Fragment4RayItem?.MaxSplit.NullIfEmpty() ?? "0";
|
||||||
|
|
||||||
|
if (configLengths.Count == 0)
|
||||||
|
{
|
||||||
|
configLengths = ["50-100"];
|
||||||
|
}
|
||||||
|
if (configDelays.Count == 0)
|
||||||
|
{
|
||||||
|
configDelays = ["10-20"];
|
||||||
|
}
|
||||||
|
|
||||||
var maxSplit = 0;
|
var maxSplit = 0;
|
||||||
var parts = configMaxSplit.Split('-');
|
var parts = configMaxSplit.Split('-');
|
||||||
if (parts.Length > 0 && int.TryParse(parts[0], out var ms))
|
if (parts.Length > 0 && int.TryParse(parts[0], out var ms))
|
||||||
@@ -954,21 +944,15 @@ public partial class CoreConfigV2rayService
|
|||||||
settings = new MaskSettings4Ray
|
settings = new MaskSettings4Ray
|
||||||
{
|
{
|
||||||
packets = configPackets,
|
packets = configPackets,
|
||||||
length = configLength,
|
lengths = configLengths,
|
||||||
delay = configDelay,
|
delays = configDelays,
|
||||||
maxSplit = maxSplit,
|
maxSplit = maxSplit,
|
||||||
}
|
// For legacy xray compatibility, remove this in the future
|
||||||
};
|
length = configLengths.FirstOrDefault(),
|
||||||
var noiseMask = new Mask4Ray
|
delay = configDelays.FirstOrDefault(),
|
||||||
{
|
},
|
||||||
type = "noise",
|
|
||||||
settings = new MaskSettings4Ray
|
|
||||||
{
|
|
||||||
length = "10-20",
|
|
||||||
delay = "10-16",
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (fragmentMask, noiseMask);
|
return fragmentMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,20 @@ public partial class CoreConfigV2rayService
|
|||||||
_coreConfig.routing.rules.AddRange(tunRules);
|
_coreConfig.routing.rules.AddRange(tunRules);
|
||||||
}
|
}
|
||||||
var lstDirectExe = BuildRoutingDirectExe();
|
var lstDirectExe = BuildRoutingDirectExe();
|
||||||
_coreConfig.routing.rules.Add(new()
|
if (lstDirectExe.Count > 0)
|
||||||
{
|
{
|
||||||
port = "53",
|
_coreConfig.routing.rules.Add(new()
|
||||||
process = lstDirectExe,
|
{
|
||||||
outboundTag = Global.DnsOutboundTag,
|
port = "53",
|
||||||
});
|
process = lstDirectExe,
|
||||||
_coreConfig.routing.rules.Add(new()
|
outboundTag = Global.DnsOutboundTag,
|
||||||
{
|
});
|
||||||
process = lstDirectExe,
|
_coreConfig.routing.rules.Add(new()
|
||||||
outboundTag = Global.DirectTag,
|
{
|
||||||
});
|
process = lstDirectExe,
|
||||||
|
outboundTag = Global.DirectTag,
|
||||||
|
});
|
||||||
|
}
|
||||||
_coreConfig.routing.rules.Add(new()
|
_coreConfig.routing.rules.Add(new()
|
||||||
{
|
{
|
||||||
inboundTag = ["tun"],
|
inboundTag = ["tun"],
|
||||||
|
|||||||
@@ -4,19 +4,22 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
[Reactive] public bool? UseSystemHosts { get; set; }
|
[Reactive] public bool UseSystemHosts { get; set; }
|
||||||
[Reactive] public bool? AddCommonHosts { get; set; }
|
[Reactive] public bool AddCommonHosts { get; set; }
|
||||||
[Reactive] public bool? FakeIP { get; set; }
|
[Reactive] public bool FakeIP { get; set; }
|
||||||
[Reactive] public bool? BlockBindingQuery { get; set; }
|
[Reactive] public string FakeIPRange { get; set; }
|
||||||
[Reactive] public string? DirectDNS { get; set; }
|
[Reactive] public bool BlockBindingQuery { get; set; }
|
||||||
[Reactive] public string? RemoteDNS { get; set; }
|
[Reactive] public string DirectDNS { get; set; }
|
||||||
[Reactive] public string? BootstrapDNS { get; set; }
|
[Reactive] public string RemoteDNS { get; set; }
|
||||||
[Reactive] public string? Strategy4Freedom { get; set; }
|
[Reactive] public string BootstrapDNS { get; set; }
|
||||||
[Reactive] public string? Strategy4Proxy { get; set; }
|
[Reactive] public string Strategy4Freedom { get; set; }
|
||||||
[Reactive] public string? Hosts { get; set; }
|
[Reactive] public string Strategy4Proxy { get; set; }
|
||||||
[Reactive] public string? DirectExpectedIPs { get; set; }
|
[Reactive] public string Strategy4ProxyDial { get; set; }
|
||||||
[Reactive] public bool? ParallelQuery { get; set; }
|
[Reactive] public string Hosts { get; set; }
|
||||||
[Reactive] public bool? ServeStale { get; set; }
|
[Reactive] public string DirectExpectedIPs { get; set; }
|
||||||
|
[Reactive] public bool ParallelQuery { get; set; }
|
||||||
|
[Reactive] public bool ServeStale { get; set; }
|
||||||
|
[Reactive] public bool EnableHappyEyeballs { get; set; }
|
||||||
|
|
||||||
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
||||||
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
||||||
@@ -67,20 +70,22 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
var item = _config.SimpleDNSItem;
|
var item = _config.SimpleDNSItem;
|
||||||
UseSystemHosts = item.UseSystemHosts;
|
UseSystemHosts = item.UseSystemHosts ?? false;
|
||||||
AddCommonHosts = item.AddCommonHosts;
|
AddCommonHosts = item.AddCommonHosts ?? false;
|
||||||
FakeIP = item.FakeIP;
|
FakeIP = item.FakeIP ?? false;
|
||||||
BlockBindingQuery = item.BlockBindingQuery;
|
FakeIPRange = item.FakeIPRange ?? string.Empty;
|
||||||
DirectDNS = item.DirectDNS;
|
BlockBindingQuery = item.BlockBindingQuery ?? false;
|
||||||
RemoteDNS = item.RemoteDNS;
|
DirectDNS = item.DirectDNS ?? string.Empty;
|
||||||
BootstrapDNS = item.BootstrapDNS;
|
RemoteDNS = item.RemoteDNS ?? string.Empty;
|
||||||
Strategy4Freedom = item.Strategy4Freedom;
|
BootstrapDNS = item.BootstrapDNS ?? string.Empty;
|
||||||
Strategy4Proxy = item.Strategy4Proxy;
|
Strategy4Freedom = item.Strategy4Freedom ?? string.Empty;
|
||||||
Hosts = item.Hosts;
|
Strategy4Proxy = item.Strategy4Proxy ?? string.Empty;
|
||||||
DirectExpectedIPs = item.DirectExpectedIPs;
|
Strategy4ProxyDial = item.Strategy4ProxyDial ?? string.Empty;
|
||||||
ParallelQuery = item.ParallelQuery;
|
Hosts = item.Hosts ?? string.Empty;
|
||||||
ServeStale = item.ServeStale;
|
DirectExpectedIPs = item.DirectExpectedIPs ?? string.Empty;
|
||||||
|
ParallelQuery = item.ParallelQuery ?? false;
|
||||||
|
ServeStale = item.ServeStale ?? false;
|
||||||
|
EnableHappyEyeballs = item.EnableHappyEyeballs ?? false;
|
||||||
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
RayCustomDNSEnableCompatible = item1.Enabled;
|
RayCustomDNSEnableCompatible = item1.Enabled;
|
||||||
UseSystemHostsCompatible = item1.UseSystemHosts;
|
UseSystemHostsCompatible = item1.UseSystemHosts;
|
||||||
@@ -102,17 +107,19 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
_config.SimpleDNSItem.UseSystemHosts = UseSystemHosts;
|
||||||
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
_config.SimpleDNSItem.AddCommonHosts = AddCommonHosts;
|
||||||
_config.SimpleDNSItem.FakeIP = FakeIP;
|
_config.SimpleDNSItem.FakeIP = FakeIP;
|
||||||
|
_config.SimpleDNSItem.FakeIPRange = FakeIPRange;
|
||||||
_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.BootstrapDNS = BootstrapDNS;
|
||||||
_config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom;
|
_config.SimpleDNSItem.Strategy4Freedom = Strategy4Freedom;
|
||||||
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy;
|
_config.SimpleDNSItem.Strategy4Proxy = Strategy4Proxy;
|
||||||
|
_config.SimpleDNSItem.Strategy4ProxyDial = Strategy4ProxyDial;
|
||||||
_config.SimpleDNSItem.Hosts = Hosts;
|
_config.SimpleDNSItem.Hosts = Hosts;
|
||||||
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
||||||
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
||||||
_config.SimpleDNSItem.ServeStale = ServeStale;
|
_config.SimpleDNSItem.ServeStale = ServeStale;
|
||||||
|
_config.SimpleDNSItem.EnableHappyEyeballs = EnableHappyEyeballs;
|
||||||
if (NormalDNSCompatible.IsNotEmpty())
|
if (NormalDNSCompatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
||||||
|
|||||||
@@ -263,6 +263,11 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
|
|
||||||
#endregion AppEvents
|
#endregion AppEvents
|
||||||
|
|
||||||
|
ProfilesViewModel.RefreshServersRequested
|
||||||
|
.AsObservable()
|
||||||
|
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||||
|
.Subscribe(async _ => await RefreshServers());
|
||||||
|
|
||||||
var vmReloadRequestedList = new List<IObservable<Unit>>
|
var vmReloadRequestedList = new List<IObservable<Unit>>
|
||||||
{
|
{
|
||||||
ProfilesViewModel.ReloadRequested.AsObservable(),
|
ProfilesViewModel.ReloadRequested.AsObservable(),
|
||||||
@@ -394,8 +399,8 @@ public class MainWindowViewModel : MyReactiveObject
|
|||||||
|
|
||||||
private async Task RefreshServers()
|
private async Task RefreshServers()
|
||||||
{
|
{
|
||||||
await ProfilesViewModel.RefreshServers();
|
await ProfilesViewModel.RefreshServersBiz();
|
||||||
await StatusBarViewModel.RefreshServers();
|
await StatusBarViewModel.RefreshServersBiz();
|
||||||
|
|
||||||
// await Task.Delay(200);
|
// await Task.Delay(200);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,24 +29,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
[Reactive] public bool EnableFragment { get; set; }
|
[Reactive] public bool EnableFragment { get; set; }
|
||||||
[Reactive] public bool EnableFinalFragment { get; set; }
|
[Reactive] public bool EnableFinalFragment { get; set; }
|
||||||
[Reactive] public string FragmentPackets { get; set; }
|
[Reactive] public string FragmentPackets { get; set; }
|
||||||
[Reactive] public string FragmentLength { get; set; }
|
[Reactive] public string FragmentLengths { get; set; }
|
||||||
[Reactive] public string FragmentInterval { get; set; }
|
[Reactive] public string FragmentDelays { get; set; }
|
||||||
[Reactive] public string FragmentMaxSplit { get; set; }
|
[Reactive] public string FragmentMaxSplit { get; set; }
|
||||||
|
|
||||||
#endregion Core
|
#endregion Core
|
||||||
|
|
||||||
#region Core KCP
|
|
||||||
|
|
||||||
//[Reactive] public int Kcpmtu { get; set; }
|
|
||||||
//[Reactive] public int Kcptti { get; set; }
|
|
||||||
//[Reactive] public int KcpuplinkCapacity { get; set; }
|
|
||||||
//[Reactive] public int KcpdownlinkCapacity { get; set; }
|
|
||||||
//[Reactive] public int KcpreadBufferSize { get; set; }
|
|
||||||
//[Reactive] public int KcpwriteBufferSize { get; set; }
|
|
||||||
//[Reactive] public bool Kcpcongestion { get; set; }
|
|
||||||
|
|
||||||
#endregion Core KCP
|
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
[Reactive] public bool AutoRun { get; set; }
|
[Reactive] public bool AutoRun { get; set; }
|
||||||
@@ -150,6 +138,7 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
|
SecondLocalPortEnabled = inbound.SecondLocalPortEnabled;
|
||||||
UdpEnabled = inbound.UdpEnabled;
|
UdpEnabled = inbound.UdpEnabled;
|
||||||
SniffingEnabled = inbound.SniffingEnabled;
|
SniffingEnabled = inbound.SniffingEnabled;
|
||||||
|
DestOverride = inbound.DestOverride ?? [];
|
||||||
RouteOnly = inbound.RouteOnly;
|
RouteOnly = inbound.RouteOnly;
|
||||||
AllowLANConn = inbound.AllowLANConn;
|
AllowLANConn = inbound.AllowLANConn;
|
||||||
NewPort4LAN = inbound.NewPort4LAN;
|
NewPort4LAN = inbound.NewPort4LAN;
|
||||||
@@ -168,24 +157,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
EnableFragment = _config.CoreBasicItem.EnableFragment;
|
EnableFragment = _config.CoreBasicItem.EnableFragment;
|
||||||
EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment;
|
EnableFinalFragment = _config.CoreBasicItem.EnableFinalFragment;
|
||||||
FragmentPackets = _config.Fragment4RayItem?.Packets;
|
FragmentPackets = _config.Fragment4RayItem?.Packets;
|
||||||
FragmentLength = _config.Fragment4RayItem?.Length;
|
FragmentLengths = Utils.List2String(_config.Fragment4RayItem?.Lengths);
|
||||||
FragmentInterval = _config.Fragment4RayItem?.Interval;
|
FragmentDelays = Utils.List2String(_config.Fragment4RayItem?.Delays);
|
||||||
FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit;
|
FragmentMaxSplit = _config.Fragment4RayItem?.MaxSplit;
|
||||||
|
|
||||||
#endregion Core
|
#endregion Core
|
||||||
|
|
||||||
#region Core KCP
|
|
||||||
|
|
||||||
//Kcpmtu = _config.kcpItem.mtu;
|
|
||||||
//Kcptti = _config.kcpItem.tti;
|
|
||||||
//KcpuplinkCapacity = _config.kcpItem.uplinkCapacity;
|
|
||||||
//KcpdownlinkCapacity = _config.kcpItem.downlinkCapacity;
|
|
||||||
//KcpreadBufferSize = _config.kcpItem.readBufferSize;
|
|
||||||
//KcpwriteBufferSize = _config.kcpItem.writeBufferSize;
|
|
||||||
//Kcpcongestion = _config.kcpItem.congestion;
|
|
||||||
|
|
||||||
#endregion Core KCP
|
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
AutoRun = _config.GuiItem.AutoRun;
|
AutoRun = _config.GuiItem.AutoRun;
|
||||||
@@ -309,34 +286,33 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
NoticeManager.Instance.Enqueue(ResUI.FillLocalListeningPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var fragmentLengths = Utils.String2List(FragmentLengths) ?? [];
|
||||||
|
var fragmentDelays = Utils.String2List(FragmentDelays) ?? [];
|
||||||
|
if (fragmentLengths.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|
||||||
|
|| fragmentDelays.Any(item => !Utils.TryParseRange(item, 0, int.MaxValue, out _, out _))
|
||||||
|
|| (FragmentMaxSplit.IsNotEmpty() && !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _)))
|
||||||
|
{
|
||||||
|
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|
var needReboot = EnableStatistics != _config.GuiItem.EnableStatistics
|
||||||
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
|| DisplayRealTimeSpeed != _config.GuiItem.DisplayRealTimeSpeed
|
||||||
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
|| EnableDragDropSort != _config.UiItem.EnableDragDropSort
|
||||||
|| EnableHWA != _config.GuiItem.EnableHWA
|
|| EnableHWA != _config.GuiItem.EnableHWA
|
||||||
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily;
|
|| CurrentFontFamily != _config.UiItem.CurrentFontFamily;
|
||||||
|
|
||||||
//if (Utile.IsNullOrEmpty(Kcpmtu.ToString()) || !Utile.IsNumeric(Kcpmtu.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(Kcptti.ToString()) || !Utile.IsNumeric(Kcptti.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpuplinkCapacity.ToString()) || !Utile.IsNumeric(KcpuplinkCapacity.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpdownlinkCapacity.ToString()) || !Utile.IsNumeric(KcpdownlinkCapacity.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpreadBufferSize.ToString()) || !Utile.IsNumeric(KcpreadBufferSize.ToString())
|
|
||||||
// || Utile.IsNullOrEmpty(KcpwriteBufferSize.ToString()) || !Utile.IsNumeric(KcpwriteBufferSize.ToString()))
|
|
||||||
//{
|
|
||||||
// NoticeHandler.Instance.Enqueue(ResUI.FillKcpParameters);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//Core
|
//Core
|
||||||
_config.Inbound.First().LocalPort = LocalPort;
|
var inbound = _config.Inbound.First();
|
||||||
_config.Inbound.First().SecondLocalPortEnabled = SecondLocalPortEnabled;
|
inbound.LocalPort = LocalPort;
|
||||||
_config.Inbound.First().UdpEnabled = UdpEnabled;
|
inbound.SecondLocalPortEnabled = SecondLocalPortEnabled;
|
||||||
_config.Inbound.First().SniffingEnabled = SniffingEnabled;
|
inbound.UdpEnabled = UdpEnabled;
|
||||||
_config.Inbound.First().DestOverride = DestOverride?.ToList();
|
inbound.SniffingEnabled = SniffingEnabled;
|
||||||
_config.Inbound.First().RouteOnly = RouteOnly;
|
inbound.DestOverride = DestOverride?.ToList();
|
||||||
_config.Inbound.First().AllowLANConn = AllowLANConn;
|
inbound.RouteOnly = RouteOnly;
|
||||||
_config.Inbound.First().NewPort4LAN = NewPort4LAN;
|
inbound.AllowLANConn = AllowLANConn;
|
||||||
_config.Inbound.First().User = User;
|
inbound.NewPort4LAN = NewPort4LAN;
|
||||||
_config.Inbound.First().Pass = Pass;
|
inbound.User = User;
|
||||||
|
inbound.Pass = Pass;
|
||||||
if (_config.Inbound.Count > 1)
|
if (_config.Inbound.Count > 1)
|
||||||
{
|
{
|
||||||
_config.Inbound.RemoveAt(1);
|
_config.Inbound.RemoveAt(1);
|
||||||
@@ -351,30 +327,12 @@ public class OptionSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox;
|
_config.CoreBasicItem.EnableCacheFile4Sbox = EnableCacheFile4Sbox;
|
||||||
_config.HysteriaItem.UpMbps = HyUpMbps ?? 0;
|
_config.HysteriaItem.UpMbps = HyUpMbps ?? 0;
|
||||||
_config.HysteriaItem.DownMbps = HyDownMbps ?? 0;
|
_config.HysteriaItem.DownMbps = HyDownMbps ?? 0;
|
||||||
if (EnableFragment)
|
|
||||||
{
|
|
||||||
if (!Utils.TryParseRange(FragmentLength, 0, int.MaxValue, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!Utils.TryParseRange(FragmentInterval, 1, 100, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (FragmentMaxSplit.IsNotEmpty()
|
|
||||||
&& !Utils.TryParseMaxSplit(FragmentMaxSplit, 0, 10000, out _, out _))
|
|
||||||
{
|
|
||||||
NoticeManager.Instance.Enqueue(ResUI.FillFragmentParameterError);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_config.CoreBasicItem.EnableFragment = EnableFragment;
|
_config.CoreBasicItem.EnableFragment = EnableFragment;
|
||||||
_config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment;
|
_config.CoreBasicItem.EnableFinalFragment = EnableFinalFragment;
|
||||||
|
_config.Fragment4RayItem ??= new();
|
||||||
_config.Fragment4RayItem.Packets = FragmentPackets;
|
_config.Fragment4RayItem.Packets = FragmentPackets;
|
||||||
_config.Fragment4RayItem.Length = FragmentLength;
|
_config.Fragment4RayItem.Lengths = fragmentLengths;
|
||||||
_config.Fragment4RayItem.Interval = FragmentInterval;
|
_config.Fragment4RayItem.Delays = fragmentDelays;
|
||||||
_config.Fragment4RayItem.MaxSplit = FragmentMaxSplit;
|
_config.Fragment4RayItem.MaxSplit = FragmentMaxSplit;
|
||||||
|
|
||||||
_config.GuiItem.AutoRun = AutoRun;
|
_config.GuiItem.AutoRun = AutoRun;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
public Interaction<Unit, Unit> AdjustMainLvColWidthInteraction { get; } = new();
|
public Interaction<Unit, Unit> AdjustMainLvColWidthInteraction { get; } = new();
|
||||||
|
|
||||||
public EventChannel<Unit> ReloadRequested { get; } = new();
|
public EventChannel<Unit> ReloadRequested { get; } = new();
|
||||||
|
public EventChannel<Unit> RefreshServersRequested { get; } = new();
|
||||||
|
|
||||||
#region private prop
|
#region private prop
|
||||||
|
|
||||||
@@ -368,12 +369,14 @@ public class ProfilesViewModel : MyReactiveObject
|
|||||||
|
|
||||||
public async Task RefreshServers()
|
public async Task RefreshServers()
|
||||||
{
|
{
|
||||||
await RefreshServersBiz();
|
RefreshServersRequested.Publish();
|
||||||
|
|
||||||
// await Task.Delay(200);
|
// await Task.Delay(200);
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshServersBiz()
|
public async Task RefreshServersBiz()
|
||||||
{
|
{
|
||||||
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
var lstModel = await GetProfileItemsEx(_config.SubIndexId, _serverFilter);
|
||||||
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
|
||||||
|
|||||||
@@ -264,12 +264,7 @@ public class StatusBarViewModel : MyReactiveObject
|
|||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshServers()
|
public async Task RefreshServersBiz()
|
||||||
{
|
|
||||||
await RefreshServersBiz();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RefreshServersBiz()
|
|
||||||
{
|
{
|
||||||
await RefreshServersMenu();
|
await RefreshServersMenu();
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -43,11 +48,6 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Context menu actions that require custom logic (Add, SelectAll)
|
// Context menu actions that require custom logic (Add, SelectAll)
|
||||||
|
|||||||
@@ -38,6 +38,11 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||||
@@ -188,11 +193,6 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
x:Name="gridBasicDNSSettings"
|
x:Name="gridBasicDNSSettings"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
ColumnDefinitions="Auto,Auto,*"
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="txtBasicDNSSettingsInvalid"
|
x:Name="txtBasicDNSSettingsInvalid"
|
||||||
@@ -167,28 +167,71 @@
|
|||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategy}" />
|
||||||
<ToggleSwitch
|
<ComboBox
|
||||||
x:Name="togParallelQuery"
|
x:Name="cmbProxyDialDNSStrategy"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center" />
|
PlaceholderText="Default" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbServeStale}" />
|
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
||||||
<ToggleSwitch
|
<ToggleSwitch
|
||||||
x:Name="togServeStale"
|
x:Name="togParallelQuery"
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbServeStale}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togServeStale"
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -243,13 +286,24 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
||||||
<ToggleSwitch
|
<Grid
|
||||||
x:Name="togFakeIP"
|
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin4}"
|
ColumnDefinitions="Auto,*">
|
||||||
HorizontalAlignment="Left"
|
<ToggleSwitch
|
||||||
VerticalAlignment="Center" />
|
x:Name="togFakeIP"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbFakeIPRange"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsEditable="True" />
|
||||||
|
</Grid>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
@@ -318,8 +372,8 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap"
|
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}"
|
||||||
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
|
|
||||||
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
|
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
|
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||||
@@ -31,16 +33,19 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||||
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.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
@@ -347,7 +347,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" />
|
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentLength"
|
x:Name="txtFragmentLengths"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="120"
|
Width="120"
|
||||||
@@ -369,7 +369,7 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" />
|
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentInterval"
|
x:Name="txtFragmentDelays"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="120"
|
Width="120"
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
@@ -35,11 +40,6 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
|
|||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ public partial class AddGroupServerWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.Text).DisposeWith(disposables);
|
||||||
@@ -45,11 +50,6 @@ public partial class AddGroupServerWindow
|
|||||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ public partial class AddServerWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
var configTypeBindings = new SerialDisposable().DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.Text).DisposeWith(disposables);
|
||||||
@@ -186,11 +191,6 @@ public partial class AddServerWindow
|
|||||||
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertCmd, v => v.btnFetchCert).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.FetchCertChainCmd, v => v.btnFetchCertChain).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
|
|||||||
@@ -52,6 +52,8 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -195,13 +197,23 @@
|
|||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategy}" />
|
||||||
<ToggleButton
|
<ComboBox
|
||||||
x:Name="togParallelQuery"
|
x:Name="cmbProxyDialDNSStrategy"
|
||||||
Grid.Row="7"
|
Grid.Row="7"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
materialDesign:HintAssist.Hint="Default"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbProxyDialResolveStrategyTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
@@ -209,13 +221,49 @@
|
|||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbServeStale}" />
|
Text="{x:Static resx:ResUI.TbParallelQuery}" />
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
x:Name="togServeStale"
|
x:Name="togParallelQuery"
|
||||||
Grid.Row="8"
|
Grid.Row="8"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbServeStale}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togServeStale"
|
||||||
|
Grid.Row="9"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -283,12 +331,25 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Style="{StaticResource ToolbarTextBlock}"
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
Text="{x:Static resx:ResUI.TbFakeIP}" />
|
||||||
<ToggleButton
|
<Grid Grid.Row="3" Grid.Column="1">
|
||||||
x:Name="togFakeIP"
|
<Grid.ColumnDefinitions>
|
||||||
Grid.Row="3"
|
<ColumnDefinition Width="Auto" />
|
||||||
Grid.Column="1"
|
<ColumnDefinition Width="*" />
|
||||||
Margin="{StaticResource Margin8}"
|
</Grid.ColumnDefinitions>
|
||||||
HorizontalAlignment="Left" />
|
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togFakeIP"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbFakeIPRange"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
IsEditable="True"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
</Grid>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ public partial class DNSSettingWindow
|
|||||||
|
|
||||||
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbDirectDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
cmbRemoteDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
|
cmbProxyDialDNSStrategy.ItemsSource = Global.DomainStrategy;
|
||||||
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
cmbDirectDNS.ItemsSource = Global.DomainDirectDNSAddress;
|
||||||
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
cmbRemoteDNS.ItemsSource = Global.DomainRemoteDNSAddress;
|
||||||
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
cmbBootstrapDNS.ItemsSource = Global.DomainPureIPDNSAddress;
|
||||||
|
cmbFakeIPRange.ItemsSource = Global.FakeIPRanges;
|
||||||
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
cmbDirectExpectedIPs.ItemsSource = Global.ExpectedIPs;
|
||||||
|
|
||||||
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
cmbdomainStrategy4FreedomCompatible.ItemsSource = Global.DomainStrategy;
|
||||||
@@ -27,16 +29,19 @@ public partial class DNSSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.UseSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AddCommonHosts, v => v.togAddCommonHosts.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FakeIP, v => v.togFakeIP.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.FakeIPRange, v => v.cmbFakeIPRange.Text).DisposeWith(disposables);
|
||||||
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.BootstrapDNS, v => v.cmbBootstrapDNS.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Freedom, v => v.cmbDirectDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Strategy4Proxy, v => v.cmbRemoteDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.Strategy4ProxyDial, v => v.cmbProxyDialDNSStrategy.SelectedItem).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.Hosts, v => v.txtHosts.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
@@ -419,7 +419,7 @@
|
|||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}"
|
Text="{x:Static resx:ResUI.TbSettingsFragmentLength}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentLength"
|
x:Name="txtFragmentLengths"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
@@ -437,7 +437,7 @@
|
|||||||
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}"
|
Text="{x:Static resx:ResUI.TbSettingsFragmentInterval}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="txtFragmentInterval"
|
x:Name="txtFragmentDelays"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ public partial class OptionSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.EnableFinalFragment, v => v.togenableFinalFragment.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentPackets, v => v.cmbFragmentPackets.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentLength, v => v.txtFragmentLength.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentLengths, v => v.txtFragmentLengths.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentInterval, v => v.txtFragmentInterval.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentDelays, v => v.txtFragmentDelays.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.FragmentMaxSplit, v => v.txtFragmentMaxSplit.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);
|
//this.Bind(ViewModel, vm => vm.Kcpmtu, v => v.txtKcpmtu.Text).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
|
|
||||||
this.WhenActivated(disposables =>
|
this.WhenActivated(disposables =>
|
||||||
{
|
{
|
||||||
|
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
||||||
|
.WhereNotNull()
|
||||||
|
.Subscribe(InitializeData)
|
||||||
|
.DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||||
@@ -31,11 +36,6 @@ public partial class RoutingRuleDetailsWindow
|
|||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SelectProfileCmd, v => v.btnSelectProfile).DisposeWith(disposables);
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
this.WhenAnyValue(v => v.ViewModel.SelectedSource)
|
|
||||||
.WhereNotNull()
|
|
||||||
.Subscribe(InitializeData)
|
|
||||||
.DisposeWith(disposables);
|
|
||||||
});
|
});
|
||||||
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ public partial class StatusBarView
|
|||||||
interaction.SetOutput(Unit.Default);
|
interaction.SetOutput(Unit.Default);
|
||||||
}).DisposeWith(disposables);
|
}).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_ = RefreshIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshIcon()
|
private async Task RefreshIcon()
|
||||||
|
|||||||
Reference in New Issue
Block a user