Compare commits

..

23 Commits

Author SHA1 Message Date
2dust
5201dd5ad0 up 7.14.1 2025-08-17 14:26:13 +08:00
2dust
4c3c1e0b5f Optimization and upgrade tools 2025-08-17 14:12:40 +08:00
DHR60
c27651b7b7 Fixed Failed Gen Default Configuration (#7785) 2025-08-17 13:52:57 +08:00
2dust
06636d04ac PacHandler is changed to singleton mode 2025-08-17 11:00:13 +08:00
DHR60
6979e21628 Remove DomainMatcher (#7781) 2025-08-17 09:32:02 +08:00
DHR60
310d266745 Add VLESS encryption support (#7782) 2025-08-17 09:15:06 +08:00
2dust
120e8d0686 Fixed a bug in parsing subscription result
https://github.com/2dust/v2rayN/issues/7734
2025-08-16 20:05:56 +08:00
2dust
186b56aed9 Refactor SubscriptionHandler and add exception capture 2025-08-16 18:01:12 +08:00
2dust
c560fe13fe Adjust the tun mtu value list
https://github.com/2dust/v2rayN/issues/7775
2025-08-16 17:18:17 +08:00
2dust
95e3ebd815 up 7.14.0 2025-08-15 17:18:16 +08:00
2dust
dc2877d817 Refactor UpdateSubscriptionProcess ,add SubscriptionHandler 2025-08-14 20:59:15 +08:00
2dust
89d6af8fc9 Added global constants such as IPIfNonMatch 2025-08-14 20:18:22 +08:00
DHR60
dcc9c9fa14 Fixes DNS (#7757)
* Adds properties

* Adds DNS routing
2025-08-14 17:32:48 +08:00
DHR60
a73906505c Improves domain blocking and proxy handling (#7754) 2025-08-14 09:30:58 +08:00
2dust
f45290eb3a Fixed a bug in dns rule processing when outbound in routing rules is a other server 2025-08-13 21:19:51 +08:00
2dust
0fb6b2e54b Bug fix for DNS setting 2025-08-13 18:43:15 +08:00
2dust
9cc99c5c63 Update Directory.Packages.props 2025-08-13 18:41:57 +08:00
dependabot[bot]
46801ce339 Bump actions/checkout from 4.2.2 to 5.0.0 (#7749)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.2.2...v5.0.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-13 08:39:18 +08:00
2dust
4345c58b45 Bug fix for FullConfigTemplate xray 2025-08-12 20:23:37 +08:00
Miheichev Aleksandr Sergeevich
a2028623e7 refactor: improve Russian localization, fix placeholders and typos (#7740)
Co-authored-by: Aleksandr Miheichev <alexandr.gmail@tuta.com>
2025-08-12 19:28:40 +08:00
Summpot
8314ff3271 Add Auto Route option to Tun mode settings (#7737)
Introduces a new 'Auto Route' option for Tun mode in the configuration, view models, and UI. Updates both Avalonia and WPF option setting windows to allow users to enable or disable automatic routing for Tun mode. Also ensures the new setting is properly bound and saved in the configuration.
2025-08-12 19:18:26 +08:00
DHR60
6a9408fe9b Fixes sing-box system hosts and ui (#7733) 2025-08-11 20:46:35 +08:00
DHR60
b5e0a77401 Full Config Template (#7576)
* Feat. custom config

* Fixes TypeInfoResolver Exception

* Adjust UI

* Fixes

* Adjust Avalonia UI

* Add Detour Feature

* Avoids detour for private networks

* Rename

* Adds Documents
2025-08-11 20:01:48 +08:00
56 changed files with 1666 additions and 370 deletions

View File

@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v5.0.0
with:
submodules: 'recursive'
fetch-depth: '0'

View File

@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v5.0.0
with:
submodules: 'recursive'
fetch-depth: '0'

View File

@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v5.0.0
with:
submodules: 'recursive'
fetch-depth: '0'

View File

@@ -27,7 +27,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v5.0.0
- name: Setup
uses: actions/setup-dotnet@v4.3.1

View File

@@ -79,15 +79,7 @@ internal class UpgradeApp
continue;
}
try
{
entry.ExtractToFile(entryOutputPath, true);
}
catch
{
Thread.Sleep(1000);
entry.ExtractToFile(entryOutputPath, true);
}
TryExtractToFile(entry, entryOutputPath);
Console.WriteLine(entryOutputPath);
}
@@ -113,4 +105,24 @@ internal class UpgradeApp
Utils.StartV2RayN();
}
private static bool TryExtractToFile(ZipArchiveEntry entry, string outputPath)
{
var retryCount = 5;
var delayMs = 1000;
for (var i = 1; i <= retryCount; i++)
{
try
{
entry.ExtractToFile(outputPath, true);
return true;
}
catch
{
Thread.Sleep(delayMs * i);
}
}
return false;
}
}

View File

@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Version>7.13.7</Version>
<Version>7.14.1</Version>
</PropertyGroup>
<PropertyGroup>

View File

@@ -10,7 +10,7 @@
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.3" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.3" />
<PackageVersion Include="CliWrap" Version="3.9.0" />
<PackageVersion Include="Downloader" Version="4.0.2" />
<PackageVersion Include="Downloader" Version="4.0.3" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />

View File

@@ -29,6 +29,7 @@ public enum EViewAction
DNSSettingWindow,
RoutingSettingWindow,
OptionSettingWindow,
FullConfigTemplateWindow,
GlobalHotkeySettingWindow,
SubSettingWindow,
DispatcherSpeedTest,

View File

@@ -48,6 +48,7 @@ public class Global
public const string ProxyTag = "proxy";
public const string DirectTag = "direct";
public const string BlockTag = "block";
public const string DnsTag = "dns-module";
public const string StreamSecurity = "tls";
public const string StreamSecurityReality = "reality";
public const string Loopback = "127.0.0.1";
@@ -56,6 +57,9 @@ public class Global
public const string HttpsProtocol = "https://";
public const string SocksProtocol = "socks://";
public const string Socks5Protocol = "socks5://";
public const string AsIs = "AsIs";
public const string IPIfNonMatch = "IPIfNonMatch";
public const string IPOnDemand = "IPOnDemand";
public const string UserEMail = "t@t.tt";
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
@@ -287,9 +291,9 @@ public class Global
public static readonly List<string> DomainStrategies =
[
"AsIs",
"IPIfNonMatch",
"IPOnDemand"
AsIs,
IPIfNonMatch,
IPOnDemand
];
public static readonly List<string> DomainStrategies4Singbox =
@@ -301,13 +305,6 @@ public class Global
""
];
public static readonly List<string> DomainMatchers =
[
"linear",
"mph",
""
];
public static readonly List<string> Fingerprints =
[
"chrome",
@@ -462,7 +459,9 @@ public class Global
1280,
1408,
1500,
9000
4064,
9000,
65535
];
public static readonly List<string> TunStacks =

View File

@@ -64,6 +64,7 @@ public sealed class AppHandler
SQLiteHelper.Instance.CreateTable<RoutingItem>();
SQLiteHelper.Instance.CreateTable<ProfileExItem>();
SQLiteHelper.Instance.CreateTable<DNSItem>();
SQLiteHelper.Instance.CreateTable<FullConfigTemplateItem>();
return true;
}
@@ -203,6 +204,16 @@ public sealed class AppHandler
return await SQLiteHelper.Instance.TableAsync<DNSItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
}
public async Task<List<FullConfigTemplateItem>?> FullConfigTemplateItem()
{
return await SQLiteHelper.Instance.TableAsync<FullConfigTemplateItem>().ToListAsync();
}
public async Task<FullConfigTemplateItem?> GetFullConfigTemplateItem(ECoreType eCoreType)
{
return await SQLiteHelper.Instance.TableAsync<FullConfigTemplateItem>().FirstOrDefaultAsync(it => it.CoreType == eCoreType);
}
#endregion SqliteHelper
#region Core Type

View File

@@ -963,7 +963,7 @@ public class ConfigHandler
{
return -1;
}
if (profileItem.Security.IsNotEmpty() && profileItem.Security != Global.None)
if (profileItem.Security.IsNullOrEmpty())
{
profileItem.Security = Global.None;
}
@@ -1412,6 +1412,11 @@ public class ConfigHandler
{
profileItem = V2rayFmt.ResolveFull(strData, subRemarks);
}
//Is Html Page
if (profileItem is null && HtmlPageFmt.IsHtmlPage(strData))
{
return -1;
}
//Is Clash configuration
if (profileItem is null)
{
@@ -2238,6 +2243,55 @@ public class ConfigHandler
#endregion Simple DNS
#region Custom Config
public static async Task<int> InitBuiltinFullConfigTemplate(Config config)
{
var items = await AppHandler.Instance.FullConfigTemplateItem();
if (items.Count <= 0)
{
var item = new FullConfigTemplateItem()
{
Remarks = "V2ray",
CoreType = ECoreType.Xray,
};
await SaveFullConfigTemplate(config, item);
var item2 = new FullConfigTemplateItem()
{
Remarks = "sing-box",
CoreType = ECoreType.sing_box,
};
await SaveFullConfigTemplate(config, item2);
}
return 0;
}
public static async Task<int> SaveFullConfigTemplate(Config config, FullConfigTemplateItem item)
{
if (item == null)
{
return -1;
}
if (item.Id.IsNullOrEmpty())
{
item.Id = Utils.GetGuid(false);
}
if (await SQLiteHelper.Instance.ReplaceAsync(item) > 0)
{
return 0;
}
else
{
return -1;
}
}
#endregion Custom Config
#region Regional Presets
/// <summary>

View File

@@ -220,14 +220,7 @@ public class BaseFmt
protected static bool Contains(string str, params string[] s)
{
foreach (var item in s)
{
if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
return s.All(item => str.Contains(item, StringComparison.OrdinalIgnoreCase));
}
protected static string WriteAllText(string strData, string ext = "json")

View File

@@ -0,0 +1,11 @@
using SkiaSharp;
namespace ServiceLib.Handler.Fmt;
public class HtmlPageFmt : BaseFmt
{
public static bool IsHtmlPage(string strData)
{
return Contains(strData, "<html", "<!doctype html", "<head");
}
}

View File

@@ -5,15 +5,18 @@ namespace ServiceLib.Handler;
public class PacHandler
{
private static string _configPath;
private static int _httpPort;
private static int _pacPort;
private static TcpListener? _tcpListener;
private static byte[] _writeContent;
private static bool _isRunning;
private static bool _needRestart = true;
private static readonly Lazy<PacHandler> _instance = new(() => new PacHandler());
public static PacHandler Instance => _instance.Value;
public static async Task Start(string configPath, int httpPort, int pacPort)
private string _configPath;
private int _httpPort;
private int _pacPort;
private TcpListener? _tcpListener;
private byte[] _writeContent;
private bool _isRunning;
private bool _needRestart = true;
public async Task StartAsync(string configPath, int httpPort, int pacPort)
{
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
@@ -30,7 +33,7 @@ public class PacHandler
}
}
private static async Task InitText()
private async Task InitText()
{
var path = Path.Combine(_configPath, "pac.txt");
@@ -59,7 +62,7 @@ public class PacHandler
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
}
private static void RunListener()
private void RunListener()
{
_tcpListener = TcpListener.Create(_pacPort);
_isRunning = true;
@@ -87,14 +90,14 @@ public class PacHandler
}, TaskCreationOptions.LongRunning);
}
private static void WriteContent(TcpClient client)
private void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop()
public void Stop()
{
if (_tcpListener == null)
{

View File

@@ -0,0 +1,214 @@
namespace ServiceLib.Handler;
public class SubscriptionHandler
{
public static async Task UpdateProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc)
{
updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart);
var subItem = await AppHandler.Instance.SubItems();
if (subItem is not { Count: > 0 })
{
updateFunc?.Invoke(false, ResUI.MsgNoValidSubscription);
return;
}
foreach (var item in subItem)
{
try
{
if (!IsValidSubscription(item, subId))
{
continue;
}
var hashCode = $"{item.Remarks}->";
if (item.Enabled == false)
{
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
continue;
}
// Create download handler
var downloadHandle = CreateDownloadHandler(hashCode, updateFunc);
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
// Get all subscription content (main subscription + additional subscriptions)
var result = await DownloadAllSubscriptions(config, item, blProxy, downloadHandle);
// Process download result
await ProcessDownloadResult(config, item.Id, result, hashCode, updateFunc);
updateFunc?.Invoke(false, "-------------------------------------------------------");
}
catch (Exception ex)
{
var hashCode = $"{item.Remarks}->";
Logging.SaveLog("UpdateSubscription", ex);
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgFailedImportSubscription}: {ex.Message}");
updateFunc?.Invoke(false, "-------------------------------------------------------");
}
}
updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}
private static bool IsValidSubscription(SubItem item, string subId)
{
var id = item.Id.TrimEx();
var url = item.Url.TrimEx();
if (id.IsNullOrEmpty() || url.IsNullOrEmpty())
{
return false;
}
if (subId.IsNotEmpty() && item.Id != subId)
{
return false;
}
if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
{
return false;
}
return true;
}
private static DownloadService CreateDownloadHandler(string hashCode, Action<bool, string> updateFunc)
{
var downloadHandle = new DownloadService();
downloadHandle.Error += (sender2, args) =>
{
updateFunc?.Invoke(false, $"{hashCode}{args.GetException().Message}");
};
return downloadHandle;
}
private static async Task<string> DownloadSubscriptionContent(DownloadService downloadHandle, string url, bool blProxy, string userAgent)
{
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
// If download with proxy fails, try direct connection
if (blProxy && result.IsNullOrEmpty())
{
result = await downloadHandle.TryDownloadString(url, false, userAgent);
}
return result ?? string.Empty;
}
private static async Task<string> DownloadAllSubscriptions(Config config, SubItem item, bool blProxy, DownloadService downloadHandle)
{
// Download main subscription content
var result = await DownloadMainSubscription(config, item, blProxy, downloadHandle);
// Process additional subscription links (if any)
if (item.ConvertTarget.IsNullOrEmpty() && item.MoreUrl.TrimEx().IsNotEmpty())
{
result = await DownloadAdditionalSubscriptions(item, result, blProxy, downloadHandle);
}
return result;
}
private static async Task<string> DownloadMainSubscription(Config config, SubItem item, bool blProxy, DownloadService downloadHandle)
{
// Prepare subscription URL and download directly
var url = Utils.GetPunycode(item.Url.TrimEx());
// If conversion is needed
if (item.ConvertTarget.IsNotEmpty())
{
var subConvertUrl = config.ConstItem.SubConvertUrl.IsNullOrEmpty()
? Global.SubConvertUrls.FirstOrDefault()
: config.ConstItem.SubConvertUrl;
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
if (!url.Contains("target="))
{
url += string.Format("&target={0}", item.ConvertTarget);
}
if (!url.Contains("config="))
{
url += string.Format("&config={0}", Global.SubConvertConfig.FirstOrDefault());
}
}
// Download and return result directly
return await DownloadSubscriptionContent(downloadHandle, url, blProxy, item.UserAgent);
}
private static async Task<string> DownloadAdditionalSubscriptions(SubItem item, string mainResult, bool blProxy, DownloadService downloadHandle)
{
var result = mainResult;
// If main subscription result is Base64 encoded, decode it first
if (result.IsNotEmpty() && Utils.IsBase64String(result))
{
result = Utils.Base64Decode(result);
}
// Process additional URL list
var lstUrl = item.MoreUrl.TrimEx().Split(",") ?? [];
foreach (var it in lstUrl)
{
var url2 = Utils.GetPunycode(it);
if (url2.IsNullOrEmpty())
{
continue;
}
var additionalResult = await DownloadSubscriptionContent(downloadHandle, url2, blProxy, item.UserAgent);
if (additionalResult.IsNotEmpty())
{
// Process additional subscription results, add to main result
if (Utils.IsBase64String(additionalResult))
{
result += Environment.NewLine + Utils.Base64Decode(additionalResult);
}
else
{
result += Environment.NewLine + additionalResult;
}
}
}
return result;
}
private static async Task ProcessDownloadResult(Config config, string id, string result, string hashCode, Action<bool, string> updateFunc)
{
if (result.IsNullOrEmpty())
{
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}");
return;
}
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
// If result is too short, display content directly
if (result.Length < 99)
{
updateFunc?.Invoke(false, $"{hashCode}{result}");
}
// Add servers to configuration
var ret = await ConfigHandler.AddBatchServers(config, result, id, true);
if (ret <= 0)
{
Logging.SaveLog("FailedImportSubscription");
Logging.SaveLog(result);
}
// Update completion message
updateFunc?.Invoke(false,
ret > 0
? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}"
: $"{hashCode}{ResUI.MsgFailedImportSubscription}");
}
}

View File

@@ -56,7 +56,7 @@ public static class SysProxyHandler
if (type != ESysProxyType.Pac && Utils.IsWindows())
{
PacHandler.Stop();
PacHandler.Instance.Stop();
}
}
catch (Exception ex)
@@ -91,7 +91,7 @@ public static class SysProxyHandler
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
await PacHandler.Instance.StartAsync(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}

View File

@@ -63,11 +63,10 @@ public class TaskHandler
}
Logging.SaveLog("Execute update subscription");
var updateHandle = new UpdateService();
foreach (var item in lstSubs)
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
await SubscriptionHandler.UpdateProcess(config, item.Id, true, (bool success, string msg) =>
{
updateFunc?.Invoke(success, msg);
if (success)

View File

@@ -142,6 +142,7 @@ public class CoreTypeItem
public class TunModeItem
{
public bool EnableTun { get; set; }
public bool AutoRoute { get; set; } = true;
public bool StrictRoute { get; set; } = true;
public string Stack { get; set; }
public int Mtu { get; set; }
@@ -164,7 +165,6 @@ public class RoutingBasicItem
{
public string DomainStrategy { get; set; }
public string DomainStrategy4Singbox { get; set; }
public string DomainMatcher { get; set; }
public string RoutingIndexId { get; set; }
}

View File

@@ -0,0 +1,18 @@
using SQLite;
namespace ServiceLib.Models;
[Serializable]
public class FullConfigTemplateItem
{
[PrimaryKey]
public string Id { get; set; }
public string Remarks { get; set; }
public bool Enabled { get; set; } = false;
public ECoreType CoreType { get; set; }
public string? Config { get; set; }
public string? TunConfig { get; set; }
public bool? AddProxyOnly { get; set; } = false;
public string? ProxyDetour { get; set; }
}

View File

@@ -203,8 +203,15 @@ public class Response4Ray
public class Dns4Ray
{
public Dictionary<string, List<string>>? hosts { get; set; }
public Dictionary<string, object>? hosts { get; set; }
public List<object> servers { get; set; }
public string? clientIp { get; set; }
public string? queryStrategy { get; set; }
public bool? disableCache { get; set; }
public bool? disableFallback { get; set; }
public bool? disableFallbackIfMatch { get; set; }
public bool? useSystemHosts { get; set; }
public string? tag { get; set; }
}
public class DnsServer4Ray
@@ -214,14 +221,18 @@ public class DnsServer4Ray
public bool? skipFallback { get; set; }
public List<string>? expectedIPs { get; set; }
public List<string>? unexpectedIPs { get; set; }
public string? clientIp { get; set; }
public string? queryStrategy { get; set; }
public int? timeoutMs { get; set; }
public bool? disableCache { get; set; }
public bool? finalQuery { get; set; }
public string? tag { get; set; }
}
public class Routing4Ray
{
public string domainStrategy { get; set; }
public string? domainMatcher { get; set; }
public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; }

View File

@@ -186,6 +186,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Please fill in the correct config template 的本地化字符串。
/// </summary>
public static string FillCorrectConfigTemplateText {
get {
return ResourceManager.GetString("FillCorrectConfigTemplateText", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please fill in the correct custom DNS 的本地化字符串。
/// </summary>
@@ -933,6 +942,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Full Config Template Setting 的本地化字符串。
/// </summary>
public static string menuFullConfigTemplate {
get {
return ResourceManager.GetString("menuFullConfigTemplate", resourceCulture);
}
}
/// <summary>
/// 查找类似 Global Hotkey Setting 的本地化字符串。
/// </summary>
@@ -2229,6 +2247,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Do Not Add Non-Proxy Protocol Outbound 的本地化字符串。
/// </summary>
public static string TbAddProxyProtocolOutboundOnly {
get {
return ResourceManager.GetString("TbAddProxyProtocolOutboundOnly", resourceCulture);
}
}
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>
@@ -2310,6 +2337,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Prevent domain-based routing rules from failing 的本地化字符串。
/// </summary>
public static string TbBlockSVCBHTTPSQueriesTips {
get {
return ResourceManager.GetString("TbBlockSVCBHTTPSQueriesTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 Browse 的本地化字符串。
/// </summary>
@@ -2427,15 +2463,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Domain Matcher 的本地化字符串。
/// </summary>
public static string TbdomainMatcher {
get {
return ResourceManager.GetString("TbdomainMatcher", resourceCulture);
}
}
/// <summary>
/// 查找类似 Domain strategy 的本地化字符串。
/// </summary>
@@ -2508,6 +2535,24 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core&apos;s basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you. 的本地化字符串。
/// </summary>
public static string TbFullConfigTemplateDesc {
get {
return ResourceManager.GetString("TbFullConfigTemplateDesc", resourceCulture);
}
}
/// <summary>
/// 查找类似 Enable Full Config Template 的本地化字符串。
/// </summary>
public static string TbFullConfigTemplateEnable {
get {
return ResourceManager.GetString("TbFullConfigTemplateEnable", resourceCulture);
}
}
/// <summary>
/// 查找类似 Global Hotkey Settings 的本地化字符串。
/// </summary>
@@ -2688,15 +2733,6 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Prevent DNS Leaks 的本地化字符串。
/// </summary>
public static string TbPreventDNSLeaks {
get {
return ResourceManager.GetString("TbPreventDNSLeaks", resourceCulture);
}
}
/// <summary>
/// 查找类似 Private Key 的本地化字符串。
/// </summary>
@@ -2724,6 +2760,24 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 v2ray Full Config Template 的本地化字符串。
/// </summary>
public static string TbRayFullConfigTemplate {
get {
return ResourceManager.GetString("TbRayFullConfigTemplate", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document 的本地化字符串。
/// </summary>
public static string TbRayFullConfigTemplateDesc {
get {
return ResourceManager.GetString("TbRayFullConfigTemplateDesc", resourceCulture);
}
}
/// <summary>
/// 查找类似 Alias (remarks) 的本地化字符串。
/// </summary>
@@ -2886,6 +2940,24 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 sing-box Full Config Template 的本地化字符串。
/// </summary>
public static string TbSBFullConfigTemplate {
get {
return ResourceManager.GetString("TbSBFullConfigTemplate", resourceCulture);
}
}
/// <summary>
/// 查找类似 Add Outbound and Endpoint Config Only, Click to view the document 的本地化字符串。
/// </summary>
public static string TbSBFullConfigTemplateDesc {
get {
return ResourceManager.GetString("TbSBFullConfigTemplateDesc", resourceCulture);
}
}
/// <summary>
/// 查找类似 Resolve Outbound Domains 的本地化字符串。
/// </summary>
@@ -3696,6 +3768,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Set Upstream Proxy Tag 的本地化字符串。
/// </summary>
public static string TbSetUpstreamProxyDetour {
get {
return ResourceManager.GetString("TbSetUpstreamProxyDetour", resourceCulture);
}
}
/// <summary>
/// 查找类似 Short Id 的本地化字符串。
/// </summary>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>تنظیم کردن به عنوان قانون فعال</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>تطبیق دامنه</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>استراتژی دامنه</value>
</data>
@@ -1443,9 +1440,6 @@
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
@@ -1470,4 +1464,37 @@
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>Prevent domain-based routing rules from failing</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Please fill in the correct config template</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>Full Config Template Setting</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>Enable Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>v2ray Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>Do Not Add Non-Proxy Protocol Outbound</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>Set Upstream Proxy Tag</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>sing-box Full Config Template</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound and Endpoint Config Only, Click to view the document</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
</data>
</root>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Beállítás aktív szabályként (Enter)</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Tartomány illesztő</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>Tartomány stratégia</value>
</data>
@@ -1443,9 +1440,6 @@
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
@@ -1470,4 +1464,37 @@
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>Prevent domain-based routing rules from failing</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Please fill in the correct config template</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>Full Config Template Setting</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>Enable Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>v2ray Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>Do Not Add Non-Proxy Protocol Outbound</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>Set Upstream Proxy Tag</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>sing-box Full Config Template</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound and Endpoint Config Only, Click to view the document</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
</data>
</root>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule (Enter)</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Domain Matcher</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>Domain strategy</value>
</data>
@@ -1443,9 +1440,6 @@
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
@@ -1470,4 +1464,37 @@
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>Prevent domain-based routing rules from failing</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Please fill in the correct config template</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>Full Config Template Setting</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>Enable Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>v2ray Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>Do Not Add Non-Proxy Protocol Outbound</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>Set Upstream Proxy Tag</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>sing-box Full Config Template</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound and Endpoint Config Only, Click to view the document</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
</data>
</root>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>Сопоставитель доменов</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>Доменная стратегия</value>
</data>
@@ -1099,13 +1096,13 @@
<value>Отмена тестирования...</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*gRPC Authority</value>
<value>* gRPC Authority (HTTP/2 псевдозаголовок :authority)</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Добавить сервер [HTTP]</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>which conflicts with the group previous proxy</value>
<value>что конфликтует с предыдущим прокси группы</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Включить фрагментацию (Fragment)</value>
@@ -1318,13 +1315,13 @@
<value>Пароль sudo системы</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password will be validated via the command line. If a validation error causes the application to malfunction, please restart the application. The password will not be stored and must be entered again after each restart.</value>
<value>Пароль sudo будет проверен в терминале. Если из-за ошибки проверки приложение начнёт работать некорректно, перезапустите его. Пароль не сохраняется — его нужно вводить после каждого перезапуска.</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*XHTTP-режим</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>Дополнительный XHTTP сырой JSON, формат: { XHTTPObject }</value>
<value>Дополнительный сырой JSON для XHTTP, формат: { XHTTP Object }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Скрыть в трее при закрытии окна</value>
@@ -1393,10 +1390,10 @@
<value>URL для тестирования текущего соединения</value>
</data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
<value>Можно указать название (Remarks) из конфигурации, убедитесь, что оно существует и уникально</value>
</data>
<data name="SudoIncorrectPasswordTip" xml:space="preserve">
<value>Incorrect password, please try again.</value>
<value>Неверный пароль, попробуйте ещё раз.</value>
</data>
<data name="TbMldsa65Verify" xml:space="preserve">
<value>Mldsa65Verify</value>
@@ -1405,69 +1402,99 @@
<value>Добавить сервер [Anytls]</value>
</data>
<data name="TbRemoteDNS" xml:space="preserve">
<value>Remote DNS</value>
<value>Удалённый DNS</value>
</data>
<data name="TbDomesticDNS" xml:space="preserve">
<value>Domestic DNS</value>
<value>Внутренний DNS</value>
</data>
<data name="TbSBOutboundsResolverDNS" xml:space="preserve">
<value>Outbound DNS Resolution (sing-box)</value>
<value>Резолвер DNS для исходящих (sing-box)</value>
</data>
<data name="TbSBOutboundDomainResolve" xml:space="preserve">
<value>Resolve Outbound Domains</value>
<value>Разрешать домены для исходящих соединений</value>
</data>
<data name="TbSBDoHResolverServer" xml:space="preserve">
<value>sing-box DoH Resolver Server</value>
<value>Сервер DoH-резолвера (sing-box)</value>
</data>
<data name="TbSBFallbackDNSResolve" xml:space="preserve">
<value>Fallback DNS Resolution, Suggest IP</value>
<value>Резервное DNS-разрешение (рекомендуется указывать IP)</value>
</data>
<data name="TbXrayFreedomResolveStrategy" xml:space="preserve">
<value>xray Freedom Resolution Strategy</value>
<value>Стратегия резолвинга Freedom (Xray)</value>
</data>
<data name="TbSBDirectResolveStrategy" xml:space="preserve">
<value>sing-box Direct Resolution Strategy</value>
<value>Стратегия прямого резолвинга (sing-box)</value>
</data>
<data name="TbSBRemoteResolveStrategy" xml:space="preserve">
<value>sing-box Remote Resolution Strategy</value>
<value>Стратегия удалённого резолвинга (sing-box)</value>
</data>
<data name="TbAddCommonDNSHosts" xml:space="preserve">
<value>Add Common DNS Hosts</value>
<value>Добавить стандартные записи hosts (DNS)</value>
</data>
<data name="TbSBDoHOverride" xml:space="preserve">
<value>The sing-box DoH resolution server can be overwritten</value>
<value>Сервер DoH-резолвера sing-box можно переопределить</value>
</data>
<data name="TbFakeIP" xml:space="preserve">
<value>FakeIP</value>
</data>
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
<value>Блокировать DNS-запросы SVCB и HTTPS</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
<value>DNS hosts: (каждая строка в формате "domain1 ip1 ip2")</value>
</data>
<data name="TbApplyProxyDomainsOnly" xml:space="preserve">
<value>Apply to Proxy Domains Only</value>
<value>Применять только к доменам через прокси</value>
</data>
<data name="ThBasicDNSSettings" xml:space="preserve">
<value>Basic DNS Settings</value>
<value>Базовые настройки DNS</value>
</data>
<data name="ThAdvancedDNSSettings" xml:space="preserve">
<value>Advanced DNS Settings</value>
<value>Расширенные настройки DNS</value>
</data>
<data name="TbValidateDirectExpectedIPs" xml:space="preserve">
<value>Validate Regional Domain IPs</value>
<value>Проверять IP-адреса региональных доменов</value>
</data>
<data name="TbValidateDirectExpectedIPsDesc" xml:space="preserve">
<value>When configured, validates IPs returned for regional domains (e.g., geosite:cn), returning only expected IPs</value>
<value>При включении проверяет IP-адреса, возвращаемые для региональных доменов (например, geosite:cn), и оставляет только ожидаемые IP-адреса</value>
</data>
<data name="TbCustomDNSEnable" xml:space="preserve">
<value>Enable Custom DNS</value>
<value>Включить пользовательский DNS</value>
</data>
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
<value>Включён пользовательский DNS — настройки на этой странице не применяются</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>Предотвращает сбои доменных правил маршрутизации</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Пожалуйста, заполните корректный шаблон конфигурации</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>Настройка полного шаблона конфигурации</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>Включить полный шаблон конфигурации</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>Полный шаблон конфигурации v2ray</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>Добавляет только конфигурацию исходящих (outbound), а также routing.balancers и routing.rules.outboundTag. Нажмите, чтобы открыть документ</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>Не добавлять исходящие для непрокси-протоколов</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>Задать тег верхнего прокси (upstream)</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>Полный шаблон конфигурации sing-box</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>Добавляет только конфигурацию Outbound и Endpoint. Нажмите, чтобы открыть документ</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>Эта функция предназначена для продвинутых пользователей и особых случаев. После включения игнорируются базовые настройки ядра, DNS и маршрутизации. Вы должны самостоятельно корректно задать порт системного прокси, учёт трафика и другие связанные параметры — всё настраивается вручную.</value>
</data>
</root>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配算法</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value>
</data>
@@ -1440,9 +1437,6 @@
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>阻止 SVCB 和 HTTPS 查询</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>避免 DNS 泄漏</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts“域名1 ip1 ip2” 一行一个)</value>
</data>
@@ -1467,4 +1461,37 @@
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>自定义 DNS 已启用,此页面配置将无效</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>避免域名分流规则失效</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>请填写正确的配置模板</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>完整配置模板设置</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>启用完整配置模板</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>v2ray 完整配置模板</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>仅添加出站配置routing.balancers 和 routing.rules.outboundTag点击查看文档</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>不添加非代理协议出站</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>设置上游代理 tag</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>sing-box 完整配置模板</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>仅添加出站和端点配置,点击查看文档</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>此功能供高级用户和有特殊需求的用户使用。 启用此功能后,将忽略 Core 的基础设置DNS 设置 ,路由设置。你需要保证系统代理的端口和流量统计等功能的配置正确,一切都由你来设置。</value>
</data>
</root>

View File

@@ -825,9 +825,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配演算法</value>
</data>
<data name="TbdomainStrategy" xml:space="preserve">
<value>域名解析策略</value>
</data>
@@ -1440,9 +1437,6 @@
<data name="TbBlockSVCBHTTPSQueries" xml:space="preserve">
<value>Block SVCB and HTTPS Queries</value>
</data>
<data name="TbPreventDNSLeaks" xml:space="preserve">
<value>Prevent DNS Leaks</value>
</data>
<data name="TbDNSHostsConfig" xml:space="preserve">
<value>DNS Hosts: ("domain1 ip1 ip2" per line)</value>
</data>
@@ -1467,4 +1461,37 @@
<data name="TbCustomDNSEnabledPageInvalid" xml:space="preserve">
<value>Custom DNS Enabled, This Page's Settings Invalid</value>
</data>
<data name="TbBlockSVCBHTTPSQueriesTips" xml:space="preserve">
<value>Prevent domain-based routing rules from failing</value>
</data>
<data name="FillCorrectConfigTemplateText" xml:space="preserve">
<value>Please fill in the correct config template</value>
</data>
<data name="menuFullConfigTemplate" xml:space="preserve">
<value>Full Config Template Setting</value>
</data>
<data name="TbFullConfigTemplateEnable" xml:space="preserve">
<value>Enable Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplate" xml:space="preserve">
<value>v2ray Full Config Template</value>
</data>
<data name="TbRayFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound Config Only, routing.balancers and routing.rules.outboundTag, Click to view the document</value>
</data>
<data name="TbAddProxyProtocolOutboundOnly" xml:space="preserve">
<value>Do Not Add Non-Proxy Protocol Outbound</value>
</data>
<data name="TbSetUpstreamProxyDetour" xml:space="preserve">
<value>Set Upstream Proxy Tag</value>
</data>
<data name="TbSBFullConfigTemplate" xml:space="preserve">
<value>sing-box Full Config Template</value>
</data>
<data name="TbSBFullConfigTemplateDesc" xml:space="preserve">
<value>Add Outbound and Endpoint Config Only, Click to view the document</value>
</data>
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
</data>
</root>

View File

@@ -1,6 +1,7 @@
using System.Data;
using System.Net;
using System.Net.NetworkInformation;
using System.Text.Json.Nodes;
namespace ServiceLib.Services.CoreConfig;
@@ -78,7 +79,8 @@ public class CoreConfigSingboxService
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
ret.Data = JsonUtils.Serialize(singboxConfig);
ret.Data = await ApplyFullConfigTemplate(singboxConfig);
return ret;
}
catch (Exception ex)
@@ -430,7 +432,8 @@ public class CoreConfigSingboxService
await ConvertGeo2Ruleset(singboxConfig);
ret.Success = true;
ret.Data = JsonUtils.Serialize(singboxConfig);
ret.Data = await ApplyFullConfigTemplate(singboxConfig);
return ret;
}
catch (Exception ex)
@@ -623,6 +626,7 @@ public class CoreConfigSingboxService
var tunInbound = JsonUtils.Deserialize<Inbound4Sbox>(EmbedUtils.GetEmbedText(Global.TunSingboxInboundFileName)) ?? new Inbound4Sbox { };
tunInbound.interface_name = Utils.IsOSX() ? $"utun{new Random().Next(99)}" : "singbox_tun";
tunInbound.mtu = _config.TunModeItem.Mtu;
tunInbound.auto_route = _config.TunModeItem.AutoRoute;
tunInbound.strict_route = _config.TunModeItem.StrictRoute;
tunInbound.stack = _config.TunModeItem.Stack;
if (_config.TunModeItem.EnableIPv6Address == false)
@@ -1325,7 +1329,7 @@ public class CoreConfigSingboxService
action = "resolve",
strategy = domainStrategy
};
if (_config.RoutingBasicItem.DomainStrategy == "IPOnDemand")
if (_config.RoutingBasicItem.DomainStrategy == Global.IPOnDemand)
{
singboxConfig.route.rules.Add(resolveRule);
}
@@ -1347,7 +1351,7 @@ public class CoreConfigSingboxService
}
}
}
if (_config.RoutingBasicItem.DomainStrategy == "IPIfNonMatch")
if (_config.RoutingBasicItem.DomainStrategy == Global.IPIfNonMatch)
{
singboxConfig.route.rules.Add(resolveRule);
foreach (var item2 in ipRules)
@@ -1654,6 +1658,7 @@ public class CoreConfigSingboxService
{
tag = Global.SingboxHostsDNSTag,
type = "hosts",
predefined = new(),
};
if (simpleDNSItem.AddCommonHosts == true)
{
@@ -1685,6 +1690,22 @@ public class CoreConfigSingboxService
}
}
if (simpleDNSItem.UseSystemHosts == true)
{
var systemHosts = Utils.GetSystemHosts();
if (systemHosts.Count > 0)
{
foreach (var host in systemHosts)
{
if (userHostsMap[host.Key] != null)
{
continue;
}
userHostsMap[host.Key] = new List<string> { host.Value };
}
}
}
foreach (var host in hostsDns.predefined)
{
if (finalDns.server == host.Key)
@@ -1842,7 +1863,12 @@ public class CoreConfigSingboxService
}
}
}
else if (item.OutboundTag == Global.ProxyTag)
else if (item.OutboundTag == Global.BlockTag)
{
rule.action = "predefined";
rule.rcode = "NXDOMAIN";
}
else
{
if (simpleDNSItem.FakeIP == true)
{
@@ -1853,12 +1879,6 @@ public class CoreConfigSingboxService
rule.server = Global.SingboxRemoteDNSTag;
rule.strategy = string.IsNullOrEmpty(simpleDNSItem.SingboxStrategy4Proxy) ? null : simpleDNSItem.SingboxStrategy4Proxy;
}
else if (item.OutboundTag == Global.BlockTag)
{
rule.action = "predefined";
rule.rcode = "NOERROR";
rule.answer = new List<string> { "A" };
}
singboxConfig.dns.rules.Add(rule);
}
@@ -2197,5 +2217,62 @@ public class CoreConfigSingboxService
return 0;
}
private async Task<string> ApplyFullConfigTemplate(SingboxConfig singboxConfig)
{
var fullConfigTemplate = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.sing_box);
if (fullConfigTemplate == null || !fullConfigTemplate.Enabled)
{
return JsonUtils.Serialize(singboxConfig);
}
var fullConfigTemplateItem = _config.TunModeItem.EnableTun ? fullConfigTemplate.TunConfig : fullConfigTemplate.Config;
if (fullConfigTemplateItem.IsNullOrEmpty())
{
return JsonUtils.Serialize(singboxConfig);
}
var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplateItem);
if (fullConfigTemplateNode == null)
{
return JsonUtils.Serialize(singboxConfig);
}
// Process outbounds
var customOutboundsNode = fullConfigTemplateNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray();
foreach (var outbound in singboxConfig.outbounds)
{
if (outbound.type.ToLower() is "direct" or "block")
{
if (fullConfigTemplate.AddProxyOnly == true)
{
continue;
}
}
else if (outbound.detour.IsNullOrEmpty() && (!fullConfigTemplate.ProxyDetour.IsNullOrEmpty()) && !Utils.IsPrivateNetwork(outbound.server ?? string.Empty))
{
outbound.detour = fullConfigTemplate.ProxyDetour;
}
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
}
fullConfigTemplateNode["outbounds"] = customOutboundsNode;
// Process endpoints
if (singboxConfig.endpoints != null && singboxConfig.endpoints.Count > 0)
{
var customEndpointsNode = fullConfigTemplateNode["endpoints"] is JsonArray endpoints ? endpoints : new JsonArray();
foreach (var endpoint in singboxConfig.endpoints)
{
if (endpoint.detour.IsNullOrEmpty() && (!fullConfigTemplate.ProxyDetour.IsNullOrEmpty()))
{
endpoint.detour = fullConfigTemplate.ProxyDetour;
}
customEndpointsNode.Add(JsonUtils.DeepCopy(endpoint));
}
fullConfigTemplateNode["endpoints"] = customEndpointsNode;
}
return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode));
}
#endregion private gen function
}

View File

@@ -68,7 +68,7 @@ public class CoreConfigV2rayService
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
ret.Success = true;
ret.Data = JsonUtils.Serialize(v2rayConfig);
ret.Data = await ApplyFullConfigTemplate(v2rayConfig);
return ret;
}
catch (Exception ex)
@@ -177,7 +177,7 @@ public class CoreConfigV2rayService
rule.balancerTag = balancer.tag;
}
}
if (v2rayConfig.routing.domainStrategy == "IPIfNonMatch")
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
{
v2rayConfig.routing.rules.Add(new()
{
@@ -197,7 +197,8 @@ public class CoreConfigV2rayService
}
ret.Success = true;
ret.Data = JsonUtils.Serialize(v2rayConfig);
ret.Data = await ApplyFullConfigTemplate(v2rayConfig, true);
return ret;
}
catch (Exception ex)
@@ -522,7 +523,6 @@ public class CoreConfigV2rayService
if (v2rayConfig.routing?.rules != null)
{
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
v2rayConfig.routing.domainMatcher = _config.RoutingBasicItem.DomainMatcher.IsNullOrEmpty() ? null : _config.RoutingBasicItem.DomainMatcher;
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
@@ -1142,7 +1142,21 @@ public class CoreConfigV2rayService
var item = await AppHandler.Instance.GetDNSItem(ECoreType.Xray);
if (item != null && item.Enabled == true)
{
return await GenDnsCompatible(node, v2rayConfig);
var result = await GenDnsCompatible(node, v2rayConfig);
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
{
// DNS routing
v2rayConfig.dns.tag = Global.DnsTag;
v2rayConfig.routing.rules.Add(new RulesItem4Ray
{
type = "field",
inboundTag = new List<string> { Global.DnsTag },
outboundTag = Global.ProxyTag,
});
}
return result;
}
var simpleDNSItem = _config.SimpleDNSItem;
var domainStrategy4Freedom = simpleDNSItem?.RayStrategy4Freedom;
@@ -1163,6 +1177,18 @@ public class CoreConfigV2rayService
await GenDnsServers(node, v2rayConfig, simpleDNSItem);
await GenDnsHosts(v2rayConfig, simpleDNSItem);
if (v2rayConfig.routing.domainStrategy == Global.IPIfNonMatch)
{
// DNS routing
v2rayConfig.dns.tag = Global.DnsTag;
v2rayConfig.routing.rules.Add(new RulesItem4Ray
{
type = "field",
inboundTag = new List<string> { Global.DnsTag },
outboundTag = Global.ProxyTag,
});
}
}
catch (Exception ex)
{
@@ -1262,7 +1288,7 @@ public class CoreConfigV2rayService
directDomainList.Add(normalizedDomain);
}
}
else if (item.OutboundTag == Global.ProxyTag)
else if (item.OutboundTag != Global.BlockTag)
{
if (normalizedDomain.StartsWith("geosite:"))
{
@@ -1339,10 +1365,13 @@ public class CoreConfigV2rayService
return await Task.FromResult(0);
}
v2rayConfig.dns ??= new Dns4Ray();
v2rayConfig.dns.hosts ??= new Dictionary<string, List<string>>();
v2rayConfig.dns.hosts ??= new Dictionary<string, object>();
if (simpleDNSItem.AddCommonHosts == true)
{
v2rayConfig.dns.hosts = Global.PredefinedHosts;
v2rayConfig.dns.hosts = Global.PredefinedHosts.ToDictionary(
kvp => kvp.Key,
kvp => (object)kvp.Value
);
}
if (simpleDNSItem.UseSystemHosts == true)
@@ -1462,7 +1491,7 @@ public class CoreConfigV2rayService
await GenDnsDomainsCompatible(node, obj, item);
v2rayConfig.dns = JsonUtils.Deserialize<Dns4Ray>(obj.ToJsonString());
v2rayConfig.dns = JsonUtils.Deserialize<Dns4Ray>(JsonUtils.Serialize(obj));
}
catch (Exception ex)
{
@@ -1839,5 +1868,85 @@ public class CoreConfigV2rayService
return await Task.FromResult(0);
}
private async Task<string> ApplyFullConfigTemplate(V2rayConfig v2rayConfig, bool handleBalancerAndRules = false)
{
var fullConfigTemplate = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.Xray);
if (fullConfigTemplate == null || !fullConfigTemplate.Enabled || fullConfigTemplate.Config.IsNullOrEmpty())
{
return JsonUtils.Serialize(v2rayConfig);
}
var fullConfigTemplateNode = JsonNode.Parse(fullConfigTemplate.Config);
if (fullConfigTemplateNode == null)
{
return JsonUtils.Serialize(v2rayConfig);
}
// Handle balancer and rules modifications (for multiple load scenarios)
if (handleBalancerAndRules && v2rayConfig.routing?.balancers?.Count > 0)
{
var balancer = v2rayConfig.routing.balancers.First();
// Modify existing rules in custom config
var rulesNode = fullConfigTemplateNode["routing"]?["rules"];
if (rulesNode != null)
{
foreach (var rule in rulesNode.AsArray())
{
if (rule["outboundTag"]?.GetValue<string>() == Global.ProxyTag)
{
rule.AsObject().Remove("outboundTag");
rule["balancerTag"] = balancer.tag;
}
}
}
// Ensure routing node exists
if (fullConfigTemplateNode["routing"] == null)
{
fullConfigTemplateNode["routing"] = new JsonObject();
}
// Handle balancers - append instead of override
if (fullConfigTemplateNode["routing"]["balancers"] is JsonArray customBalancersNode)
{
if (JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers)) is JsonArray newBalancers)
{
foreach (var balancerNode in newBalancers)
{
customBalancersNode.Add(balancerNode?.DeepClone());
}
}
}
else
{
fullConfigTemplateNode["routing"]["balancers"] = JsonNode.Parse(JsonUtils.Serialize(v2rayConfig.routing.balancers));
}
}
// Handle outbounds - append instead of override
var customOutboundsNode = fullConfigTemplateNode["outbounds"] is JsonArray outbounds ? outbounds : new JsonArray();
foreach (var outbound in v2rayConfig.outbounds)
{
if (outbound.protocol.ToLower() is "blackhole" or "dns" or "freedom")
{
if (fullConfigTemplate.AddProxyOnly == true)
{
continue;
}
}
else if ((outbound.streamSettings?.sockopt?.dialerProxy.IsNullOrEmpty() == true) && (!fullConfigTemplate.ProxyDetour.IsNullOrEmpty()) && !(Utils.IsPrivateNetwork(outbound.settings?.servers?.FirstOrDefault()?.address ?? string.Empty) || Utils.IsPrivateNetwork(outbound.settings?.vnext?.FirstOrDefault()?.address ?? string.Empty)))
{
outbound.streamSettings ??= new StreamSettings4Ray();
outbound.streamSettings.sockopt ??= new Sockopt4Ray();
outbound.streamSettings.sockopt.dialerProxy = fullConfigTemplate.ProxyDetour;
}
customOutboundsNode.Add(JsonUtils.DeepCopy(outbound));
}
fullConfigTemplateNode["outbounds"] = customOutboundsNode;
return await Task.FromResult(JsonUtils.Serialize(fullConfigTemplateNode));
}
#endregion private gen function
}

View File

@@ -6,7 +6,7 @@ namespace ServiceLib.Services;
public class UpdateService
{
private Action<bool, string>? _updateFunc;
private int _timeout = 30;
private readonly int _timeout = 30;
private static readonly string _tag = "UpdateService";
public async Task CheckUpdateGuiN(Config config, Action<bool, string> updateFunc, bool preRelease)
@@ -104,137 +104,6 @@ public class UpdateService
}
}
public async Task UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action<bool, string> updateFunc)
{
_updateFunc = updateFunc;
_updateFunc?.Invoke(false, ResUI.MsgUpdateSubscriptionStart);
var subItem = await AppHandler.Instance.SubItems();
if (subItem is not { Count: > 0 })
{
_updateFunc?.Invoke(false, ResUI.MsgNoValidSubscription);
return;
}
foreach (var item in subItem)
{
var id = item.Id.TrimEx();
var url = item.Url.TrimEx();
var userAgent = item.UserAgent.TrimEx();
var hashCode = $"{item.Remarks}->";
if (id.IsNullOrEmpty() || url.IsNullOrEmpty() || (subId.IsNotEmpty() && item.Id != subId))
{
//_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue;
}
if (!url.StartsWith(Global.HttpsProtocol) && !url.StartsWith(Global.HttpProtocol))
{
continue;
}
if (item.Enabled == false)
{
_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgSkipSubscriptionUpdate}");
continue;
}
var downloadHandle = new DownloadService();
downloadHandle.Error += (sender2, args) =>
{
_updateFunc?.Invoke(false, $"{hashCode}{args.GetException().Message}");
};
_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgStartGettingSubscriptions}");
//one url
url = Utils.GetPunycode(url);
//convert
if (item.ConvertTarget.IsNotEmpty())
{
var subConvertUrl = config.ConstItem.SubConvertUrl.IsNullOrEmpty() ? Global.SubConvertUrls.FirstOrDefault() : config.ConstItem.SubConvertUrl;
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
if (!url.Contains("target="))
{
url += string.Format("&target={0}", item.ConvertTarget);
}
if (!url.Contains("config="))
{
url += string.Format("&config={0}", Global.SubConvertConfig.FirstOrDefault());
}
}
var result = await downloadHandle.TryDownloadString(url, blProxy, userAgent);
if (blProxy && result.IsNullOrEmpty())
{
result = await downloadHandle.TryDownloadString(url, false, userAgent);
}
//more url
if (item.ConvertTarget.IsNullOrEmpty() && item.MoreUrl.TrimEx().IsNotEmpty())
{
if (result.IsNotEmpty() && Utils.IsBase64String(result))
{
result = Utils.Base64Decode(result);
}
var lstUrl = item.MoreUrl.TrimEx().Split(",") ?? [];
foreach (var it in lstUrl)
{
var url2 = Utils.GetPunycode(it);
if (url2.IsNullOrEmpty())
{
continue;
}
var result2 = await downloadHandle.TryDownloadString(url2, blProxy, userAgent);
if (blProxy && result2.IsNullOrEmpty())
{
result2 = await downloadHandle.TryDownloadString(url2, false, userAgent);
}
if (result2.IsNotEmpty())
{
if (Utils.IsBase64String(result2))
{
result += Environment.NewLine + Utils.Base64Decode(result2);
}
else
{
result += Environment.NewLine + result2;
}
}
}
}
if (result.IsNullOrEmpty())
{
_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgSubscriptionDecodingFailed}");
}
else
{
_updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgGetSubscriptionSuccessfully}");
if (result?.Length < 99)
{
_updateFunc?.Invoke(false, $"{hashCode}{result}");
}
var ret = await ConfigHandler.AddBatchServers(config, result, id, true);
if (ret <= 0)
{
Logging.SaveLog("FailedImportSubscription");
Logging.SaveLog(result);
}
_updateFunc?.Invoke(false,
ret > 0
? $"{hashCode}{ResUI.MsgUpdateSubscriptionEnd}"
: $"{hashCode}{ResUI.MsgFailedImportSubscription}");
}
_updateFunc?.Invoke(false, "-------------------------------------------------------");
//await ConfigHandler.DedupServerList(config, id);
}
_updateFunc?.Invoke(true, $"{ResUI.MsgUpdateSubscriptionEnd}");
}
public async Task UpdateGeoFileAll(Config config, Action<bool, string> updateFunc)
{
await UpdateGeoFiles(config, updateFunc);

View File

@@ -75,10 +75,7 @@ public class CheckUpdateViewModel : MyReactiveObject
private async Task CheckUpdate()
{
await Task.Run(async () =>
{
await CheckUpdateTask();
});
await Task.Run(CheckUpdateTask);
}
private async Task CheckUpdateTask()

View File

@@ -150,7 +150,7 @@ public class DNSSettingViewModel : MyReactiveObject
await ConfigHandler.SaveDNSItems(_config, item1);
var item2 = await AppHandler.Instance.GetDNSItem(ECoreType.sing_box);
item2.Enabled = RayCustomDNSEnableCompatible;
item2.Enabled = SBCustomDNSEnableCompatible;
item2.DomainStrategy4Freedom = DomainStrategy4Freedom2Compatible;
item2.DomainDNSAddress = DomainDNSAddress2Compatible;
item2.NormalDNS = JsonUtils.Serialize(JsonUtils.ParseJson(NormalDNS2Compatible));

View File

@@ -0,0 +1,113 @@
using System.Reactive;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
namespace ServiceLib.ViewModels;
public class FullConfigTemplateViewModel : MyReactiveObject
{
#region Reactive
[Reactive]
public bool EnableFullConfigTemplate4Ray { get; set; }
[Reactive]
public bool EnableFullConfigTemplate4Singbox { get; set; }
[Reactive]
public string FullConfigTemplate4Ray { get; set; }
[Reactive]
public string FullConfigTemplate4Singbox { get; set; }
[Reactive]
public string FullTunConfigTemplate4Singbox { get; set; }
[Reactive]
public bool AddProxyOnly4Ray { get; set; }
[Reactive]
public bool AddProxyOnly4Singbox { get; set; }
[Reactive]
public string ProxyDetour4Ray { get; set; }
[Reactive]
public string ProxyDetour4Singbox { get; set; }
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
#endregion Reactive
public FullConfigTemplateViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
{
_config = AppHandler.Instance.Config;
_updateView = updateView;
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
{
await SaveSettingAsync();
});
_ = Init();
}
private async Task Init()
{
var item = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.Xray);
EnableFullConfigTemplate4Ray = item?.Enabled ?? false;
FullConfigTemplate4Ray = item?.Config ?? string.Empty;
AddProxyOnly4Ray = item?.AddProxyOnly ?? false;
ProxyDetour4Ray = item?.ProxyDetour ?? string.Empty;
var item2 = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.sing_box);
EnableFullConfigTemplate4Singbox = item2?.Enabled ?? false;
FullConfigTemplate4Singbox = item2?.Config ?? string.Empty;
FullTunConfigTemplate4Singbox = item2?.TunConfig ?? string.Empty;
AddProxyOnly4Singbox = item2?.AddProxyOnly ?? false;
ProxyDetour4Singbox = item2?.ProxyDetour ?? string.Empty;
}
private async Task SaveSettingAsync()
{
if (!await SaveXrayConfigAsync())
return;
if (!await SaveSingboxConfigAsync())
return;
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
_ = _updateView?.Invoke(EViewAction.CloseWindow, null);
}
private async Task<bool> SaveXrayConfigAsync()
{
var item = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.Xray);
item.Enabled = EnableFullConfigTemplate4Ray;
item.Config = null;
item.Config = FullConfigTemplate4Ray;
item.AddProxyOnly = AddProxyOnly4Ray;
item.ProxyDetour = ProxyDetour4Ray;
await ConfigHandler.SaveFullConfigTemplate(_config, item);
return true;
}
private async Task<bool> SaveSingboxConfigAsync()
{
var item = await AppHandler.Instance.GetFullConfigTemplateItem(ECoreType.sing_box);
item.Enabled = EnableFullConfigTemplate4Singbox;
item.Config = null;
item.TunConfig = null;
item.Config = FullConfigTemplate4Singbox;
item.TunConfig = FullTunConfigTemplate4Singbox;
item.AddProxyOnly = AddProxyOnly4Singbox;
item.ProxyDetour = ProxyDetour4Singbox;
await ConfigHandler.SaveFullConfigTemplate(_config, item);
return true;
}
}

View File

@@ -39,6 +39,7 @@ public class MainWindowViewModel : MyReactiveObject
public ReactiveCommand<Unit, Unit> RoutingSettingCmd { get; }
public ReactiveCommand<Unit, Unit> DNSSettingCmd { get; }
public ReactiveCommand<Unit, Unit> FullConfigTemplateCmd { get; }
public ReactiveCommand<Unit, Unit> GlobalHotkeySettingCmd { get; }
public ReactiveCommand<Unit, Unit> RebootAsAdminCmd { get; }
public ReactiveCommand<Unit, Unit> ClearServerStatisticsCmd { get; }
@@ -169,6 +170,10 @@ public class MainWindowViewModel : MyReactiveObject
{
await DNSSettingAsync();
});
FullConfigTemplateCmd = ReactiveCommand.CreateFromTask(async () =>
{
await FullConfigTemplateAsync();
});
GlobalHotkeySettingCmd = ReactiveCommand.CreateFromTask(async () =>
{
if (await _updateView?.Invoke(EViewAction.GlobalHotkeySettingWindow, null) == true)
@@ -220,6 +225,7 @@ public class MainWindowViewModel : MyReactiveObject
await ConfigHandler.InitBuiltinRouting(_config);
await ConfigHandler.InitBuiltinDNS(_config);
await ConfigHandler.InitBuiltinFullConfigTemplate(_config);
await ProfileExHandler.Instance.Init();
await CoreHandler.Instance.Init(_config, UpdateHandler);
TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler);
@@ -471,7 +477,7 @@ public class MainWindowViewModel : MyReactiveObject
public async Task UpdateSubscriptionProcess(string subId, bool blProxy)
{
await (new UpdateService()).UpdateSubscriptionProcess(_config, subId, blProxy, UpdateTaskHandler);
await SubscriptionHandler.UpdateProcess(_config, subId, blProxy, UpdateTaskHandler);
}
#endregion Subscription
@@ -508,6 +514,15 @@ public class MainWindowViewModel : MyReactiveObject
}
}
private async Task FullConfigTemplateAsync()
{
var ret = await _updateView?.Invoke(EViewAction.FullConfigTemplateWindow, null);
if (ret == true)
{
await Reload();
}
}
public async Task RebootAsAdmin()
{
ProcUtils.RebootAsAdmin();

View File

@@ -84,6 +84,7 @@ public class OptionSettingViewModel : MyReactiveObject
#region Tun mode
[Reactive] public bool TunAutoRoute { get; set; }
[Reactive] public bool TunStrictRoute { get; set; }
[Reactive] public string TunStack { get; set; }
[Reactive] public int TunMtu { get; set; }
@@ -201,6 +202,7 @@ public class OptionSettingViewModel : MyReactiveObject
#region Tun mode
TunAutoRoute = _config.TunModeItem.AutoRoute;
TunStrictRoute = _config.TunModeItem.StrictRoute;
TunStack = _config.TunModeItem.Stack;
TunMtu = _config.TunModeItem.Mtu;
@@ -354,6 +356,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.SystemProxyItem.SystemProxyAdvancedProtocol = systemProxyAdvancedProtocol;
//tun mode
_config.TunModeItem.AutoRoute = TunAutoRoute;
_config.TunModeItem.StrictRoute = TunStrictRoute;
_config.TunModeItem.Stack = TunStack;
_config.TunModeItem.Mtu = TunMtu;

View File

@@ -20,9 +20,6 @@ public class RoutingSettingViewModel : MyReactiveObject
[Reactive]
public string DomainStrategy { get; set; }
[Reactive]
public string DomainMatcher { get; set; }
[Reactive]
public string DomainStrategy4Singbox { get; set; }
@@ -75,7 +72,6 @@ public class RoutingSettingViewModel : MyReactiveObject
SelectedSource = new();
DomainStrategy = _config.RoutingBasicItem.DomainStrategy;
DomainMatcher = _config.RoutingBasicItem.DomainMatcher;
DomainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config);
@@ -109,7 +105,6 @@ public class RoutingSettingViewModel : MyReactiveObject
private async Task SaveRoutingAsync()
{
_config.RoutingBasicItem.DomainStrategy = DomainStrategy;
_config.RoutingBasicItem.DomainMatcher = DomainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = DomainStrategy4Singbox;
if (await ConfigHandler.SaveConfig(_config) == 0)

View File

@@ -334,10 +334,7 @@ public class StatusBarViewModel : MyReactiveObject
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
var msg = await Task.Run(async () =>
{
return await ConnectionHandler.Instance.RunAvailabilityCheck();
});
var msg = await Task.Run(ConnectionHandler.Instance.RunAvailabilityCheck);
NoticeHandler.Instance.SendMessageEx(msg);
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);

View File

@@ -97,7 +97,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
@@ -117,7 +118,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="5"
@@ -178,7 +180,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSBDoHOverride}" />
Text="{x:Static resx:ResUI.TbSBDoHOverride}"
TextWrapping="Wrap" />
</Grid>
</ScrollViewer>
</TabItem>
@@ -228,7 +231,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}" />
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="3"
@@ -247,7 +251,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueriesTips}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
@@ -267,7 +272,8 @@
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="5"

View File

@@ -0,0 +1,198 @@
<Window
x:Class="v2rayN.Desktop.Views.FullConfigTemplateWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuFullConfigTemplate}"
Width="900"
Height="600"
x:DataType="vms:FullConfigTemplateViewModel"
ShowInTaskbar="False"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel
Margin="{StaticResource Margin4}"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
x:Name="btnSave"
Width="100"
Content="{x:Static resx:ResUI.TbConfirm}"
Cursor="Hand"
IsDefault="True" />
<Button
x:Name="btnCancel"
Width="100"
Margin="{StaticResource MarginLr8}"
Content="{x:Static resx:ResUI.TbCancel}"
Cursor="Hand"
IsCancel="True" />
</StackPanel>
<TabControl HorizontalContentAlignment="Stretch">
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRayFullConfigTemplate}">
<DockPanel Margin="{StaticResource Margin4}">
<Grid DockPanel.Dock="Top" RowDefinitions="Auto,Auto,Auto">
<TextBlock
Grid.Row="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFullConfigTemplateDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="1"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkFullConfigTemplateDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRayFullConfigTemplateDesc}" />
</HyperlinkButton>
</TextBlock>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFullConfigTemplateEnable}" />
<ToggleSwitch
x:Name="rayFullConfigTemplateEnable"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
<ToggleSwitch
x:Name="togAddProxyProtocolOutboundOnly4Ray"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
<TextBox
x:Name="txtProxyDetour4Ray"
Width="200"
Margin="{StaticResource Margin4}" />
</StackPanel>
</WrapPanel>
<HeaderedContentControl
Margin="{StaticResource Margin4}"
BorderBrush="Gray"
BorderThickness="1"
Header="xray config template json">
<TextBox
x:Name="rayFullConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl>
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbSBFullConfigTemplate}">
<DockPanel Margin="{StaticResource Margin4}">
<Grid DockPanel.Dock="Top" RowDefinitions="Auto,Auto,Auto">
<TextBlock
Grid.Row="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFullConfigTemplateDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="1"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkFullConfigTemplateDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbSBFullConfigTemplateDesc}" />
</HyperlinkButton>
</TextBlock>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbFullConfigTemplateEnable}" />
<ToggleSwitch
x:Name="sbFullConfigTemplateEnable"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
<ToggleSwitch
x:Name="togAddProxyProtocolOutboundOnly4Singbox"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
<TextBox
x:Name="txtProxyDetour4Singbox"
Width="200"
Margin="{StaticResource Margin4}" />
</StackPanel>
</WrapPanel>
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
<HeaderedContentControl
Grid.Column="0"
BorderBrush="Gray"
BorderThickness="1"
Header="sing-box config template json">
<TextBox
x:Name="sbFullConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<HeaderedContentControl
Grid.Column="2"
BorderBrush="Gray"
BorderThickness="1"
Header="sing-box tun config template json">
<TextBox
x:Name="sbFullTunConfigTemplate"
VerticalAlignment="Stretch"
Classes="TextArea"
MinLines="10"
TextWrapping="Wrap" />
</HeaderedContentControl>
</Grid>
</DockPanel>
</TabItem>
</TabControl>
</DockPanel>
</Window>

View File

@@ -0,0 +1,51 @@
using System.Reactive.Disposables;
using Avalonia.Interactivity;
using ReactiveUI;
using v2rayN.Desktop.Base;
namespace v2rayN.Desktop.Views;
public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateViewModel>
{
private static Config _config;
public FullConfigTemplateWindow()
{
InitializeComponent();
_config = AppHandler.Instance.Config;
btnCancel.Click += (s, e) => this.Close();
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, vm => vm.EnableFullConfigTemplate4Ray, v => v.rayFullConfigTemplateEnable.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullConfigTemplate4Ray, v => v.rayFullConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableFullConfigTemplate4Singbox, v => v.sbFullConfigTemplateEnable.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullConfigTemplate4Singbox, v => v.sbFullConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullTunConfigTemplate4Singbox, v => v.sbFullTunConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});
}
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
{
switch (action)
{
case EViewAction.CloseWindow:
this.Close(true);
break;
}
return await Task.FromResult(true);
}
private void linkFullConfigTemplateDoc_Click(object sender, RoutedEventArgs e)
{
ProcUtils.ProcessStart("https://github.com/2dust/v2rayN/wiki/Description-of-some-ui#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE");
}
}

View File

@@ -72,6 +72,7 @@
<MenuItem x:Name="menuOptionSetting" Header="{x:Static resx:ResUI.menuOptionSetting}" />
<MenuItem x:Name="menuRoutingSetting" Header="{x:Static resx:ResUI.menuRoutingSetting}" />
<MenuItem x:Name="menuDNSSetting" Header="{x:Static resx:ResUI.menuDNSSetting}" />
<MenuItem x:Name="menuFullConfigTemplate" Header="{x:Static resx:ResUI.menuFullConfigTemplate}" />
<MenuItem x:Name="menuGlobalHotkeySetting" Header="{x:Static resx:ResUI.menuGlobalHotkeySetting}" />
<Separator />
<MenuItem x:Name="menuRebootAsAdmin" Header="{x:Static resx:ResUI.menuRebootAsAdmin}" />

View File

@@ -100,6 +100,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.DNSSettingCmd, v => v.menuDNSSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FullConfigTemplateCmd, v => v.menuFullConfigTemplate).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RebootAsAdminCmd, v => v.menuRebootAsAdmin).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables);
@@ -190,6 +191,9 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
case EViewAction.DNSSettingWindow:
return await new DNSSettingWindow().ShowDialog<bool>(this);
case EViewAction.FullConfigTemplateWindow:
return await new FullConfigTemplateWindow().ShowDialog<bool>(this);
case EViewAction.RoutingSettingWindow:
return await new RoutingSettingWindow().ShowDialog<bool>(this);

View File

@@ -729,71 +729,84 @@
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,Auto"
DockPanel.Dock="Top"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="Auto Route" />
<ToggleSwitch
x:Name="togAutoRoute"
Grid.Row="2"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="Strict Route" />
<ToggleSwitch
x:Name="togStrictRoute"
Grid.Row="2"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="3"
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="Stack" />
<ComboBox
x:Name="cmbStack"
Grid.Row="3"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="4"
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="Mtu" />
<ComboBox
x:Name="cmbMtu"
Grid.Row="4"
Grid.Row="5"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="5"
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
<ToggleSwitch
x:Name="togEnableExInbound"
Grid.Row="5"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Row="7"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsEnableIPv6Address}" />
<ToggleSwitch
x:Name="togEnableIPv6Address"
Grid.Row="6"
Grid.Row="7"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" />

View File

@@ -105,6 +105,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunAutoRoute, v => v.togAutoRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);

View File

@@ -50,7 +50,7 @@
Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto"
DockPanel.Dock="Top"
RowDefinitions="Auto,Auto,Auto">
RowDefinitions="Auto,Auto">
<TextBlock
Grid.Row="0"
@@ -74,19 +74,6 @@
Grid.Row="1"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
<ComboBox
x:Name="cmbdomainMatcher"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
@@ -94,7 +81,7 @@
</TextBlock>
<ComboBox
x:Name="cmbdomainStrategy4Singbox"
Grid.Row="2"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}"

View File

@@ -27,7 +27,6 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
@@ -36,7 +35,6 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainMatcher, v => v.cmbdomainMatcher.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.SelectedValue).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);

View File

@@ -39,6 +39,9 @@
<EmbeddedResource Include="Assets\v2rayN.ico">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<Compile Update="Views\FullConfigTemplateWindow.axaml.cs">
<DependentUpon>FullConfigTemplateWindow.axaml</DependentUpon>
</Compile>
<None Update="v2rayN.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@@ -124,7 +124,8 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}" />
Text="{x:Static resx:ResUI.TbSBOutboundDomainResolve}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
@@ -147,7 +148,8 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}" />
Text="{x:Static resx:ResUI.TbSBFallbackDNSResolve}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="5"
@@ -281,7 +283,8 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}" />
Text="{x:Static resx:ResUI.TbApplyProxyDomainsOnly}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="3"
@@ -302,7 +305,8 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPreventDNSLeaks}" />
Text="{x:Static resx:ResUI.TbBlockSVCBHTTPSQueriesTips}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="4"
@@ -325,7 +329,8 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}" />
Text="{x:Static resx:ResUI.TbValidateDirectExpectedIPsDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="5"

View File

@@ -0,0 +1,227 @@
<base:WindowBase
x:Class="v2rayN.Views.FullConfigTemplateWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:v2rayN.Base"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuFullConfigTemplate}"
Width="1000"
Height="700"
x:TypeArguments="vms:FullConfigTemplateViewModel"
ShowInTaskbar="False"
Style="{StaticResource WindowGlobal}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel
Margin="{StaticResource Margin4}"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
x:Name="btnSave"
Width="100"
Content="{x:Static resx:ResUI.TbConfirm}"
Cursor="Hand"
IsDefault="True"
Style="{StaticResource DefButton}" />
<Button
x:Name="btnCancel"
Width="100"
Margin="{StaticResource MarginLeftRight8}"
Content="{x:Static resx:ResUI.TbCancel}"
Cursor="Hand"
IsCancel="true"
Style="{StaticResource DefButton}" />
</StackPanel>
<TabControl HorizontalContentAlignment="Left">
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRayFullConfigTemplate}">
<DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFullConfigTemplateDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="1"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkFullConfigTemplateDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRayFullConfigTemplateDesc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFullConfigTemplateEnable}" />
<ToggleButton
x:Name="rayFullConfigTemplateEnable"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
<ToggleButton
x:Name="togAddProxyProtocolOutboundOnly4Ray"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
<TextBox
x:Name="txtProxyDetour4Ray"
Width="200"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefTextBox}" />
</StackPanel>
</WrapPanel>
<TextBox
x:Name="rayFullConfigTemplate"
Margin="{StaticResource Margin8}"
VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="xray config template json"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</DockPanel>
</TabItem>
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbSBFullConfigTemplate}">
<DockPanel Margin="{StaticResource Margin8}">
<Grid DockPanel.Dock="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFullConfigTemplateDesc}"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="1"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkFullConfigTemplateDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbSBFullConfigTemplateDesc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbFullConfigTemplateEnable}" />
<ToggleButton
x:Name="sbFullConfigTemplateEnable"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</StackPanel>
</Grid>
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbAddProxyProtocolOutboundOnly}" />
<ToggleButton
x:Name="togAddProxyProtocolOutboundOnly4Singbox"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSetUpstreamProxyDetour}" />
<TextBox
x:Name="txtProxyDetour4Singbox"
Width="200"
Margin="{StaticResource Margin8}"
Style="{StaticResource DefTextBox}" />
</StackPanel>
</WrapPanel>
<Grid Margin="{StaticResource Margin8}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBox
x:Name="sbFullConfigTemplate"
Grid.Column="0"
VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="sing-box config template json"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<TextBox
x:Name="sbFullTunConfigTemplate"
Grid.Column="2"
VerticalAlignment="Stretch"
materialDesign:HintAssist.Hint="sing-box tun config template json"
AcceptsReturn="True"
BorderThickness="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</Grid>
</DockPanel>
</TabItem>
</TabControl>
</DockPanel>
</base:WindowBase>

View File

@@ -0,0 +1,52 @@
using System.Reactive.Disposables;
using System.Windows;
using ReactiveUI;
namespace v2rayN.Views;
public partial class FullConfigTemplateWindow
{
private static Config _config;
public FullConfigTemplateWindow()
{
InitializeComponent();
this.Owner = Application.Current.MainWindow;
_config = AppHandler.Instance.Config;
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, vm => vm.EnableFullConfigTemplate4Ray, v => v.rayFullConfigTemplateEnable.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullConfigTemplate4Ray, v => v.rayFullConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AddProxyOnly4Ray, v => v.togAddProxyProtocolOutboundOnly4Ray.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyDetour4Ray, v => v.txtProxyDetour4Ray.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableFullConfigTemplate4Singbox, v => v.sbFullConfigTemplateEnable.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullConfigTemplate4Singbox, v => v.sbFullConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FullTunConfigTemplate4Singbox, v => v.sbFullTunConfigTemplate.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AddProxyOnly4Singbox, v => v.togAddProxyProtocolOutboundOnly4Singbox.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyDetour4Singbox, v => v.txtProxyDetour4Singbox.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme);
}
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
{
switch (action)
{
case EViewAction.CloseWindow:
this.DialogResult = true;
break;
}
return await Task.FromResult(true);
}
private void linkFullConfigTemplateDoc_Click(object sender, RoutedEventArgs e)
{
ProcUtils.ProcessStart("https://github.com/2dust/v2rayN/wiki/Description-of-some-ui#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE");
}
}

View File

@@ -173,6 +173,10 @@
x:Name="menuDNSSetting"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuDNSSetting}" />
<MenuItem
x:Name="menuFullConfigTemplate"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuFullConfigTemplate}" />
<MenuItem
x:Name="menuGlobalHotkeySetting"
Height="{StaticResource MenuItemHeight}"

View File

@@ -97,6 +97,7 @@ public partial class MainWindow
this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.DNSSettingCmd, v => v.menuDNSSetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.FullConfigTemplateCmd, v => v.menuFullConfigTemplate).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RebootAsAdminCmd, v => v.menuRebootAsAdmin).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables);
@@ -186,6 +187,9 @@ public partial class MainWindow
case EViewAction.OptionSettingWindow:
return (new OptionSettingWindow().ShowDialog() ?? false);
case EViewAction.FullConfigTemplateWindow:
return (new FullConfigTemplateWindow().ShowDialog() ?? false);
case EViewAction.GlobalHotkeySettingWindow:
return (new GlobalHotkeySettingWindow().ShowDialog() ?? false);

View File

@@ -1023,6 +1023,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -1036,9 +1037,9 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="Strict Route" />
Text="Auto Route" />
<ToggleButton
x:Name="togStrictRoute"
x:Name="togAutoRoute"
Grid.Row="2"
Grid.Column="1"
Margin="{StaticResource Margin8}"
@@ -1050,10 +1051,24 @@
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="Strict Route" />
<ToggleButton
x:Name="togStrictRoute"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="Stack" />
<ComboBox
x:Name="cmbStack"
Grid.Row="3"
Grid.Row="4"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
@@ -1061,7 +1076,7 @@
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="4"
Grid.Row="5"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
@@ -1069,7 +1084,7 @@
Text="Mtu" />
<ComboBox
x:Name="cmbMtu"
Grid.Row="4"
Grid.Row="5"
Grid.Column="1"
Width="200"
Margin="{StaticResource Margin8}"
@@ -1077,7 +1092,7 @@
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="5"
Grid.Row="6"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
@@ -1085,13 +1100,13 @@
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
<ToggleButton
x:Name="togEnableExInbound"
Grid.Row="5"
Grid.Row="6"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />
<TextBlock
Grid.Row="6"
Grid.Row="7"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
@@ -1099,7 +1114,7 @@
Text="{x:Static resx:ResUI.TbSettingsEnableIPv6Address}" />
<ToggleButton
x:Name="togEnableIPv6Address"
Grid.Row="6"
Grid.Row="7"
Grid.Column="1"
Margin="{StaticResource Margin8}"
HorizontalAlignment="Left" />

View File

@@ -117,6 +117,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunAutoRoute, v => v.togAutoRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.Text).DisposeWith(disposables);

View File

@@ -78,7 +78,6 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -109,21 +108,6 @@
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
<ComboBox
x:Name="cmbdomainMatcher"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkdomainStrategy4Singbox_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
@@ -132,7 +116,7 @@
</TextBlock>
<ComboBox
x:Name="cmbdomainStrategy4Singbox"
Grid.Row="2"
Grid.Row="1"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}"

View File

@@ -22,7 +22,6 @@ public partial class RoutingSettingWindow
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
cmbdomainStrategy.ItemsSource = Global.DomainStrategies;
cmbdomainMatcher.ItemsSource = Global.DomainMatchers;
cmbdomainStrategy4Singbox.ItemsSource = Global.DomainStrategies4Singbox;
this.WhenActivated(disposables =>
@@ -31,7 +30,6 @@ public partial class RoutingSettingWindow
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainMatcher, v => v.cmbdomainMatcher.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DomainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);