Compare commits

...

51 Commits
7.0.9 ... 7.2.0

Author SHA1 Message Date
2dust
05d446ed37 up 7.2.0 2024-11-22 18:04:36 +08:00
2dust
7a0b068642 Improve Follow System Theme for windows 2024-11-22 17:37:30 +08:00
2dust
c0ef8c09af Add Follow System Theme for desktop 2024-11-22 17:35:49 +08:00
fonaix
a2db6dd468 修复:TrayIcon不跟随代理模式变化的问题 (#6126)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题

* 添加:MacOS 打开存储所在位置功能

* 修复:删除全部节点时,UI不更新的问题

* 修复:TrayIcon不跟随代理模式变化的问题
2024-11-21 09:02:35 +08:00
2dust
471bc0f65d Update README.md 2024-11-20 15:33:29 +08:00
2dust
80f840a7c2 Fix
https://github.com/2dust/v2rayN/issues/6119
2024-11-20 15:29:06 +08:00
2dust
a2413fdf23 Remove Routing Basic function 2024-11-20 12:01:04 +08:00
2dust
9cbe2b938c Fixed the inbound issue caused by server configuration error during speed test
https://github.com/2dust/v2rayN/issues/6110
2024-11-20 10:34:51 +08:00
2dust
e915726c52 Improved upgrade
https://github.com/2dust/v2rayN/issues/6102
2024-11-20 10:29:04 +08:00
2dust
b11e68cfd8 Remove StatisticsV2rayService
Remove ProtosLib project
2024-11-19 19:20:12 +08:00
2dust
bee66d06dd Added real IP location display
https://ipapi.co/api/?shell#introduction
2024-11-19 16:43:00 +08:00
2dust
945a0add96 Code clean 2024-11-19 15:52:08 +08:00
2dust
294cabcf05 Update README.md 2024-11-18 17:14:42 +08:00
2dust
22eb993ebf up 7.1.3 2024-11-18 16:51:51 +08:00
2dust
b5e1a297ae Optimize Linux start tun mode
You can choose not to store the password and enter it manually each time
2024-11-18 16:44:12 +08:00
2dust
499a16feae Fix LocalizationHelper for AmazTool 2024-11-18 10:13:49 +08:00
Slnanx
1866a59d12 更新程序内嵌资源文件 (#6101)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了

* 内嵌资源

* Update LocalizationHelper.cs
2024-11-18 09:57:38 +08:00
2dust
10513e0f3b Fixed the problem that the statistics column would not be hidden 2024-11-18 09:56:13 +08:00
Slnanx
2e32de2fbb fix (#6099)
* fix

* fix

* 移除自述

* 改用单例模式,避免多次初始化。

* 小修正

* 修正

* 更正自述

* 应该完成了
2024-11-17 19:42:14 +08:00
2dust
30a838df77 Bug fix
https://github.com/2dust/v2rayN/issues/6092
2024-11-17 16:18:46 +08:00
2dust
7cf9b9f57e up 7.1.2 2024-11-17 14:15:37 +08:00
2dust
736d995d4c up PackageReference 2024-11-17 14:11:51 +08:00
2dust
e335b2c0d6 Fix with AppendQuotes 2024-11-17 14:11:17 +08:00
2dust
96ae5517f6 Improve core msg 2024-11-17 09:58:57 +08:00
Slnanx
fb4b8d923a 可以通过判断系统语言来显示对应语言 (#6083) 2024-11-17 09:42:40 +08:00
2dust
2ade705e51 Bug fix 2024-11-16 20:15:05 +08:00
NagisaEfi
e0086b4b79 Update ResUI.zh-Hant.resx (#6080) 2024-11-16 10:34:55 +08:00
2dust
8f6d443104 Hide to tray when closing the window
https://github.com/2dust/v2rayN/issues/6076
2024-11-15 19:50:37 +08:00
2dust
5dbce16895 up 7.1.1 2024-11-15 13:36:44 +08:00
2dust
1016dcb3d1 Improve PAC 2024-11-15 11:59:22 +08:00
2dust
ba5ad12e13 Linux password encryption storage 2024-11-15 09:42:49 +08:00
2dust
57f9c8158e up 7.1.0 2024-11-14 15:20:14 +08:00
2dust
b8a0293b52 Add xhttp extra for xray
https://github.com/XTLS/Xray-core/pull/4000
2024-11-14 14:37:03 +08:00
2dust
59b7daaef5 Improve UI 2024-11-14 14:25:58 +08:00
2dust
d781c768e9 Add xhttp mode for xray
https://github.com/XTLS/Xray-core/pull/3994
2024-11-14 09:48:43 +08:00
2dust
04efed2079 SplitHTTP is now XHTTP for xray 2024-11-13 19:48:44 +08:00
2dust
2de9e14c7d xray-core uses quic to add failure prompts and plans to remove quic 2024-11-13 19:00:35 +08:00
2dust
a849dec6c2 Remove SagerNet 2024-11-13 18:00:31 +08:00
2dust
28019dc511 Migrate xray traffic statistics to Metrics
https://xtls.github.io/config/metrics.html
2024-11-13 16:45:23 +08:00
2dust
9d638968a9 Use tun mode without running with sudo in linux 2024-11-13 16:22:56 +08:00
2dust
f921ff7d77 Update README.md 2024-11-13 16:00:01 +08:00
NagisaEfi
e3ea329795 Update ResUI.zh-Hant.resx (#6049) 2024-11-13 09:49:41 +08:00
TTG
87f1c129b6 Update DNS Routing (#6045)
* Update DNS Routing

* Removed outdated DNS IP
2024-11-12 09:42:10 +08:00
2dust
a1c8bc0e61 Improve the code 2024-11-11 16:56:08 +08:00
fonaix
61e9101851 添加:MacOS 打开存储所在位置功能 (#6038)
* 添加:MacOS 代理配置与清除

* 修复:点击表头排序时,超时服务器排在前面的问题

* 添加:MacOS 打开存储所在位置功能

* 修复:删除全部节点时,UI不更新的问题
2024-11-11 09:48:20 +08:00
2dust
a6289347cc Bug fix
https://github.com/2dust/v2rayN/issues/6037
2024-11-11 09:37:49 +08:00
2dust
9e84de8e76 Migrating the sing-box configuration to 1.10.0
https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged
2024-11-10 17:30:03 +08:00
2dust
d04cc53152 Fill ResUI 2024-11-10 17:25:36 +08:00
2dust
1ff3c5fc07 Fix
https://github.com/2dust/v2rayN/issues/6032
2024-11-10 17:24:41 +08:00
2dust
3db047a12f Fix 2024-11-09 14:37:48 +08:00
TTG
bf4615f2f2 Update Configuration to Optimize (#6027)
* Remove geolocation-cn

* Segment and update DNS lists
2024-11-09 09:28:10 +08:00
99 changed files with 2281 additions and 1461 deletions

View File

@@ -1,5 +1,5 @@
# v2rayN # v2rayN
A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/Xray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master) [![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayN)](https://github.com/2dust/v2rayN/commits/master)
@@ -9,13 +9,19 @@ A GUI client for Windows, support [Xray core](https://github.com/XTLS/Xray-core)
## How to use ## How to use
- If you are new to this, please download v2rayN-With-Core.zip from [releases](https://github.com/2dust/v2rayN/releases) Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-files-introduction) and select the version you need to download
- Otherwise please download v2rayN.zip (you will also need to download cores in the bin directory) ### Windows
- Run v2rayN.exe - Run `v2rayN.exe`
### Linux
- `chmod +x v2rayN` Run `./v2rayN`
```
Debian 9+
Ubuntu 16.04+
Fedora 30+
```
## Requirements ## Requirements
- (6.35 and above)[Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) - [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- (6.33 and below)[Microsoft .NET 6.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores) - [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)

View File

@@ -8,5 +8,10 @@
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright> <Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
<FileVersion>1.3.0</FileVersion> <FileVersion>1.3.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Assets\en-US.json" />
<EmbeddedResource Include="Assets\zh-CN.json" />
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,14 @@
{
"Restart_v2rayN": "Start v2rayN, please wait...",
"Guidelines": "Please run it from the main application.",
"Upgrade_File_Not_Found": "Upgrade failed, file not found.",
"In_Progress": "In progress, please wait...",
"Try_Terminate_Process": "Try to terminate the v2rayN process.",
"Failed_Terminate_Process": "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.",
"Start_Unzipping": "Start extracting the update package.",
"Success_Unzipping": "Successfully extracted the update package!",
"Failed_Unzipping": "Failed to extract the update package!",
"Failed_Upgrade": "Upgrade failed!",
"Success_Upgrade": "Upgrade success!",
"Information": "Information"
}

View File

@@ -0,0 +1,14 @@
{
"Restart_v2rayN": "正在重启,请等待...",
"Guidelines": "请从主应用运行!",
"Upgrade_File_Not_Found": "升级失败,文件不存在!",
"In_Progress": "正在进行中,请等待...",
"Try_Terminate_Process": "尝试结束 v2rayN 进程...",
"Failed_Terminate_Process": "请手动关闭正在运行的v2rayN否则可能升级失败。",
"Start_Unzipping": "开始解压缩更新包...",
"Success_Unzipping": "解压缩更新包成功!",
"Failed_Unzipping": "解压缩更新包失败!",
"Failed_Upgrade": "升级失败!",
"Success_Upgrade": "升级成功!",
"Information": "提示"
}

View File

@@ -0,0 +1,59 @@
using System.Globalization;
using System.Reflection;
using System.Text.Json;
namespace AmazTool
{
public class LocalizationHelper
{
private static Dictionary<string, string> _languageResources = [];
static LocalizationHelper()
{
// 加载语言资源
LoadLanguageResources();
}
private static void LoadLanguageResources()
{
try
{
var currentLanguage = CultureInfo.CurrentCulture.Name;
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
{
currentLanguage = "en-US";
}
var resourceName = $"AmazTool.Assets.{currentLanguage}.json";
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null) return;
using StreamReader reader = new(stream);
var json = reader.ReadToEnd();
if (!string.IsNullOrEmpty(json))
{
_languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
}
}
catch (IOException ex)
{
Console.WriteLine($"Failed to read language resource file: {ex.Message}");
}
catch (JsonException ex)
{
Console.WriteLine($"Failed to parse JSON data: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error occurred: {ex.Message}");
}
}
public static string GetLocalizedValue(string key)
{
return _languageResources.TryGetValue(key, out var translation) ? translation : key;
}
}
}

View File

@@ -10,7 +10,7 @@
{ {
if (args.Length == 0) if (args.Length == 0)
{ {
Console.WriteLine("Please run it from the main application.(请从主应用运行)"); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
Thread.Sleep(5000); Thread.Sleep(5000);
return; return;
} }

View File

@@ -8,35 +8,37 @@ namespace AmazTool
{ {
public static void Upgrade(string fileName) public static void Upgrade(string fileName)
{ {
Console.WriteLine(fileName); Console.WriteLine($"{LocalizationHelper.GetLocalizedValue("Start_Unzipping")}\n{fileName}");
Console.WriteLine("In progress, please wait...(正在进行中,请等待)");
Thread.Sleep(9000); Waiting(9);
if (!File.Exists(fileName)) if (!File.Exists(fileName))
{ {
Console.WriteLine("Upgrade Failed, File Not Exist(升级失败,文件不存在)."); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
return; return;
} }
Console.WriteLine("Try to end the process(尝试结束进程)."); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
try try
{ {
var existing = Process.GetProcessesByName(V2rayN); var existing = Process.GetProcessesByName(V2rayN);
foreach (var pp in existing) foreach (var pp in existing)
{ {
pp?.Kill(); var path = pp.MainModule?.FileName ?? "";
pp?.WaitForExit(1000); if (path.StartsWith(GetPath(V2rayN)))
{
pp?.Kill();
pp?.WaitForExit(1000);
}
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
// Access may be denied without admin right. The user may not be an administrator. // Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine("Failed to close v2rayN(关闭v2rayN失败).\n" + Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Terminate_Process") + ex.StackTrace);
"Close it manually, or the upgrade may fail.(请手动关闭正在运行的v2rayN否则可能升级失败。\n\n" + ex.StackTrace);
} }
Console.WriteLine("Start extracting files(开始解压文件)."); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Start_Unzipping"));
StringBuilder sb = new(); StringBuilder sb = new();
try try
{ {
@@ -79,17 +81,17 @@ namespace AmazTool
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("Upgrade Failed(升级失败)." + ex.StackTrace); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
//return; //return;
} }
if (sb.Length > 0) if (sb.Length > 0)
{ {
Console.WriteLine("Upgrade Failed(升级失败)." + sb.ToString()); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
//return; //return;
} }
Console.WriteLine("Start v2rayN, please wait...(正在重启,请等待)"); Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
Thread.Sleep(9000); Waiting(9);
Process process = new() Process process = new()
{ {
StartInfo = new() StartInfo = new()
@@ -122,6 +124,15 @@ namespace AmazTool
return Path.Combine(startupPath, fileName); return Path.Combine(startupPath, fileName);
} }
private static void Waiting(int second)
{
for (var i = second; i > 0; i--)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
private static string V2rayN => "v2rayN"; private static string V2rayN => "v2rayN";
} }
} }

View File

@@ -11,11 +11,11 @@ public class PacHandler
private static int _httpPort; private static int _httpPort;
private static int _pacPort; private static int _pacPort;
private static TcpListener? _tcpListener; private static TcpListener? _tcpListener;
private static string _pacText; private static byte[] _writeContent;
private static bool _isRunning; private static bool _isRunning;
private static bool _needRestart = true; private static bool _needRestart = true;
public static void Start(string configPath, int httpPort, int pacPort) public static async Task Start(string configPath, int httpPort, int pacPort)
{ {
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning); _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
@@ -23,7 +23,7 @@ public class PacHandler
_httpPort = httpPort; _httpPort = httpPort;
_pacPort = pacPort; _pacPort = pacPort;
InitText(); await InitText();
if (_needRestart) if (_needRestart)
{ {
@@ -32,15 +32,24 @@ public class PacHandler
} }
} }
private static void InitText() private static async Task InitText()
{ {
var path = Path.Combine(_configPath, "pac.txt"); var path = Path.Combine(_configPath, "pac.txt");
if (!File.Exists(path)) if (!File.Exists(path))
{ {
File.AppendAllText(path, Resources.ResourceManager.GetString("pac")); await File.AppendAllTextAsync(path, Resources.ResourceManager.GetString("pac"));
} }
_pacText = File.ReadAllText(path).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;"); var pacText = (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
sb.AppendLine();
sb.Append(pacText);
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
} }
private static void RunListener() private static void RunListener()
@@ -60,21 +69,8 @@ public class PacHandler
continue; continue;
} }
var client = _tcpListener.AcceptTcpClient(); var client = await _tcpListener.AcceptTcpClientAsync();
await Task.Run(() => await Task.Run(() => { WriteContent(client); });
{
var stream = client.GetStream();
var sb = new StringBuilder();
sb.AppendLine("HTTP/1.0 200 OK");
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
sb.AppendLine("Connection:close");
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(_pacText));
sb.AppendLine();
sb.Append(_pacText);
var content = Encoding.UTF8.GetBytes(sb.ToString());
stream.Write(content, 0, content.Length);
stream.Flush();
});
} }
catch catch
{ {
@@ -84,6 +80,13 @@ public class PacHandler
}, TaskCreationOptions.LongRunning); }, TaskCreationOptions.LongRunning);
} }
private static void WriteContent(TcpClient client)
{
var stream = client.GetStream();
stream.Write(_writeContent, 0, _writeContent.Length);
stream.Flush();
}
public static void Stop() public static void Stop()
{ {
if (_tcpListener == null) return; if (_tcpListener == null) return;

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Statistics.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.28.3" />
<PackageReference Include="Grpc.Net.Client" Version="2.66.0" />
<PackageReference Include="Grpc.Tools" Version="2.67.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -1,53 +0,0 @@
syntax = "proto3";
package v2ray.core.app.stats.command;
option csharp_namespace = "ProtosLib.Statistics";
message GetStatsRequest {
// Name of the stat counter.
string name = 1;
// Whether or not to reset the counter to fetching its value.
bool reset = 2;
}
message Stat {
string name = 1;
int64 value = 2;
}
message GetStatsResponse {
Stat stat = 1;
}
message QueryStatsRequest {
string pattern = 1;
bool reset = 2;
}
message QueryStatsResponse {
repeated Stat stat = 1;
}
message SysStatsRequest {
}
message SysStatsResponse {
uint32 NumGoroutine = 1;
uint32 NumGC = 2;
uint64 Alloc = 3;
uint64 TotalAlloc = 4;
uint64 Sys = 5;
uint64 Mallocs = 6;
uint64 Frees = 7;
uint64 LiveObjects = 8;
uint64 PauseTotalNs = 9;
uint32 Uptime = 10;
}
service StatsService {
rpc GetStats(GetStatsRequest) returns (GetStatsResponse) {}
rpc QueryStats(QueryStatsRequest) returns (QueryStatsResponse) {}
rpc GetSysStats(SysStatsRequest) returns (SysStatsResponse) {}
}
message Config {}

View File

@@ -1,13 +0,0 @@
using ProtosLib.Statistics;
namespace ProtosLib
{
public class Tests
{
private StatsService.StatsServiceClient client_;
public Tests()
{
}
}
}

View File

@@ -0,0 +1,75 @@
using System.Security.Cryptography;
using System.Text;
namespace ServiceLib.Common
{
public class DesUtils
{
/// <summary>
/// Encrypt
/// </summary>
/// <param name="text"></param>
/// /// <param name="key"></param>
/// <returns></returns>
public static string Encrypt(string? text, string? key = null)
{
if (text.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateEncryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
using var sWriter = new StreamWriter(cryStream);
sWriter.Write(text);
sWriter.Flush();
cryStream.FlushFinalBlock();
memStream.Flush();
return Convert.ToBase64String(memStream.GetBuffer(), 0, (int)memStream.Length);
}
/// <summary>
/// Decrypt
/// </summary>
/// <param name="encryptText"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Decrypt(string? encryptText, string? key = null)
{
if (encryptText.IsNullOrEmpty())
{
return string.Empty;
}
GetKeyIv(key ?? GetDefaultKey(), out var rgbKey, out var rgbIv);
var dsp = DES.Create();
var buffer = Convert.FromBase64String(encryptText);
using var memStream = new MemoryStream();
using var cryStream = new CryptoStream(memStream, dsp.CreateDecryptor(rgbKey, rgbIv), CryptoStreamMode.Write);
cryStream.Write(buffer, 0, buffer.Length);
cryStream.FlushFinalBlock();
return Encoding.UTF8.GetString(memStream.ToArray());
}
private static void GetKeyIv(string key, out byte[] rgbKey, out byte[] rgbIv)
{
if (key.IsNullOrEmpty())
{
throw new ArgumentNullException("The key cannot be null");
}
if (key.Length <= 8)
{
throw new ArgumentNullException("The key length cannot be less than 8 characters.");
}
rgbKey = Encoding.ASCII.GetBytes(key.Substring(0, 8));
rgbIv = Encoding.ASCII.GetBytes(key.Insert(0, "w").Substring(0, 8));
}
private static string GetDefaultKey()
{
return Utils.GetMd5(Utils.GetHomePath() + "DesUtils");
}
}
}

View File

@@ -4,12 +4,8 @@
{ {
v2fly = 1, v2fly = 1,
Xray = 2, Xray = 2,
//SagerNet = 3,
v2fly_v5 = 4, v2fly_v5 = 4,
//clash = 11,
//clash_meta = 12,
mihomo = 13, mihomo = 13,
hysteria = 21, hysteria = 21,

View File

@@ -7,6 +7,7 @@
ws, ws,
httpupgrade, httpupgrade,
splithttp, splithttp,
xhttp,
h2, h2,
http, http,
quic, quic,

View File

@@ -20,6 +20,7 @@
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases"; public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"; public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs"; public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string IPAPIUrl = "https://ipapi.co/json";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="; public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json"; public const string ConfigFileName = "guiNConfig.json";
@@ -175,11 +176,10 @@
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" }; public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" }; public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
public static readonly List<string> SsSecuritiesInSagerNet = new() { "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "rc4", "rc4-md5", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-cfb8", "aes-192-cfb8", "aes-256-cfb8", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "bf-cfb", "cast5-cfb", "des-cfb", "idea-cfb", "rc2-cfb", "seed-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "camellia-128-cfb8", "camellia-192-cfb8", "camellia-256-cfb8", "salsa20", "chacha20", "chacha20-ietf", "xchacha20" };
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }; public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" }; public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" }; public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "splithttp", "h2", "quic", "grpc" }; public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "splithttp", "h2", "quic", "grpc" };
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" }; public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" }; public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" }; public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
@@ -188,6 +188,7 @@
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" }; public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" }; public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" }; public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up" };
public static readonly List<string> AllowInsecure = new() { "true", "false", "" }; public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" }; public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
@@ -207,9 +208,9 @@
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" }; public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" }; public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
public static readonly List<string> allowSelectType = new List<string> { "selector", "urltest", "loadbalance", "fallback" }; public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" };
public static readonly List<string> notAllowTestType = new List<string> { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" }; public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
public static readonly List<string> proxyVehicleType = new List<string> { "file", "http" }; public static readonly List<string> proxyVehicleType = new() { "file", "http" };
#endregion const #endregion const
} }

View File

@@ -211,12 +211,12 @@
public async Task<List<RoutingItem>?> RoutingItems() public async Task<List<RoutingItem>?> RoutingItems()
{ {
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(it => it.Locked == false).OrderBy(t => t.Sort).ToListAsync(); return await SQLiteHelper.Instance.TableAsync<RoutingItem>().OrderBy(t => t.Sort).ToListAsync();
} }
public async Task<RoutingItem?> GetRoutingItem(string id) public async Task<RoutingItem?> GetRoutingItem(string id)
{ {
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == false && it.Id == id); return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Id == id);
} }
public async Task<List<DNSItem>?> DNSItems() public async Task<List<DNSItem>?> DNSItems()
@@ -247,7 +247,7 @@
case ECoreType.sing_box: case ECoreType.sing_box:
return Global.SsSecuritiesInSingbox; return Global.SsSecuritiesInSingbox;
} }
return Global.SsSecuritiesInSagerNet; return Global.SsSecuritiesInSingbox;
} }
public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType)

View File

@@ -65,10 +65,8 @@ namespace ServiceLib.Handler
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString(); config.Inbound[0].Protocol = EInboundProtocol.socks.ToString();
} }
} }
config.RoutingBasicItem ??= new()
{ config.RoutingBasicItem ??= new();
EnableRoutingAdvanced = true
};
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy)) if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
{ {
@@ -240,6 +238,7 @@ namespace ServiceLib.Handler
item.PublicKey = profileItem.PublicKey; item.PublicKey = profileItem.PublicKey;
item.ShortId = profileItem.ShortId; item.ShortId = profileItem.ShortId;
item.SpiderX = profileItem.SpiderX; item.SpiderX = profileItem.SpiderX;
item.Extra = profileItem.Extra;
} }
var ret = item.ConfigType switch var ret = item.ConfigType switch
@@ -958,7 +957,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address && o.Address == n.Address
&& o.Port == n.Port && o.Port == n.Port
&& o.Id == n.Id && o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security && o.Security == n.Security
&& o.Network == n.Network && o.Network == n.Network
&& o.HeaderType == n.HeaderType && o.HeaderType == n.HeaderType
@@ -967,6 +965,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity) && (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow && o.Flow == n.Flow
&& o.Sni == n.Sni && o.Sni == n.Sni
&& o.Alpn == n.Alpn
&& o.Fingerprint == n.Fingerprint
&& o.PublicKey == n.PublicKey
&& o.ShortId == n.ShortId
&& (!remarks || o.Remarks == n.Remarks); && (!remarks || o.Remarks == n.Remarks);
} }
@@ -1294,6 +1296,20 @@ namespace ServiceLib.Handler
} }
} }
//Keep the last traffic statistics
if (lstOriSub != null)
{
var lstSub = await AppHandler.Instance.ProfileItems(subid);
foreach (var item in lstSub)
{
var existItem = lstOriSub?.FirstOrDefault(t => config.UiItem.EnableUpdateSubOnlyRemarksExist ? t.Remarks == item.Remarks : CompareProfileItem(t, item, true));
if (existItem != null)
{
await StatisticsHandler.Instance.CloneServerStatItem(existItem.IndexId, item.IndexId);
}
}
}
return counter; return counter;
} }
@@ -1596,7 +1612,7 @@ namespace ServiceLib.Handler
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId); var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
if (item is null) if (item is null)
{ {
var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(t => t.Locked == false); var item2 = await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync();
await SetDefaultRouting(config, item2); await SetDefaultRouting(config, item2);
return item2; return item2;
} }
@@ -1670,6 +1686,15 @@ namespace ServiceLib.Handler
{ {
var ver = "V3-"; var ver = "V3-";
var items = await AppHandler.Instance.RoutingItems(); var items = await AppHandler.Instance.RoutingItems();
//TODO Temporary code to be removed later
var lockItem = items?.FirstOrDefault(t => t.Locked == true);
if (lockItem != null)
{
await ConfigHandler.RemoveRoutingItem(lockItem);
items = await AppHandler.Instance.RoutingItems();
}
if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0) if (!blImportAdvancedRules && items.Where(t => t.Remarks.StartsWith(ver)).ToList().Count > 0)
{ {
return 0; return 0;
@@ -1710,11 +1735,6 @@ namespace ServiceLib.Handler
return 0; return 0;
} }
public static async Task<RoutingItem?> GetLockedRoutingItem(Config config)
{
return await SQLiteHelper.Instance.TableAsync<RoutingItem>().FirstOrDefaultAsync(it => it.Locked == true);
}
public static async Task RemoveRoutingItem(RoutingItem routingItem) public static async Task RemoveRoutingItem(RoutingItem routingItem)
{ {
await SQLiteHelper.Instance.DeleteAsync(routingItem); await SQLiteHelper.Instance.DeleteAsync(routingItem);

View File

@@ -59,15 +59,18 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName); var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName); var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(false, result.Msg);
if (result.Success != true) if (result.Success != true)
{ {
ShowMsg(true, result.Msg);
return; return;
} }
else else
{ {
ShowMsg(true, $"{node.GetSummary()}"); ShowMsg(true, $"{node.GetSummary()}");
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop(); await CoreStop();
await Task.Delay(100);
await CoreStart(node); await CoreStart(node);
//In tun mode, do a delay check and restart the core //In tun mode, do a delay check and restart the core
@@ -99,6 +102,8 @@ namespace ServiceLib.Handler
ShowMsg(false, result.Msg); ShowMsg(false, result.Msg);
if (result.Success) if (result.Success)
{ {
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
pid = await CoreStartSpeedtest(configPath, coreType); pid = await CoreStartSpeedtest(configPath, coreType);
} }
return pid; return pid;
@@ -145,7 +150,7 @@ namespace ServiceLib.Handler
private string CoreFindExe(CoreInfo coreInfo) private string CoreFindExe(CoreInfo coreInfo)
{ {
string fileName = string.Empty; var fileName = string.Empty;
foreach (var name in coreInfo.CoreExes) foreach (var name in coreInfo.CoreExes)
{ {
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString()); var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
@@ -157,7 +162,7 @@ namespace ServiceLib.Handler
} }
if (Utils.IsNullOrEmpty(fileName)) if (Utils.IsNullOrEmpty(fileName))
{ {
string msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url); var msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
Logging.SaveLog(msg); Logging.SaveLog(msg);
ShowMsg(false, msg); ShowMsg(false, msg);
} }
@@ -166,24 +171,12 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node) private async Task CoreStart(ProfileItem node)
{ {
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
//ECoreType coreType;
//if (node.configType != EConfigType.Custom && _config.tunModeItem.enableTun)
//{
// coreType = ECoreType.sing_box;
//}
//else
//{
// coreType = LazyConfig.Instance.GetCoreType(node, node.configType);
//}
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType); var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType; _config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog; var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
var proc = await RunProcess(node, coreInfo, "", displayLog); var proc = await RunProcess(coreInfo, Global.CoreConfigFileName, displayLog, true);
if (proc is null) if (proc is null)
{ {
return; return;
@@ -220,12 +213,12 @@ namespace ServiceLib.Handler
} }
if (itemSocks != null) if (itemSocks != null)
{ {
string fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName); var fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2); var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
if (result.Success) if (result.Success)
{ {
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType); var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
var proc2 = await RunProcess(node, coreInfo2, $" -c {Global.CorePreConfigFileName}", true); var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true, true);
if (proc2 is not null) if (proc2 is not null)
{ {
_processPre = proc2; _processPre = proc2;
@@ -237,13 +230,10 @@ namespace ServiceLib.Handler
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType) private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{ {
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try try
{ {
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType); var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
var proc = await RunProcess(new(), coreInfo, $" -c {Global.CoreSpeedtestConfigFileName}", true); var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
if (proc is null) if (proc is null)
{ {
return -1; return -1;
@@ -254,8 +244,7 @@ namespace ServiceLib.Handler
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; ShowMsg(false, ex.Message);
ShowMsg(false, msg);
return -1; return -1;
} }
} }
@@ -265,19 +254,29 @@ namespace ServiceLib.Handler
_updateFunc?.Invoke(notify, msg); _updateFunc?.Invoke(notify, msg);
} }
private bool IsNeedSudo(ECoreType eCoreType)
{
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& Utils.IsLinux()
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
#endregion Private #endregion Private
#region Process #region Process
private async Task<Process?> RunProcess(ProfileItem node, CoreInfo coreInfo, string configPath, bool displayLog) private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
{ {
var fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
try try
{ {
string fileName = CoreFindExe(coreInfo);
if (Utils.IsNullOrEmpty(fileName))
{
return null;
}
Process proc = new() Process proc = new()
{ {
StartInfo = new() StartInfo = new()
@@ -293,33 +292,44 @@ namespace ServiceLib.Handler
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null, StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
}
var startUpErrorMessage = new StringBuilder(); var startUpErrorMessage = new StringBuilder();
var startUpSuccessful = false; var startUpSuccessful = false;
if (displayLog) if (displayLog)
{ {
proc.OutputDataReceived += (sender, e) => proc.OutputDataReceived += (sender, e) =>
{ {
if (Utils.IsNotEmpty(e.Data)) if (Utils.IsNullOrEmpty(e.Data)) return;
{ ShowMsg(false, e.Data + Environment.NewLine);
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
}
}; };
proc.ErrorDataReceived += (sender, e) => proc.ErrorDataReceived += (sender, e) =>
{ {
if (Utils.IsNotEmpty(e.Data)) if (Utils.IsNullOrEmpty(e.Data)) return;
{ ShowMsg(false, e.Data + Environment.NewLine);
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
if (!startUpSuccessful) if (!startUpSuccessful)
{ {
startUpErrorMessage.Append(msg); startUpErrorMessage.Append(e.Data + Environment.NewLine);
}
} }
}; };
} }
proc.Start(); proc.Start();
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
await Task.Delay(10);
await proc.StandardInput.WriteLineAsync(pwd);
}
if (displayLog) if (displayLog)
{ {
proc.BeginOutputReadLine(); proc.BeginOutputReadLine();
@@ -342,32 +352,68 @@ namespace ServiceLib.Handler
catch (Exception ex) catch (Exception ex)
{ {
Logging.SaveLog(ex.Message, ex); Logging.SaveLog(ex.Message, ex);
string msg = ex.Message; ShowMsg(true, ex.Message);
ShowMsg(true, msg);
return null; return null;
} }
} }
private async Task RunProcessAsLinuxRoot(Process proc, string fileName, CoreInfo coreInfo, string configPath)
{
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
//Prefer shell scripts
var shFilePath = Utils.GetBinPath("run_as_root.sh");
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
sb.AppendLine(cmdLine);
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
//Replace command
var args = File.Exists(shFilePath) ? shFilePath : cmdLine;
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {args}";
}
else
{
proc.StartInfo.FileName = $"/bin/pkexec";
proc.StartInfo.Arguments = $"{args}";
}
proc.StartInfo.WorkingDirectory = null;
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
Logging.SaveLog(proc.StartInfo.Arguments);
}
private async Task KillProcess(Process? proc) private async Task KillProcess(Process? proc)
{ {
if (proc is null) if (proc is null)
{ {
return; return;
} }
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
try try
{
await proc.WaitForExitAsync(timeout.Token);
}
catch (OperationCanceledException)
{ {
proc.Kill(); proc.Kill();
proc.WaitForExit(100); }
if (!proc.HasExited) if (!proc.HasExited)
{
try
{
await proc.WaitForExitAsync(timeout.Token);
}
catch (Exception)
{ {
proc.Kill(); proc.Kill();
proc.WaitForExit(100);
} }
} }
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
} }
#endregion Process #endregion Process

View File

@@ -1,6 +1,4 @@
using System.Runtime.Intrinsics.X86; namespace ServiceLib.Handler
namespace ServiceLib.Handler
{ {
public sealed class CoreInfoHandler public sealed class CoreInfoHandler
{ {
@@ -74,7 +72,7 @@ namespace ServiceLib.Handler
{ {
CoreType = ECoreType.Xray, CoreType = ECoreType.Xray,
CoreExes = new List<string> { "xray", "wxray" }, CoreExes = new List<string> { "xray", "wxray" },
Arguments = "run {0}", Arguments = "run -c {0}",
Url = Global.XrayCoreUrl, Url = Global.XrayCoreUrl,
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip", DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
@@ -89,7 +87,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.mihomo, CoreType = ECoreType.mihomo,
CoreExes = new List<string> { $"mihomo-windows-amd64{(Avx2.X64.IsSupported ? "" : "-compatible")}", "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-windows-386", "mihomo", "clash" }, CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
Arguments = "-f config.json" + PortableMode(), Arguments = "-f config.json" + PortableMode(),
Url = Global.MihomoCoreUrl, Url = Global.MihomoCoreUrl,
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -105,7 +103,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.hysteria, CoreType = ECoreType.hysteria,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -134,7 +132,7 @@ namespace ServiceLib.Handler
{ {
CoreType = ECoreType.sing_box, CoreType = ECoreType.sing_box,
CoreExes = new List<string> { "sing-box-client", "sing-box" }, CoreExes = new List<string> { "sing-box-client", "sing-box" },
Arguments = "run {0} --disable-color", Arguments = "run -c {0} --disable-color",
Url = Global.SingboxCoreUrl, Url = Global.SingboxCoreUrl,
RedirectInfo = true, RedirectInfo = true,
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -157,7 +155,7 @@ namespace ServiceLib.Handler
_coreInfo.Add(new CoreInfo _coreInfo.Add(new CoreInfo
{ {
CoreType = ECoreType.hysteria2, CoreType = ECoreType.hysteria2,
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-windows-386", "hysteria" }, CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria" },
Arguments = "", Arguments = "",
Url = Global.HysteriaCoreUrl, Url = Global.HysteriaCoreUrl,
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl), ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
@@ -167,7 +165,7 @@ namespace ServiceLib.Handler
private string PortableMode() private string PortableMode()
{ {
return $" -d \"{Utils.GetBinPath("")}\""; return $" -d {Utils.GetBinPath("").AppendQuotes()}";
} }
} }
} }

View File

@@ -83,7 +83,6 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (Utils.IsNotEmpty(item.RequestHost)) if (Utils.IsNotEmpty(item.RequestHost))
{ {
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost)); dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
@@ -94,6 +93,26 @@ namespace ServiceLib.Handler.Fmt
} }
break; break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
if (Utils.IsNotEmpty(item.RequestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
}
if (Utils.IsNotEmpty(item.Path))
{
dicQuery.Add("path", Utils.UrlEncode(item.Path));
}
if (Utils.IsNotEmpty(item.HeaderType) && Global.XhttpMode.Contains(item.HeaderType))
{
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
}
if (Utils.IsNotEmpty(item.Extra))
{
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
}
break;
case nameof(ETransport.http): case nameof(ETransport.http):
case nameof(ETransport.h2): case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http); dicQuery["type"] = nameof(ETransport.http);
@@ -156,11 +175,18 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? ""); item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/"); item.Path = Utils.UrlDecode(query["path"] ?? "/");
break; break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
item.Path = Utils.UrlDecode(query["path"] ?? "/");
item.HeaderType = Utils.UrlDecode(query["mode"] ?? "");
item.Extra = Utils.UrlDecode(query["extra"] ?? "");
break;
case nameof(ETransport.http): case nameof(ETransport.http):
case nameof(ETransport.h2): case nameof(ETransport.h2):
item.Network = nameof(ETransport.h2); item.Network = nameof(ETransport.h2);

View File

@@ -9,7 +9,8 @@
private ServerStatItem? _serverStatItem; private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat; private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc; private Action<ServerSpeedItem>? _updateFunc;
private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox; private StatisticsSingboxService? _statisticsSingbox;
public List<ServerStatItem> ServerStat => _lstServerStat; public List<ServerStatItem> ServerStat => _lstServerStat;
@@ -25,7 +26,7 @@
await InitData(); await InitData();
_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler); _statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler); _statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
} }
@@ -33,7 +34,7 @@
{ {
try try
{ {
_statisticsV2Ray?.Close(); _statisticsXray?.Close();
_statisticsSingbox?.Close(); _statisticsSingbox?.Close();
} }
catch (Exception ex) catch (Exception ex)
@@ -64,6 +65,25 @@
} }
} }
public async Task CloneServerStatItem(string indexId, string toIndexId)
{
if (_lstServerStat == null)
{
return;
}
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
if (stat == null)
{
return;
}
var toStat = JsonUtils.DeepCopy(stat);
toStat.IndexId = toIndexId;
await SQLiteHelper.Instance.ReplaceAsync(toStat);
_lstServerStat.Add(toStat);
}
private async Task InitData() private async Task InitData()
{ {
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )"); await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

@@ -5,6 +5,7 @@
/* /*
* 仅测试了MacOS 13.7.1 x86 版本,其他版本有待确认 * 仅测试了MacOS 13.7.1 x86 版本,其他版本有待确认
*/ */
/// <summary> /// <summary>
/// 应用接口类型 /// 应用接口类型
/// </summary> /// </summary>
@@ -21,14 +22,12 @@
await ExecCmd(lstCmd); await ExecCmd(lstCmd);
} }
public static async Task UnsetProxy() public static async Task UnsetProxy()
{ {
var lstCmd = GetUnsetCmds(); var lstCmd = GetUnsetCmds();
await ExecCmd(lstCmd); await ExecCmd(lstCmd);
} }
private static async Task ExecCmd(List<CmdItem> lstCmd) private static async Task ExecCmd(List<CmdItem> lstCmd)
{ {
foreach (var cmd in lstCmd) foreach (var cmd in lstCmd)

View File

@@ -33,15 +33,10 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.SetProxy(Global.Loopback, port); await ProxySettingLinux.SetProxy(Global.Loopback, port);
break; break;
case ESysProxyType.ForcedChange: case ESysProxyType.ForcedChange when Utils.IsOSX():
{ await ProxySettingOSX.SetProxy(Global.Loopback, port);
if (Utils.IsOSX()) break;
{
await ProxySettingOSX.SetProxy(Global.Loopback, port);
}
break;
}
case ESysProxyType.ForcedClear when Utils.IsWindows(): case ESysProxyType.ForcedClear when Utils.IsWindows():
ProxySettingWindows.UnsetProxy(); ProxySettingWindows.UnsetProxy();
break; break;
@@ -50,23 +45,13 @@ namespace ServiceLib.Handler.SysProxy
await ProxySettingLinux.UnsetProxy(); await ProxySettingLinux.UnsetProxy();
break; break;
case ESysProxyType.ForcedClear: case ESysProxyType.ForcedClear when Utils.IsOSX():
{ await ProxySettingOSX.UnsetProxy();
if (Utils.IsOSX()) break;
{
await ProxySettingOSX.UnsetProxy();
}
break;
}
case ESysProxyType.Pac when Utils.IsWindows(): case ESysProxyType.Pac when Utils.IsWindows():
{ await SetWindowsProxyPac(port);
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac); break;
PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
break;
}
} }
if (type != ESysProxyType.Pac && Utils.IsWindows()) if (type != ESysProxyType.Pac && Utils.IsWindows())
@@ -102,5 +87,13 @@ namespace ServiceLib.Handler.SysProxy
.Replace("{socks_port}", portSocks.ToString()); .Replace("{socks_port}", portSocks.ToString());
} }
} }
private static async Task SetWindowsProxyPac(int port)
{
var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
ProxySettingWindows.SetProxy(strProxy, "", 4);
}
} }
} }

View File

@@ -20,6 +20,7 @@
case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5: case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5:
case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo: case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo:
return true; return true;
default: default:
return false; return false;
} }

View File

@@ -80,7 +80,7 @@
public bool IgnoreGeoUpdateCore { get; set; } = true; public bool IgnoreGeoUpdateCore { get; set; } = true;
public int AutoUpdateInterval { get; set; } public int AutoUpdateInterval { get; set; }
public bool EnableSecurityProtocolTls13 { get; set; } public bool EnableSecurityProtocolTls13 { get; set; }
public int TrayMenuServersLimit { get; set; } = 20; public int TrayMenuServersLimit { get; set; } = 20;
@@ -116,6 +116,7 @@
public bool EnableDragDropSort { get; set; } public bool EnableDragDropSort { get; set; }
public bool DoubleClick2Activate { get; set; } public bool DoubleClick2Activate { get; set; }
public bool AutoHideStartup { get; set; } public bool AutoHideStartup { get; set; }
public bool Hide2TrayWhenClose { get; set; }
public List<ColumnItem> MainColumnItem { get; set; } public List<ColumnItem> MainColumnItem { get; set; }
public bool ShowInTaskbar { get; set; } public bool ShowInTaskbar { get; set; }
} }
@@ -161,6 +162,7 @@
public int Mtu { get; set; } public int Mtu { get; set; }
public bool EnableExInbound { get; set; } public bool EnableExInbound { get; set; }
public bool EnableIPv6Address { get; set; } public bool EnableIPv6Address { get; set; }
public string? LinuxSudoPwd { get; set; }
} }
[Serializable] [Serializable]
@@ -178,7 +180,6 @@
public string DomainStrategy4Singbox { get; set; } public string DomainStrategy4Singbox { get; set; }
public string DomainMatcher { get; set; } public string DomainMatcher { get; set; }
public string RoutingIndexId { get; set; } public string RoutingIndexId { get; set; }
public bool EnableRoutingAdvanced { get; set; }
} }
[Serializable] [Serializable]

View File

@@ -0,0 +1,13 @@
namespace ServiceLib.Models
{
internal class IPAPIInfo
{
public string? ip { get; set; }
public string? city { get; set; }
public string? region { get; set; }
public string? region_code { get; set; }
public string? country { get; set; }
public string? country_name { get; set; }
public string? country_code { get; set; }
}
}

View File

@@ -30,44 +30,25 @@ namespace ServiceLib.Models
public string GetSummary() public string GetSummary()
{ {
string summary = string.Format("[{0}] ", (ConfigType).ToString()); var summary = $"[{(ConfigType).ToString()}] ";
string[] arrAddr = Address.Split('.'); var arrAddr = Address.Split('.');
string addr; var addr = arrAddr.Length switch
if (arrAddr.Length > 2)
{ {
addr = $"{arrAddr.First()}***{arrAddr.Last()}"; > 2 => $"{arrAddr.First()}***{arrAddr.Last()}",
} > 1 => $"***{arrAddr.Last()}",
else if (arrAddr.Length > 1) _ => Address
};
summary += ConfigType switch
{ {
addr = $"***{arrAddr.Last()}"; EConfigType.Custom => $"[{CoreType.ToString()}]{Remarks}",
} _ => $"{Remarks}({addr}:{Port})"
else };
{
addr = Address;
}
switch (ConfigType)
{
case EConfigType.Custom:
summary += string.Format("[{1}]{0}", Remarks, CoreType.ToString());
break;
default:
summary += string.Format("{0}({1}:{2})", Remarks, addr, Port);
break;
}
return summary; return summary;
} }
public List<string>? GetAlpn() public List<string>? GetAlpn()
{ {
if (Utils.IsNullOrEmpty(Alpn)) return Utils.IsNullOrEmpty(Alpn) ? null : Utils.String2List(Alpn);
{
return null;
}
else
{
return Utils.String2List(Alpn);
}
} }
public string GetNetwork() public string GetNetwork()
@@ -110,5 +91,6 @@ namespace ServiceLib.Models
public string PublicKey { get; set; } public string PublicKey { get; set; }
public string ShortId { get; set; } public string ShortId { get; set; }
public string SpiderX { get; set; } public string SpiderX { get; set; }
public string Extra { get; set; }
} }
} }

View File

@@ -78,8 +78,7 @@
public int? listen_port { get; set; } public int? listen_port { get; set; }
public string? domain_strategy { get; set; } public string? domain_strategy { get; set; }
public string interface_name { get; set; } public string interface_name { get; set; }
public string inet4_address { get; set; } public List<string>? address { get; set; }
public string? inet6_address { get; set; }
public int? mtu { get; set; } public int? mtu { get; set; }
public bool? auto_route { get; set; } public bool? auto_route { get; set; }
public bool? strict_route { get; set; } public bool? strict_route { get; set; }

View File

@@ -2,60 +2,33 @@ using System.Text.Json.Serialization;
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
/// <summary>
/// v2ray配置文件实体类 例子SampleConfig.txt
/// </summary>
public class V2rayConfig public class V2rayConfig
{ {
/// <summary>
/// Properties that do not belong to Ray
/// </summary>
public string? remarks { get; set; } public string? remarks { get; set; }
/// <summary>
/// 日志配置
/// </summary>
public Log4Ray log { get; set; } public Log4Ray log { get; set; }
/// <summary>
/// 传入连接配置
/// </summary>
public List<Inbounds4Ray> inbounds { get; set; } public List<Inbounds4Ray> inbounds { get; set; }
/// <summary>
/// 传出连接配置
/// </summary>
public List<Outbounds4Ray> outbounds { get; set; } public List<Outbounds4Ray> outbounds { get; set; }
/// <summary> public Stats4Ray? stats { get; set; }
/// 统计需要, 空对象
/// </summary>
public Stats4Ray stats { get; set; }
/// </summary> public Metrics4Ray? metrics { get; set; }
public API4Ray api { get; set; }
/// </summary> public Policy4Ray? policy { get; set; }
public Policy4Ray policy { get; set; }
/// <summary>
/// DNS 配置
/// </summary>
public object dns { get; set; } public object dns { get; set; }
/// <summary>
/// 路由配置
/// </summary>
public Routing4Ray routing { get; set; } public Routing4Ray routing { get; set; }
} }
public class Stats4Ray public class Stats4Ray
{ } { }
public class API4Ray public class Metrics4Ray
{ {
public string tag { get; set; } public string tag { get; set; }
public List<string> services { get; set; }
} }
public class Policy4Ray public class Policy4Ray
@@ -71,124 +44,59 @@ namespace ServiceLib.Models
public class Log4Ray public class Log4Ray
{ {
/// <summary> public string? access { get; set; }
///
/// </summary>
public string access { get; set; }
/// <summary> public string? error { get; set; }
///
/// </summary>
public string error { get; set; }
/// <summary> public string? loglevel { get; set; }
///
/// </summary>
public string loglevel { get; set; }
} }
public class Inbounds4Ray public class Inbounds4Ray
{ {
public string tag { get; set; } public string tag { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public string listen { get; set; } public string listen { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Sniffing4Ray sniffing { get; set; } public Sniffing4Ray sniffing { get; set; }
/// <summary>
///
/// </summary>
public Inboundsettings4Ray settings { get; set; } public Inboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; }
} }
public class Inboundsettings4Ray public class Inboundsettings4Ray
{ {
/// <summary> public string? auth { get; set; }
///
/// </summary>
public string auth { get; set; }
/// <summary> public bool? udp { get; set; }
///
/// </summary>
public bool udp { get; set; }
/// <summary> public string? ip { get; set; }
///
/// </summary>
public string ip { get; set; }
/// <summary> public string? address { get; set; }
/// api 使用
/// </summary>
public string address { get; set; }
/// <summary> public List<UsersItem4Ray>? clients { get; set; }
///
/// </summary>
public List<UsersItem4Ray> clients { get; set; }
/// <summary> public string? decryption { get; set; }
/// VLESS
/// </summary>
public string decryption { get; set; }
public bool allowTransparent { get; set; } public bool? allowTransparent { get; set; }
public List<AccountsItem4Ray> accounts { get; set; } public List<AccountsItem4Ray>? accounts { get; set; }
} }
public class UsersItem4Ray public class UsersItem4Ray
{ {
/// <summary> public string? id { get; set; }
///
/// </summary>
public string id { get; set; }
/// <summary> public int? alterId { get; set; }
///
/// </summary>
public int alterId { get; set; }
/// <summary> public string? email { get; set; }
///
/// </summary>
public string email { get; set; }
/// <summary> public string? security { get; set; }
///
/// </summary>
public string security { get; set; }
/// <summary> public string? encryption { get; set; }
/// VLESS
/// </summary>
public string encryption { get; set; }
/// <summary>
/// VLESS
/// </summary>
public string? flow { get; set; } public string? flow { get; set; }
} }
@@ -201,57 +109,27 @@ namespace ServiceLib.Models
public class Outbounds4Ray public class Outbounds4Ray
{ {
/// <summary>
/// 默认值agentout
/// </summary>
public string tag { get; set; } public string tag { get; set; }
/// <summary>
///
/// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary>
///
/// </summary>
public Outboundsettings4Ray settings { get; set; } public Outboundsettings4Ray settings { get; set; }
/// <summary>
///
/// </summary>
public StreamSettings4Ray streamSettings { get; set; } public StreamSettings4Ray streamSettings { get; set; }
/// <summary>
///
/// </summary>
public Mux4Ray mux { get; set; } public Mux4Ray mux { get; set; }
} }
public class Outboundsettings4Ray public class Outboundsettings4Ray
{ {
/// <summary>
///
/// </summary>
public List<VnextItem4Ray>? vnext { get; set; } public List<VnextItem4Ray>? vnext { get; set; }
/// <summary> public List<ServersItem4Ray>? servers { get; set; }
///
/// </summary>
public List<ServersItem4Ray> servers { get; set; }
/// <summary> public Response4Ray? response { get; set; }
///
/// </summary>
public Response4Ray response { get; set; }
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public int? userLevel { get; set; } public int? userLevel { get; set; }
public FragmentItem4Ray? fragment { get; set; } public FragmentItem4Ray? fragment { get; set; }
@@ -259,85 +137,40 @@ namespace ServiceLib.Models
public class VnextItem4Ray public class VnextItem4Ray
{ {
/// <summary>
///
/// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public List<UsersItem4Ray> users { get; set; } public List<UsersItem4Ray> users { get; set; }
} }
public class ServersItem4Ray public class ServersItem4Ray
{ {
/// <summary>
///
/// </summary>
public string email { get; set; } public string email { get; set; }
/// <summary>
///
/// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary>
///
/// </summary>
public string? method { get; set; } public string? method { get; set; }
/// <summary>
///
/// </summary>
public bool? ota { get; set; } public bool? ota { get; set; }
/// <summary>
///
/// </summary>
public string? password { get; set; } public string? password { get; set; }
/// <summary>
///
/// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; } public int? level { get; set; }
/// <summary>
/// trojan
/// </summary>
public string flow { get; set; } public string flow { get; set; }
/// <summary>
///
/// </summary>
public List<SocksUsersItem4Ray> users { get; set; } public List<SocksUsersItem4Ray> users { get; set; }
} }
public class SocksUsersItem4Ray public class SocksUsersItem4Ray
{ {
/// <summary>
///
/// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; } public string pass { get; set; }
/// <summary>
///
/// </summary>
public int? level { get; set; } public int? level { get; set; }
} }
@@ -351,17 +184,11 @@ namespace ServiceLib.Models
public class Response4Ray public class Response4Ray
{ {
/// <summary>
///
/// </summary>
public string type { get; set; } public string type { get; set; }
} }
public class Dns4Ray public class Dns4Ray
{ {
/// <summary>
///
/// </summary>
public List<string> servers { get; set; } public List<string> servers { get; set; }
} }
@@ -373,19 +200,10 @@ namespace ServiceLib.Models
public class Routing4Ray public class Routing4Ray
{ {
/// <summary>
///
/// </summary>
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
/// <summary>
///
/// </summary>
public string? domainMatcher { get; set; } public string? domainMatcher { get; set; }
/// <summary>
///
/// </summary>
public List<RulesItem4Ray> rules { get; set; } public List<RulesItem4Ray> rules { get; set; }
public List<BalancersItem4Ray>? balancers { get; set; } public List<BalancersItem4Ray>? balancers { get; set; }
@@ -426,87 +244,39 @@ namespace ServiceLib.Models
public class StreamSettings4Ray public class StreamSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string network { get; set; } public string network { get; set; }
/// <summary>
///
/// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary>
///
/// </summary>
public TlsSettings4Ray? tlsSettings { get; set; } public TlsSettings4Ray? tlsSettings { get; set; }
/// <summary>
/// Tcp传输额外设置
/// </summary>
public TcpSettings4Ray? tcpSettings { get; set; } public TcpSettings4Ray? tcpSettings { get; set; }
/// <summary>
/// Kcp传输额外设置
/// </summary>
public KcpSettings4Ray? kcpSettings { get; set; } public KcpSettings4Ray? kcpSettings { get; set; }
/// <summary>
/// ws传输额外设置
/// </summary>
public WsSettings4Ray? wsSettings { get; set; } public WsSettings4Ray? wsSettings { get; set; }
/// <summary>
///
/// </summary>
public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; } public HttpupgradeSettings4Ray? httpupgradeSettings { get; set; }
/// <summary> public XhttpSettings4Ray? xhttpSettings { get; set; }
///
/// </summary>
public SplithttpSettings4Ray? splithttpSettings { get; set; }
/// <summary>
/// h2传输额外设置
/// </summary>
public HttpSettings4Ray? httpSettings { get; set; } public HttpSettings4Ray? httpSettings { get; set; }
/// <summary>
/// QUIC
/// </summary>
public QuicSettings4Ray? quicSettings { get; set; } public QuicSettings4Ray? quicSettings { get; set; }
/// <summary>
/// VLESS only
/// </summary>
public TlsSettings4Ray? realitySettings { get; set; } public TlsSettings4Ray? realitySettings { get; set; }
/// <summary>
/// grpc
/// </summary>
public GrpcSettings4Ray? grpcSettings { get; set; } public GrpcSettings4Ray? grpcSettings { get; set; }
/// <summary>
/// sockopt
/// </summary>
public Sockopt4Ray? sockopt { get; set; } public Sockopt4Ray? sockopt { get; set; }
} }
public class TlsSettings4Ray public class TlsSettings4Ray
{ {
/// <summary>
/// 是否允许不安全连接(用于客户端)
/// </summary>
public bool? allowInsecure { get; set; } public bool? allowInsecure { get; set; }
/// <summary>
///
/// </summary>
public string? serverName { get; set; } public string? serverName { get; set; }
/// <summary>
///
/// </summary>
public List<string>? alpn { get; set; } public List<string>? alpn { get; set; }
public string? fingerprint { get; set; } public string? fingerprint { get; set; }
@@ -519,157 +289,94 @@ namespace ServiceLib.Models
public class TcpSettings4Ray public class TcpSettings4Ray
{ {
/// <summary>
/// 数据包头部伪装设置
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
} }
public class Header4Ray public class Header4Ray
{ {
/// <summary>
/// 伪装
/// </summary>
public string type { get; set; } public string type { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object request { get; set; } public object request { get; set; }
/// <summary>
/// 结构复杂,直接存起来
/// </summary>
public object response { get; set; } public object response { get; set; }
} }
public class KcpSettings4Ray public class KcpSettings4Ray
{ {
/// <summary>
///
/// </summary>
public int mtu { get; set; } public int mtu { get; set; }
/// <summary>
///
/// </summary>
public int tti { get; set; } public int tti { get; set; }
/// <summary>
///
/// </summary>
public int uplinkCapacity { get; set; } public int uplinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public int downlinkCapacity { get; set; } public int downlinkCapacity { get; set; }
/// <summary>
///
/// </summary>
public bool congestion { get; set; } public bool congestion { get; set; }
/// <summary>
///
/// </summary>
public int readBufferSize { get; set; } public int readBufferSize { get; set; }
/// <summary>
///
/// </summary>
public int writeBufferSize { get; set; } public int writeBufferSize { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
/// <summary>
///
/// </summary>
public string seed { get; set; } public string seed { get; set; }
} }
public class WsSettings4Ray public class WsSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string path { get; set; } public string path { get; set; }
/// <summary>
///
/// </summary>
public Headers4Ray headers { get; set; } public Headers4Ray headers { get; set; }
} }
public class Headers4Ray public class Headers4Ray
{ {
/// <summary>
///
/// </summary>
public string Host { get; set; } public string Host { get; set; }
/// <summary>
/// 用户代理
/// </summary>
[JsonPropertyName("User-Agent")] [JsonPropertyName("User-Agent")]
public string UserAgent { get; set; } public string UserAgent { get; set; }
} }
public class HttpupgradeSettings4Ray public class HttpupgradeSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string? path { get; set; } public string? path { get; set; }
/// <summary>
///
/// </summary>
public string? host { get; set; } public string? host { get; set; }
} }
public class SplithttpSettings4Ray public class XhttpSettings4Ray
{ {
public string? path { get; set; } public string? path { get; set; }
public string? host { get; set; } public string? host { get; set; }
public string? mode { get; set; }
public string? scMaxEachPostBytes { get; set; }
public string? scMaxConcurrentPosts { get; set; }
public string? scMinPostsIntervalMs { get; set; }
public Xmux4Ray? xmux { get; set; }
public object? extra { get; set; }
}
public int? maxUploadSize { get; set; } public class Xmux4Ray
{
public int? maxConcurrentUploads { get; set; } public int? maxConcurrency { get; set; }
public int? maxConnections { get; set; }
public int? cMaxReuseTimes { get; set; }
public int? cMaxLifetimeMs { get; set; }
} }
public class HttpSettings4Ray public class HttpSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string? path { get; set; } public string? path { get; set; }
/// <summary>
///
/// </summary>
public List<string>? host { get; set; } public List<string>? host { get; set; }
} }
public class QuicSettings4Ray public class QuicSettings4Ray
{ {
/// <summary>
///
/// </summary>
public string security { get; set; } public string security { get; set; }
/// <summary>
///
/// </summary>
public string key { get; set; } public string key { get; set; }
/// <summary>
///
/// </summary>
public Header4Ray header { get; set; } public Header4Ray header { get; set; }
} }
@@ -686,14 +393,8 @@ namespace ServiceLib.Models
public class AccountsItem4Ray public class AccountsItem4Ray
{ {
/// <summary>
///
/// </summary>
public string user { get; set; } public string user { get; set; }
/// <summary>
///
/// </summary>
public string pass { get; set; } public string pass { get; set; }
} }

View File

@@ -0,0 +1,20 @@
using System.Collections;
namespace ServiceLib.Models
{
internal class V2rayMetricsVars
{
public V2rayMetricsVarsStats? stats { get; set; }
}
}
public class V2rayMetricsVarsStats
{
public Hashtable? outbound { get; set; }
}
public class V2rayMetricsVarsLink
{
public long downlink { get; set; }
public long uplink { get; set; }
}

View File

@@ -1365,24 +1365,6 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Basic Function 的本地化字符串。
/// </summary>
public static string menuRoutingBasic {
get {
return ResourceManager.GetString("menuRoutingBasic", resourceCulture);
}
}
/// <summary>
/// 查找类似 Import Basic Rules 的本地化字符串。
/// </summary>
public static string menuRoutingBasicImportRules {
get {
return ResourceManager.GetString("menuRoutingBasicImportRules", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。 /// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。
/// </summary> /// </summary>
@@ -3103,6 +3085,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 HTTP Port 的本地化字符串。 /// 查找类似 HTTP Port 的本地化字符串。
/// </summary> /// </summary>
@@ -3148,6 +3139,42 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Linux system sudo password 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPassword {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPassword", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please set the sudo password in Tun mode settings first 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordIsEmpty {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordIsEmpty", resourceCulture);
}
}
/// <summary>
/// 查找类似 Please do not run this app with sudo 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordNotSudoRunApp {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordNotSudoRunApp", resourceCulture);
}
}
/// <summary>
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
/// </summary>
public static string TbSettingsLinuxSudoPasswordTip {
get {
return ResourceManager.GetString("TbSettingsLinuxSudoPasswordTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Enable Log 的本地化字符串。 /// 查找类似 Enable Log 的本地化字符串。
/// </summary> /// </summary>
@@ -3599,7 +3626,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 The ping of current service: {0} ms 的本地化字符串。 /// 查找类似 The delay : {0} ms, {1} 的本地化字符串。
/// </summary> /// </summary>
public static string TestMeOutput { public static string TestMeOutput {
get { get {
@@ -3661,6 +3688,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 XHTTP Extra raw JSON, format: { XHTTPObject } 的本地化字符串。
/// </summary>
public static string TransportExtraTip {
get {
return ResourceManager.GetString("TransportExtraTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 *tcp camouflage type 的本地化字符串。 /// 查找类似 *tcp camouflage type 的本地化字符串。
/// </summary> /// </summary>
@@ -3698,7 +3734,16 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *ws/httpupgrade/splithttp path 的本地化字符串。 /// 查找类似 *xhttp mode 的本地化字符串。
/// </summary>
public static string TransportHeaderTypeTip5 {
get {
return ResourceManager.GetString("TransportHeaderTypeTip5", resourceCulture);
}
}
/// <summary>
/// 查找类似 *ws/httpupgrade/xhttp path 的本地化字符串。
/// </summary> /// </summary>
public static string TransportPathTip1 { public static string TransportPathTip1 {
get { get {
@@ -3752,7 +3797,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 *ws/httpupgrade/splithttp host 的本地化字符串。 /// 查找类似 *ws/httpupgrade/xhttp host 的本地化字符串。
/// </summary> /// </summary>
public static string TransportRequestHostTip2 { public static string TransportRequestHostTip2 {
get { get {

View File

@@ -302,7 +302,7 @@
<value>اسکن URL وارد کردن با موفقیت</value> <value>اسکن URL وارد کردن با موفقیت</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>پینگ سرویس فعلی: {0} ms</value> <value>پینگ سرویس فعلی: {0} ms, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>موفقیت عملیات</value> <value>موفقیت عملیات</value>
@@ -847,12 +847,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule</value> <value>Set as active rule</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>عملکرد پایه</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>واردات قوانین اساسی</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>تطبیق دامنه</value> <value>تطبیق دامنه</value>
</data> </data>
@@ -1033,4 +1027,361 @@
<data name="menuProxiesSelectActivity" xml:space="preserve"> <data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value> <value>Select active node (Enter)</value>
</data> </data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>Multi-Server lowest latency</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>Auto column width adjustment</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>Export Base64-encoded Share Links to Clipboard</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo files source (optional)</value>
</data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset files source (optional)</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>Routing rules source (optional)</value>
</data>
<data name="menuRegionalPresets" xml:space="preserve">
<value>Regional presets setting</value>
</data>
<data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>Russia</value>
</data>
<data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Users in China region can ignore this item</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>Invalid address (Url)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>Please do not use the insecure HTTP protocol subscription address</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsLogEnabledToFile" xml:space="preserve">
<value>Enable logging to file</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="menuRebootAsAdmin" xml:space="preserve">
<value>Restart as Administrator</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvAutoUpdateInterval" xml:space="preserve">
<value>Automatic update interval (minutes)</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="menuDNSSetting" xml:space="preserve">
<value>DNS Settings</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbSettingsCoreDnsSingbox" xml:space="preserve">
<value>sing-box DNS settings</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="menuMoveToGroup" xml:space="preserve">
<value>Move to group</value>
</data>
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
<value>Enable Server Drag Drop Sort(Require restart)</value>
</data>
<data name="TbAutoRefresh" xml:space="preserve">
<value>AutoRefresh</value>
</data>
<data name="SpeedtestingSkip" xml:space="preserve">
<value>Skip test</value>
</data>
<data name="menuEditServer" xml:space="preserve">
<value>Edit Server (Ctrl+D)</value>
</data>
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
<value>Double-click server make active</value>
</data>
<data name="SpeedtestingCompleted" xml:space="preserve">
<value>Test completed</value>
</data>
<data name="TbSettingsDefFingerprint" xml:space="preserve">
<value>Default TLS fingerprint</value>
</data>
<data name="TbSettingsCurrentFontFamily" xml:space="preserve">
<value>FontFamily(Require restart)</value>
</data>
<data name="TbSettingsCurrentFontFamilyTip" xml:space="preserve">
<value>Copy the font TTF/TTC file to the directory guiFonts, restart the settings</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>Set this with admin privileges, get admin privileges after startup</value>
</data>
<data name="TbSettingsFontSize" xml:space="preserve">
<value>Font Size</value>
</data>
<data name="TbSettingsSpeedTestTimeout" xml:space="preserve">
<value>SpeedTest Single Timeout Value</value>
</data>
<data name="TbSettingsSpeedTestUrl" xml:space="preserve">
<value>SpeedTest URL</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="TbSettingsFollowSystemTheme" xml:space="preserve">
<value>Follow System Theme</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] server</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root> </root>

View File

@@ -302,7 +302,7 @@
<value>Scan import the shared link successfully</value> <value>Scan import the shared link successfully</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</value> <value>The delay : {0} ms, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>Operation success</value> <value>Operation success</value>
@@ -344,7 +344,7 @@
<value>Please fill in the correct custom DNS</value> <value>Please fill in the correct custom DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host Separated by commas (,)</value> <value>*http host Separated by commas (,)</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host Separated by commas (,)</value> <value>*h2 host Separated by commas (,)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule(Enter)</value> <value>Set as active rule(Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>Basic Function</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>Import Basic Rules</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>Domain Matcher</value> <value>Domain Matcher</value>
</data> </data>
@@ -1369,4 +1363,25 @@
<data name="LvMemo" xml:space="preserve"> <data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value> <value>Remarks Memo</value>
</data> </data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root> </root>

View File

@@ -302,7 +302,7 @@
<value>Сканирование URL-адреса импорта успешна.</value> <value>Сканирование URL-адреса импорта успешна.</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>Задержка текущего сервера: {0} мс</value> <value>Задержка текущего сервера: {0} мс, {1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>Операция успешна</value> <value>Операция успешна</value>
@@ -856,12 +856,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value> <value>Установить как активное правило</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>Основные функции</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>Импорт основных правил</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>Сопоставитель доменов</value> <value>Сопоставитель доменов</value>
</data> </data>
@@ -1046,6 +1040,348 @@
<value>Россия</value> <value>Россия</value>
</data> </data>
<data name="TbSettingsChinaUserTip" xml:space="preserve"> <data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>Используйте Настройки -> Региональные пресеты вместо изменения этого поля</value> <value>Используйте Настройки -&gt; Региональные пресеты вместо изменения этого поля</value>
</data>
<data name="LvMemo" xml:space="preserve">
<value>Remarks Memo</value>
</data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>Speed Ping Test URL</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>Part Node Latency Test</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>Refresh Proxies</value>
</data>
<data name="TbAutoScrollToEnd" xml:space="preserve">
<value>Auto ScrollToEnd</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>Select active node (Enter)</value>
</data>
<data name="TbRuleMatchingTips" xml:space="preserve">
<value>(Domain or IP or ProcName) and Port and Protocol and InboundTag =&gt; OutboundTag</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>obfs password</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>Multi-Server lowest latency</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>Main layout orientation(Require restart)</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>Multi-server load balancing</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>Latency Test</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>Add [WireGuard] server</value>
</data>
<data name="menuProfileAutofitColumnWidth" xml:space="preserve">
<value>Auto column width adjustment</value>
</data>
<data name="menuExport2ShareUrlBase64" xml:space="preserve">
<value>Export Base64-encoded Share Links to Clipboard</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>Delay</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>Enable additional Inbound</value>
</data>
<data name="LvPrevProfileTip" xml:space="preserve">
<value>Please make sure the remarks exists and is unique</value>
</data>
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
<value>Export selected server for complete configuration to clipboard</value>
</data>
<data name="LvNextProfile" xml:space="preserve">
<value>Next proxy remarks</value>
</data>
<data name="menuShowOrHideMainWindow" xml:space="preserve">
<value>Show or hide the main window</value>
</data>
<data name="LvPrevProfile" xml:space="preserve">
<value>Previous proxy remarks</value>
</data>
<data name="TbHeaderType8" xml:space="preserve">
<value>Congestion control</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound DNS address</value>
</data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>Updating subscription, only determine remarks exists</value>
</data>
<data name="SpeedtestingStop" xml:space="preserve">
<value>Test terminating...</value>
</data>
<data name="TransportRequestHostTip5" xml:space="preserve">
<value>*grpc Authority</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>Default</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>Chain</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>Sorting</value>
</data>
<data name="menuOpenTheFileLocation" xml:space="preserve">
<value>Open the storage location</value>
</data>
<data name="NeedRebootTips" xml:space="preserve">
<value>Successful operation. Click the settings menu to reboot the app.</value>
</data>
<data name="LvCustomRulesetPath4Singbox" xml:space="preserve">
<value>Custom the rule-set of sing-box</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>Download Traffic</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>Host</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>Name</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>Network</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>Time</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>Type</value>
</data>
<data name="TbSettingsEnableCacheFile4Sbox" xml:space="preserve">
<value>Enable cache file for sing-box (ruleset files)</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>Upload Speed</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>Upload Traffic</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>Connections</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>Close Connection</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>Close All Connection</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>Proxies</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>Rule mode</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>Direct</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>Global</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>Do not change</value>
</data>
<data name="TbSettingsEnableFragment" xml:space="preserve">
<value>Enable fragment</value>
</data>
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>Rule</value>
</data>
<data name="menuAddHttpServer" xml:space="preserve">
<value>Add [HTTP] server</value>
</data>
<data name="menuAddTuicServer" xml:space="preserve">
<value>Add [TUIC] server</value>
</data>
<data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it!</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>Enable IPv6 Address</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>Custom config socks port</value>
</data>
<data name="LvWebDavCheck" xml:space="preserve">
<value>WebDav Check</value>
</data>
<data name="TbRoutingRuleDomain" xml:space="preserve">
<value>Domain</value>
</data>
<data name="TbRoutingRuleIP" xml:space="preserve">
<value>IP or IP CIDR</value>
</data>
<data name="TbRoutingRuleProcess" xml:space="preserve">
<value>Full process name (Tun mode)</value>
</data>
<data name="TbSettingsMux4SboxProtocol" xml:space="preserve">
<value>sing-box Mux Protocol</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="TbdomainStrategy4Singbox" xml:space="preserve">
<value>sing-box domain strategy</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
<data name="TbSettingDnsImportDefConfig" xml:space="preserve">
<value>Click to import default DNS config</value>
</data>
<data name="TipActiveServer" xml:space="preserve">
<value>Active</value>
</data>
<data name="TbDnsSingboxObjectDoc" xml:space="preserve">
<value>Please fill in DNS Structure, Click to view the document</value>
</data>
<data name="LvConvertTargetTip" xml:space="preserve">
<value>Please leave blank if no conversion is required</value>
</data>
<data name="LvConvertTarget" xml:space="preserve">
<value>Convert target type</value>
</data>
<data name="menuStorageUI" xml:space="preserve">
<value>Save Interface Layout</value>
</data>
<data name="SpeedDisplayText" xml:space="preserve">
<value>{0} : {1}/s↑ | {2}/s↓</value>
</data>
<data name="LvMoreUrl" xml:space="preserve">
<value>More URLs, separated by commas; Subscription conversion will be invalid</value>
</data>
<data name="MsgSkipSubscriptionUpdate" xml:space="preserve">
<value>Updates are not enabled, skip this subscription</value>
</data>
<data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>UpgradeApp does not exist</value>
</data>
<data name="menuAddServerViaImage" xml:space="preserve">
<value>Scan QR code in the image</value>
</data>
<data name="TipDisplayLog" xml:space="preserve">
<value>Please turn off when there is an abnormal disconnection</value>
</data>
<data name="SpeedtestingWait" xml:space="preserve">
<value>Waiting for testing (press ESC to terminate)...</value>
</data>
<data name="TbSpiderX" xml:space="preserve">
<value>SpiderX</value>
</data>
<data name="TbShortId" xml:space="preserve">
<value>ShortId</value>
</data>
<data name="InvalidUrlTip" xml:space="preserve">
<value>Invalid address (Url)</value>
</data>
<data name="InsecureUrlProtocol" xml:space="preserve">
<value>Please do not use the insecure HTTP protocol subscription address</value>
</data>
<data name="TbPublicKey" xml:space="preserve">
<value>PublicKey</value>
</data>
<data name="menuMoveTo" xml:space="preserve">
<value>Move up and down</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6;</value>
</data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>Install the font to the system and restart the settings</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>Add [Hysteria2] server</value>
</data>
<data name="LvWebDavPassword" xml:space="preserve">
<value>WebDav Password</value>
</data>
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>Download Speed</value>
</data>
<data name="menuRemoteRestore" xml:space="preserve">
<value>Restore from remote (WebDAV)</value>
</data>
<data name="menuRemoteBackup" xml:space="preserve">
<value>Backup to remote (WebDAV)</value>
</data>
<data name="LvWebDavUserName" xml:space="preserve">
<value>WebDav User Name</value>
</data>
<data name="menuLocalRestore" xml:space="preserve">
<value>Restore from local</value>
</data>
<data name="menuLocalBackup" xml:space="preserve">
<value>Backup to local</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>Use System Hosts</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>Backup and Restore</value>
</data>
<data name="menuLocalBackupAndRestore" xml:space="preserve">
<value>Local</value>
</data>
<data name="menuExitTips" xml:space="preserve">
<value>Are you sure to exit?</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria Max bandwidth (Up/Dw)</value>
</data>
<data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav Url</value>
</data>
<data name="menuRemoteBackupAndRestore" xml:space="preserve">
<value>Remote (WebDAV)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux system sudo password</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>The password is encrypted and stored only in local files.</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>Please set the sudo password in Tun mode settings first</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>Please do not run this app with sudo</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp mode</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data> </data>
</root> </root>

View File

@@ -302,7 +302,7 @@
<value>扫描导入分享链接成功</value> <value>扫描导入分享链接成功</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>当前服务的真连接延迟: {0} ms</value> <value>当前延迟: {0} ms{1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value> <value>操作成功</value>
@@ -344,7 +344,7 @@
<value>请填写正确的自定义DNS</value> <value>请填写正确的自定义DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -359,7 +359,7 @@
<value>*http host中间逗号(,)分隔</value> <value>*http host中间逗号(,)分隔</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中间逗号(,)分隔</value> <value>*h2 host中间逗号(,)分隔</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value> <value>设为活动规则 (Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>基础功能</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>一键导入基础规则</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配算法</value> <value>域名匹配算法</value>
</data> </data>
@@ -1271,7 +1265,7 @@
<value>显示或隐藏主界面</value> <value>显示或隐藏主界面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve"> <data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value> <value>您当前运行的是独立包,请手动下载 SelfContained.7z文件解压覆盖</value>
</data> </data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自定义配置的Socks端口</value> <value>自定义配置的Socks端口</value>
@@ -1366,4 +1360,25 @@
<data name="LvMemo" xml:space="preserve"> <data name="LvMemo" xml:space="preserve">
<value>备注备忘</value> <value>备注备忘</value>
</data> </data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>请不要用sudo运行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value>
</data>
</root> </root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value> <value>設定格式不正確</value>
</data> </data>
<data name="CustomServerTips" xml:space="preserve"> <data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value> <value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data> </data>
<data name="Downloading" xml:space="preserve"> <data name="Downloading" xml:space="preserve">
<value>下載開始...</value> <value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value> <value>請填寫正確格式伺服器埠</value>
</data> </data>
<data name="FillLocalListeningPort" xml:space="preserve"> <data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value> <value>請填寫本機聽埠</value>
</data> </data>
<data name="FillPassword" xml:space="preserve"> <data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value> <value>請填寫密碼</value>
@@ -301,7 +301,7 @@
<value>掃描匯入分享链接成功</value> <value>掃描匯入分享链接成功</value>
</data> </data>
<data name="TestMeOutput" xml:space="preserve"> <data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連接延遲: {0} ms</value> <value>目前延遲: {0} ms{1}</value>
</data> </data>
<data name="OperationSuccess" xml:space="preserve"> <data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value> <value>操作成功</value>
@@ -343,7 +343,7 @@
<value>請填寫正確的自訂DNS</value> <value>請填寫正確的自訂DNS</value>
</data> </data>
<data name="TransportPathTip1" xml:space="preserve"> <data name="TransportPathTip1" xml:space="preserve">
<value>*ws/httpupgrade/splithttp path</value> <value>*ws/httpupgrade/xhttp path</value>
</data> </data>
<data name="TransportPathTip2" xml:space="preserve"> <data name="TransportPathTip2" xml:space="preserve">
<value>*h2 path</value> <value>*h2 path</value>
@@ -358,7 +358,7 @@
<value>*http host中間逗號(,)分隔</value> <value>*http host中間逗號(,)分隔</value>
</data> </data>
<data name="TransportRequestHostTip2" xml:space="preserve"> <data name="TransportRequestHostTip2" xml:space="preserve">
<value>*ws/httpupgrade/splithttp host</value> <value>*ws/httpupgrade/xhttp host</value>
</data> </data>
<data name="TransportRequestHostTip3" xml:space="preserve"> <data name="TransportRequestHostTip3" xml:space="preserve">
<value>*h2 host中間逗號(,)分隔</value> <value>*h2 host中間逗號(,)分隔</value>
@@ -511,7 +511,7 @@
<value>清除所有服務統計資料</value> <value>清除所有服務統計資料</value>
</data> </data>
<data name="menuRealPingServer" xml:space="preserve"> <data name="menuRealPingServer" xml:space="preserve">
<value>測試伺服器真連延遲(多選) (Ctrl+R)</value> <value>測試伺服器真連延遲(多選) (Ctrl+R)</value>
</data> </data>
<data name="menuSortServerResult" xml:space="preserve"> <data name="menuSortServerResult" xml:space="preserve">
<value>按測試結果排序</value> <value>按測試結果排序</value>
@@ -683,7 +683,7 @@
<value>進階代理設定, 協定選擇(可選)</value> <value>進階代理設定, 協定選擇(可選)</value>
</data> </data>
<data name="TbSettingsAllowLAN" xml:space="preserve"> <data name="TbSettingsAllowLAN" xml:space="preserve">
<value>允許來自區域網路的連</value> <value>允許來自區域網路的連</value>
</data> </data>
<data name="TbSettingsAutoHideStartup" xml:space="preserve"> <data name="TbSettingsAutoHideStartup" xml:space="preserve">
<value>啟動後隱藏視窗</value> <value>啟動後隱藏視窗</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value> <value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data> </data>
<data name="TbSettingsHttpPort" xml:space="preserve"> <data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value> <value>本機HTTP聽埠</value>
</data> </data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve"> <data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value> <value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value> <value>開啟流量探測</value>
</data> </data>
<data name="TbSettingsSocksPort" xml:space="preserve"> <data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS聽埠</value> <value>本機SOCKS聽埠</value>
</data> </data>
<data name="TbSettingsStartBoot" xml:space="preserve"> <data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value> <value>開機啟動(可能會不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve"> <data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value> <value>設為活動規則 (Enter)</value>
</data> </data>
<data name="menuRoutingBasic" xml:space="preserve">
<value>基礎功能</value>
</data>
<data name="menuRoutingBasicImportRules" xml:space="preserve">
<value>一鍵匯入基礎規則</value>
</data>
<data name="TbdomainMatcher" xml:space="preserve"> <data name="TbdomainMatcher" xml:space="preserve">
<value>域名匹配演算法</value> <value>域名匹配演算法</value>
</data> </data>
@@ -998,7 +992,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value> <value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data> </data>
<data name="TbSettingsSocksPortTip" xml:space="preserve"> <data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value> <value>http連接埠= +1Pac連接埠= +4*ray API連接埠= +5mihomo API連接埠= +6</value>
</data> </data>
<data name="TbSettingsStartBootTip" xml:space="preserve"> <data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value> <value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1088,7 @@
<value>請確保別名存在並且唯一</value> <value>請確保別名存在並且唯一</value>
</data> </data>
<data name="TbSettingsEnableExInbound" xml:space="preserve"> <data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value> <value>啟用額外偵聽連接埠</value>
</data> </data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve"> <data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value> <value>啟用IPv6</value>
@@ -1106,7 +1100,7 @@
<value>自动滚动到末尾</value> <value>自动滚动到末尾</value>
</data> </data>
<data name="TbSettingsSpeedPingTestUrl" xml:space="preserve"> <data name="TbSettingsSpeedPingTestUrl" xml:space="preserve">
<value>真連測試址</value> <value>真連測試址</value>
</data> </data>
<data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve"> <data name="TbSettingsEnableUpdateSubOnlyRemarksExist" xml:space="preserve">
<value>更新訂閱時只判斷別名是否存在</value> <value>更新訂閱時只判斷別名是否存在</value>
@@ -1151,10 +1145,10 @@
<value>顯示或隱藏主介面</value> <value>顯示或隱藏主介面</value>
</data> </data>
<data name="UpdateStandalonePackageTip" xml:space="preserve"> <data name="UpdateStandalonePackageTip" xml:space="preserve">
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value> <value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋</value>
</data> </data>
<data name="TbPreSocksPort4Sub" xml:space="preserve"> <data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value> <value>自訂設定的Socks連接埠</value>
</data> </data>
<data name="menuBackupAndRestore" xml:space="preserve"> <data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value> <value>備份和還原</value>
@@ -1187,7 +1181,7 @@
<value>WebDav 密碼</value> <value>WebDav 密碼</value>
</data> </data>
<data name="LvWebDavUrl" xml:space="preserve"> <data name="LvWebDavUrl" xml:space="preserve">
<value>WebDav 伺服器址</value> <value>WebDav 伺服器址</value>
</data> </data>
<data name="LvWebDavDirName" xml:space="preserve"> <data name="LvWebDavDirName" xml:space="preserve">
<value>遠端資料夾名稱(可選)</value> <value>遠端資料夾名稱(可選)</value>
@@ -1205,25 +1199,25 @@
<value>儲存介面佈局</value> <value>儲存介面佈局</value>
</data> </data>
<data name="TbSettingsGeoFilesSource" xml:space="preserve"> <data name="TbSettingsGeoFilesSource" xml:space="preserve">
<value>Geo文件來源(可選)</value> <value>Geo檔案來源(可選)</value>
</data> </data>
<data name="UpgradeAppNotExistTip" xml:space="preserve"> <data name="UpgradeAppNotExistTip" xml:space="preserve">
<value>升工具App不存在</value> <value>升工具App不存在</value>
</data> </data>
<data name="TbSettingsSrsFilesSource" xml:space="preserve"> <data name="TbSettingsSrsFilesSource" xml:space="preserve">
<value>sing-box ruleset文件來源(可選)</value> <value>sing-box ruleset檔案來源(可選)</value>
</data> </data>
<data name="TbSettingsRoutingRulesSource" xml:space="preserve"> <data name="TbSettingsRoutingRulesSource" xml:space="preserve">
<value>路由规则集来源(可)</value> <value>路由規則集來源(可)</value>
</data> </data>
<data name="TbSettingsChinaUserTip" xml:space="preserve"> <data name="TbSettingsChinaUserTip" xml:space="preserve">
<value>中国区域用可忽略此</value> <value>中國區域用可忽略此</value>
</data> </data>
<data name="menuRegionalPresets" xml:space="preserve"> <data name="menuRegionalPresets" xml:space="preserve">
<value>区域预置设置</value> <value>區域預置設定</value>
</data> </data>
<data name="menuRegionalPresetsDefault" xml:space="preserve"> <data name="menuRegionalPresetsDefault" xml:space="preserve">
<value>默认区域</value> <value>預設區域</value>
</data> </data>
<data name="menuRegionalPresetsRussia" xml:space="preserve"> <data name="menuRegionalPresetsRussia" xml:space="preserve">
<value>俄羅斯</value> <value>俄羅斯</value>
@@ -1232,13 +1226,13 @@
<value>掃描圖片中的二維碼</value> <value>掃描圖片中的二維碼</value>
</data> </data>
<data name="InvalidUrlTip" xml:space="preserve"> <data name="InvalidUrlTip" xml:space="preserve">
<value>址(Url)無效</value> <value>址(Url)無效</value>
</data> </data>
<data name="InsecureUrlProtocol" xml:space="preserve"> <data name="InsecureUrlProtocol" xml:space="preserve">
<value>請不要使用不安全的HTTP協定訂閱位址</value> <value>請不要使用不安全的HTTP協定訂閱位址</value>
</data> </data>
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve"> <data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
<value>安裝字到系統中,重新啟動設定</value> <value>安裝字到系統中,重新啟動設定</value>
</data> </data>
<data name="menuExitTips" xml:space="preserve"> <data name="menuExitTips" xml:space="preserve">
<value>是否確定退出?</value> <value>是否確定退出?</value>
@@ -1246,4 +1240,145 @@
<data name="LvMemo" xml:space="preserve"> <data name="LvMemo" xml:space="preserve">
<value>備註備忘</value> <value>備註備忘</value>
</data> </data>
<data name="TbHeaderType8" xml:space="preserve">
<value>擁塞控制算法</value>
</data>
<data name="menuProxiesSelectActivity" xml:space="preserve">
<value>設為活動節點 (Enter)</value>
</data>
<data name="menuProxiesReload" xml:space="preserve">
<value>重新整理</value>
</data>
<data name="TbSorting" xml:space="preserve">
<value>排序</value>
</data>
<data name="menuProxiesDelaytest" xml:space="preserve">
<value>延遲測試</value>
</data>
<data name="menuModeRule" xml:space="preserve">
<value>規則</value>
</data>
<data name="menuModeNothing" xml:space="preserve">
<value>随原配置</value>
</data>
<data name="menuModeGlobal" xml:space="preserve">
<value>全局</value>
</data>
<data name="menuModeDirect" xml:space="preserve">
<value>直連</value>
</data>
<data name="menuRulemode" xml:space="preserve">
<value>規則模式</value>
</data>
<data name="TbProxies" xml:space="preserve">
<value>目前代理</value>
</data>
<data name="menuConnectionCloseAll" xml:space="preserve">
<value>關閉所有連線</value>
</data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Outbound預設解析策略</value>
</data>
<data name="menuConnectionClose" xml:space="preserve">
<value>關閉連線</value>
</data>
<data name="TbSortingUpTraffic" xml:space="preserve">
<value>上傳流量</value>
</data>
<data name="TbSortingUpSpeed" xml:space="preserve">
<value>上傳速度</value>
</data>
<data name="TbSortingType" xml:space="preserve">
<value>類型</value>
</data>
<data name="TbSortingTime" xml:space="preserve">
<value>時間</value>
</data>
<data name="TbSortingNetwork" xml:space="preserve">
<value>網路</value>
</data>
<data name="TbSortingName" xml:space="preserve">
<value>名稱</value>
</data>
<data name="TbSortingHost" xml:space="preserve">
<value>主機</value>
</data>
<data name="TbSortingDownTraffic" xml:space="preserve">
<value>下載流量</value>
</data>
<data name="TbSortingDownSpeed" xml:space="preserve">
<value>下載速度</value>
</data>
<data name="TbSortingDelay" xml:space="preserve">
<value>延遲</value>
</data>
<data name="TbSortingDefault" xml:space="preserve">
<value>預設</value>
</data>
<data name="TbConnections" xml:space="preserve">
<value>目前連線</value>
</data>
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
<value>多伺服器最低延遲 (多選)</value>
</data>
<data name="menuProxiesDelaytestPart" xml:space="preserve">
<value>目前部分節點延遲測試</value>
</data>
<data name="menuSetDefaultLoadBalanceServer" xml:space="preserve">
<value>多伺服器負載平衡 (多選)</value>
</data>
<data name="menuAddHysteria2Server" xml:space="preserve">
<value>添加[Hysteria2]伺服器</value>
</data>
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
<value>Hysteria 最大頻寬(Up/Dw)</value>
</data>
<data name="TbSettingsMainGirdOrientation" xml:space="preserve">
<value>主界面佈局方向(需重啟)</value>
</data>
<data name="menuAddWireguardServer" xml:space="preserve">
<value>添加[WireGuard]伺服器</value>
</data>
<data name="TbPrivateKey" xml:space="preserve">
<value>PrivateKey</value>
</data>
<data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value>
</data>
<data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value>
</data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>使用系統hosts</value>
</data>
<data name="TbSortingChain" xml:space="preserve">
<value>路由鏈</value>
</data>
<data name="TbSettingsDomainDNSAddress" xml:space="preserve">
<value>Outbound域名解析位址</value>
</data>
<data name="TbPath7" xml:space="preserve">
<value>混淆密碼(obfs password)</value>
</data>
<data name="TbSettingsLinuxSudoPassword" xml:space="preserve">
<value>Linux系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordNotSudoRunApp" xml:space="preserve">
<value>請不要用sudo來運行本app</value>
</data>
<data name="TransportHeaderTypeTip5" xml:space="preserve">
<value>*xhttp 模式</value>
</data>
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value>
</data>
</root> </root>

View File

@@ -1,73 +1,149 @@
[ [
{ {
"remarks": "绕过bittorrent", "remarks": "绕过bittorrent",
"outboundTag": "direct", "outboundTag": "direct",
"protocol": [ "protocol": [
"bittorrent" "bittorrent"
] ]
}, },
{ {
"remarks": "Google cn", "remarks": "Google cn",
"outboundTag": "proxy", "outboundTag": "proxy",
"domain": [ "domain": [
"domain:googleapis.cn", "domain:googleapis.cn",
"domain:gstatic.com" "domain:gstatic.com"
] ]
}, },
{ {
"remarks": "阻断udp443", "remarks": "阻断udp443",
"outboundTag": "block", "outboundTag": "block",
"port": "443", "port": "443",
"network": "udp" "network": "udp"
}, },
{ {
"remarks": "阻断广告", "remarks": "阻断广告",
"outboundTag": "block", "outboundTag": "block",
"domain": [ "domain": [
"geosite:category-ads-all" "geosite:category-ads-all"
] ]
}, },
{ {
"remarks": "绕过局域网IP", "remarks": "绕过局域网IP",
"outboundTag": "direct", "outboundTag": "direct",
"ip": [ "ip": [
"geoip:private" "geoip:private"
] ]
}, },
{ {
"remarks": "绕过局域网域名", "remarks": "绕过局域网域名",
"outboundTag": "direct", "outboundTag": "direct",
"domain": [ "domain": [
"geosite:private" "geosite:private"
] ]
}, },
{ {
"remarks": "代理IP", "remarks": "代理海外公共DNSIP",
"outboundTag": "proxy", "outboundTag": "proxy",
"ip": [ "ip": [
"1.0.0.1", "1.1.1.1",
"1.1.1.1", "1.0.0.1",
"8.8.8.8", "2606:4700:4700::1111",
"8.8.4.4", "2606:4700:4700::1001",
"geoip:facebook", "1.1.1.2",
"geoip:fastly", "1.0.0.2",
"geoip:google", "2606:4700:4700::1112",
"geoip:netflix", "2606:4700:4700::1002",
"geoip:telegram", "1.1.1.3",
"geoip:twitter" "1.0.0.3",
] "2606:4700:4700::1113",
}, "2606:4700:4700::1003",
{ "8.8.8.8",
"remarks": "代理GFW", "8.8.4.4",
"outboundTag": "proxy", "2001:4860:4860::8888",
"domain": [ "2001:4860:4860::8844",
"geosite:gfw", "94.140.14.14",
"geosite:greatfire" "94.140.15.15",
] "2a10:50c0::ad1:ff",
}, "2a10:50c0::ad2:ff",
{ "94.140.14.15",
"remarks": "最终直连", "94.140.15.16",
"port": "0-65535", "2a10:50c0::bad1:ff",
"outboundTag": "direct" "2a10:50c0::bad2:ff",
} "94.140.14.140",
"94.140.14.141",
"2a10:50c0::1:ff",
"2a10:50c0::2:ff",
"208.67.222.222",
"208.67.220.220",
"2620:119:35::35",
"2620:119:53::53",
"208.67.222.123",
"208.67.220.123",
"2620:119:35::123",
"2620:119:53::123",
"9.9.9.9",
"149.112.112.112",
"2620:fe::9",
"2620:fe::fe",
"9.9.9.11",
"149.112.112.11",
"2620:fe::11",
"2620:fe::fe:11",
"9.9.9.10",
"149.112.112.10",
"2620:fe::10",
"2620:fe::fe:10",
"77.88.8.8",
"77.88.8.1",
"2a02:6b8::feed:0ff",
"2a02:6b8:0:1::feed:0ff",
"77.88.8.88",
"77.88.8.2",
"2a02:6b8::feed:bad",
"2a02:6b8:0:1::feed:bad",
"77.88.8.7",
"77.88.8.3",
"2a02:6b8::feed:a11",
"2a02:6b8:0:1::feed:a11"
]
},
{
"remarks": "代理海外公共DNS域名",
"outboundTag": "proxy",
"domain": [
"domain:cloudflare-dns.com",
"domain:one.one.one.one",
"domain:dns.google",
"domain:adguard-dns.com",
"domain:opendns.com",
"domain:umbrella.com",
"domain:quad9.net",
"domain:yandex.net"
]
},
{
"remarks": "代理IP",
"outboundTag": "proxy",
"ip": [
"geoip:facebook",
"geoip:fastly",
"geoip:google",
"geoip:netflix",
"geoip:telegram",
"geoip:twitter"
]
},
{
"remarks": "代理GFW",
"outboundTag": "proxy",
"domain": [
"geosite:gfw",
"geosite:greatfire"
]
},
{
"remarks": "最终直连",
"port": "0-65535",
"outboundTag": "direct"
}
] ]

View File

@@ -1,4 +1,5 @@
[{ [
{
"remarks": "block", "remarks": "block",
"outboundTag": "block", "outboundTag": "block",
"domain": [ "domain": [
@@ -12,14 +13,14 @@
"geosite:cn" "geosite:cn"
] ]
}, },
{ {
"remarks": "direct", "remarks": "direct",
"outboundTag": "direct", "outboundTag": "direct",
"ip": [ "ip": [
"geoip:private", "geoip:private",
"geoip:cn" "geoip:cn"
] ]
}, },
{ {
"remarks": "proxy", "remarks": "proxy",
"port": "0-65535", "port": "0-65535",

View File

@@ -34,29 +34,62 @@
"geosite:private" "geosite:private"
] ]
}, },
{
"remarks": "绕过中国公共DNSIP",
"outboundTag": "direct",
"ip": [
"223.5.5.5",
"223.6.6.6",
"2400:3200::1",
"2400:3200:baba::1",
"119.29.29.29",
"1.12.12.12",
"120.53.53.53",
"2402:4e00::",
"2402:4e00:1::",
"180.76.76.76",
"2400:da00::6666",
"114.114.114.114",
"114.114.115.115",
"114.114.114.119",
"114.114.115.119",
"114.114.114.110",
"114.114.115.110",
"180.184.1.1",
"180.184.2.2",
"101.226.4.6",
"218.30.118.6",
"123.125.81.6",
"140.207.198.6",
"1.2.4.8",
"210.2.4.8",
"52.80.66.66",
"117.50.22.22",
"2400:7fc0:849e:200::4",
"2404:c2c0:85d8:901::4",
"117.50.10.10",
"52.80.52.52",
"2400:7fc0:849e:200::8",
"2404:c2c0:85d8:901::8",
"117.50.60.30",
"52.80.60.30"
]
},
{
"remarks": "绕过中国公共DNS域名",
"outboundTag": "direct",
"domain": [
"domain:alidns.com",
"domain:doh.pub",
"domain:dot.pub",
"domain:360.cn",
"domain:onedns.net"
]
},
{ {
"remarks": "绕过中国IP", "remarks": "绕过中国IP",
"outboundTag": "direct", "outboundTag": "direct",
"ip": [ "ip": [
"223.5.5.5/32",
"223.6.6.6/32",
"2400:3200::1/128",
"2400:3200:baba::1/128",
"119.29.29.29/32",
"1.12.12.12/32",
"120.53.53.53/32",
"2402:4e00::/128",
"2402:4e00:1::/128",
"180.76.76.76/32",
"2400:da00::6666/128",
"114.114.114.114/32",
"114.114.115.115/32",
"180.184.1.1/32",
"180.184.2.2/32",
"101.226.4.6/32",
"218.30.118.6/32",
"123.125.81.6/32",
"140.207.198.6/32",
"geoip:cn" "geoip:cn"
] ]
}, },
@@ -64,13 +97,7 @@
"remarks": "绕过中国域名", "remarks": "绕过中国域名",
"outboundTag": "direct", "outboundTag": "direct",
"domain": [ "domain": [
"domain:dns.alidns.com", "geosite:cn"
"domain:doh.pub",
"domain:dot.pub",
"domain:doh.360.cn",
"domain:dot.360.cn",
"geosite:cn",
"geosite:geolocation-cn"
] ]
}, },
{ {

View File

@@ -20,8 +20,7 @@
"rules": [ "rules": [
{ {
"rule_set": [ "rule_set": [
"geosite-cn", "geosite-cn"
"geosite-geolocation-cn"
], ],
"server": "local" "server": "local"
}, },

View File

@@ -7,8 +7,7 @@
{ {
"address": "223.5.5.5", "address": "223.5.5.5",
"domains": [ "domains": [
"geosite:cn", "geosite:cn"
"geosite:geolocation-cn"
], ],
"expectIPs": [ "expectIPs": [
"geoip:cn" "geoip:cn"

View File

@@ -2,8 +2,10 @@
"type": "tun", "type": "tun",
"tag": "tun-in", "tag": "tun-in",
"interface_name": "singbox_tun", "interface_name": "singbox_tun",
"inet4_address": "172.19.0.1/30", "address": [
"inet6_address": "fdfe:dcba:9876::1/126", "172.18.0.1/30",
"fdfe:dcba:9876::1/126"
],
"mtu": 9000, "mtu": 9000,
"auto_route": true, "auto_route": true,
"strict_route": false, "strict_route": false,

View File

@@ -4,17 +4,17 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>7.0.9</Version> <Version>7.2.0</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Downloader" Version="3.2.1" /> <PackageReference Include="Downloader" Version="3.3.0" />
<PackageReference Include="ReactiveUI" Version="20.1.63" /> <PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" /> <PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.2.22" /> <PackageReference Include="Splat.NLog" Version="15.2.22" />
<PackageReference Include="WebDav.Client" Version="2.8.0" /> <PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.3" /> <PackageReference Include="YamlDotNet" Version="16.2.0" />
<PackageReference Include="QRCoder" Version="1.6.0" /> <PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="CliWrap" Version="3.6.7" /> <PackageReference Include="CliWrap" Version="3.6.7" />
<PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" /> <PackageReference Include="SkiaSharp.QrCode" Version="0.7.0" />
@@ -49,7 +49,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PacLib\PacLib.csproj" /> <ProjectReference Include="..\PacLib\PacLib.csproj" />
<ProjectReference Include="..\ProtosLib\ProtosLib.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -26,7 +26,7 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.CheckServerSettings; ret.Msg = ResUI.CheckServerSettings;
return ret; return ret;
} }
if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp)) if (node.GetNetwork() is nameof(ETransport.kcp) or nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{ {
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}"; ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret; return ret;
@@ -90,8 +90,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient); var result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -119,10 +119,10 @@ namespace ServiceLib.Services.CoreConfig
await GenLog(singboxConfig); await GenLog(singboxConfig);
//GenDns(new(), singboxConfig); //GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. singboxConfig.inbounds.Clear();
singboxConfig.outbounds.RemoveAt(0); singboxConfig.outbounds.RemoveAt(0);
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest); var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
@@ -499,13 +499,10 @@ namespace ServiceLib.Services.CoreConfig
inbound.sniff_override_destination = _config.Inbound[0].RouteOnly ? false : _config.Inbound[0].SniffingEnabled; inbound.sniff_override_destination = _config.Inbound[0].RouteOnly ? false : _config.Inbound[0].SniffingEnabled;
inbound.domain_strategy = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainStrategy4Singbox) ? null : _config.RoutingBasicItem.DomainStrategy4Singbox; inbound.domain_strategy = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainStrategy4Singbox) ? null : _config.RoutingBasicItem.DomainStrategy4Singbox;
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); inbound.domain_strategy = routing.DomainStrategy4Singbox;
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
} }
//http //http
@@ -558,7 +555,7 @@ namespace ServiceLib.Services.CoreConfig
//tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled; //tunInbound.sniff_override_destination = _config.inbound[0].routeOnly ? false : _config.inbound[0].sniffingEnabled;
if (_config.TunModeItem.EnableIPv6Address == false) if (_config.TunModeItem.EnableIPv6Address == false)
{ {
tunInbound.inet6_address = null; tunInbound.address = ["172.18.0.1/30"];
} }
singboxConfig.inbounds.Add(tunInbound); singboxConfig.inbounds.Add(tunInbound);
@@ -958,28 +955,13 @@ namespace ServiceLib.Services.CoreConfig
}); });
} }
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
if (routing != null) foreach (var item in rules ?? [])
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet); if (item.Enabled)
foreach (var item in rules ?? [])
{
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
}
}
}
}
else
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet);
foreach (var item in rules ?? [])
{ {
await GenRoutingUserRule(item, singboxConfig.route.rules); await GenRoutingUserRule(item, singboxConfig.route.rules);
} }
@@ -1334,20 +1316,18 @@ namespace ServiceLib.Services.CoreConfig
//load custom ruleset file //load custom ruleset file
List<Ruleset4Sbox> customRulesets = []; List<Ruleset4Sbox> customRulesets = [];
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox)) if (Utils.IsNotEmpty(result))
{ {
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox); customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
if (Utils.IsNotEmpty(result)) .Where(t => t.tag != null)
{ .Where(t => t.type != null)
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? []) .Where(t => t.format != null)
.Where(t => t.tag != null) .ToList();
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
} }
} }

View File

@@ -27,6 +27,12 @@ namespace ServiceLib.Services.CoreConfig
return ret; return ret;
} }
if (node.GetNetwork() is nameof(ETransport.quic))
{
ret.Msg = ResUI.Incorrectconfiguration + $" - {node.GetNetwork()}";
return ret;
}
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
var result = Utils.GetEmbedText(Global.V2raySampleClient); var result = Utils.GetEmbedText(Global.V2raySampleClient);
@@ -210,8 +216,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration; ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient); var result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound); var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty()) if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{ {
ret.Msg = ResUI.FailedGetDefaultConfiguration; ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -238,10 +244,11 @@ namespace ServiceLib.Services.CoreConfig
} }
await GenLog(v2rayConfig); await GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts. v2rayConfig.inbounds.Clear();
v2rayConfig.outbounds.RemoveAt(0); v2rayConfig.outbounds.Clear();
v2rayConfig.routing.rules.Clear();
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest); var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
foreach (var it in selecteds) foreach (var it in selecteds)
{ {
@@ -264,7 +271,7 @@ namespace ServiceLib.Services.CoreConfig
//find unused port //find unused port
var port = httpPort; var port = httpPort;
for (int k = httpPort; k < Global.MaxPort; k++) for (var k = httpPort; k < Global.MaxPort; k++)
{ {
if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0) if (lstIpEndPoints?.FindIndex(_it => _it.Port == k) >= 0)
{ {
@@ -288,16 +295,6 @@ namespace ServiceLib.Services.CoreConfig
it.Port = port; it.Port = port;
it.AllowTest = true; it.AllowTest = true;
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
//outbound //outbound
if (item is null) if (item is null)
{ {
@@ -320,6 +317,16 @@ namespace ServiceLib.Services.CoreConfig
continue; continue;
} }
//inbound
Inbounds4Ray inbound = new()
{
listen = Global.Loopback,
port = port,
protocol = EInboundProtocol.http.ToString(),
};
inbound.tag = inbound.protocol + inbound.port.ToString();
v2rayConfig.inbounds.Add(inbound);
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound); var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(item, outbound); await GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString(); outbound.tag = Global.ProxyTag + inbound.port.ToString();
@@ -366,8 +373,8 @@ namespace ServiceLib.Services.CoreConfig
else else
{ {
v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel; v2rayConfig.log.loglevel = _config.CoreBasicItem.Loglevel;
v2rayConfig.log.access = ""; v2rayConfig.log.access = null;
v2rayConfig.log.error = ""; v2rayConfig.log.error = null;
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -460,33 +467,17 @@ namespace ServiceLib.Services.CoreConfig
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy; v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainMatcher) ? null : _config.RoutingBasicItem.DomainMatcher; v2rayConfig.routing.domainMatcher = Utils.IsNullOrEmpty(_config.RoutingBasicItem.DomainMatcher) ? null : _config.RoutingBasicItem.DomainMatcher;
if (_config.RoutingBasicItem.EnableRoutingAdvanced) var routing = await ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{ {
var routing = await ConfigHandler.GetDefaultRouting(_config); if (Utils.IsNotEmpty(routing.DomainStrategy))
if (routing != null)
{ {
if (Utils.IsNotEmpty(routing.DomainStrategy)) v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
{
v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
}
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules)
{
if (item.Enabled)
{
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig);
}
}
} }
} var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
else foreach (var item in rules)
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
{ {
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet); if (item.Enabled)
foreach (var item in rules)
{ {
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item)); var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig); await GenRoutingUserRule(item2, v2rayConfig);
@@ -920,23 +911,35 @@ namespace ServiceLib.Services.CoreConfig
streamSettings.httpupgradeSettings = httpupgradeSettings; streamSettings.httpupgradeSettings = httpupgradeSettings;
break; break;
//splithttp //splithttp //xhttp
case nameof(ETransport.splithttp): case nameof(ETransport.splithttp):
SplithttpSettings4Ray splithttpSettings = new() case nameof(ETransport.xhttp):
streamSettings.network = ETransport.xhttp.ToString();
XhttpSettings4Ray xhttpSettings = new()
{ {
maxUploadSize = 1000000, scMaxEachPostBytes = "500000-1000000",
maxConcurrentUploads = 10 scMaxConcurrentPosts = "50-100",
scMinPostsIntervalMs = "30-50"
}; };
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(node.Path))
{ {
splithttpSettings.path = node.Path; xhttpSettings.path = node.Path;
} }
if (Utils.IsNotEmpty(host)) if (Utils.IsNotEmpty(host))
{ {
splithttpSettings.host = host; xhttpSettings.host = host;
} }
streamSettings.splithttpSettings = splithttpSettings; if (Utils.IsNotEmpty(node.HeaderType) && Global.XhttpMode.Contains(node.HeaderType))
{
xhttpSettings.mode = node.HeaderType;
}
if (Utils.IsNotEmpty(node.Extra))
{
xhttpSettings.extra = JsonUtils.ParseJson(node.Extra);
}
streamSettings.xhttpSettings = xhttpSettings;
break; break;
//h2 //h2
@@ -1006,18 +1009,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host //request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName); string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(','); string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost); string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\""); request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost())); request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
//Path //Path
string pathHttp = @"/"; string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path)) if (Utils.IsNotEmpty(node.Path))
{ {
string[] arrPath = node.Path.Split(','); string[] arrPath = node.Path.Split(',');
pathHttp = string.Join("\",\"", arrPath); pathHttp = string.Join(",".AppendQuotes(), arrPath);
} }
request = request.Replace("$requestPath$", $"\"{pathHttp}\""); request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
tcpSettings.header.request = JsonUtils.Deserialize<object>(request); tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
streamSettings.tcpSettings = tcpSettings; streamSettings.tcpSettings = tcpSettings;
@@ -1120,17 +1122,14 @@ namespace ServiceLib.Services.CoreConfig
if (_config.GuiItem.EnableStatistics) if (_config.GuiItem.EnableStatistics)
{ {
string tag = EInboundProtocol.api.ToString(); string tag = EInboundProtocol.api.ToString();
API4Ray apiObj = new(); Metrics4Ray apiObj = new();
Policy4Ray policyObj = new(); Policy4Ray policyObj = new();
SystemPolicy4Ray policySystemSetting = new(); SystemPolicy4Ray policySystemSetting = new();
string[] services = { "StatsService" };
v2rayConfig.stats = new Stats4Ray(); v2rayConfig.stats = new Stats4Ray();
apiObj.tag = tag; apiObj.tag = tag;
apiObj.services = services.ToList(); v2rayConfig.metrics = apiObj;
v2rayConfig.api = apiObj;
policySystemSetting.statsOutboundDownlink = true; policySystemSetting.statsOutboundDownlink = true;
policySystemSetting.statsOutboundUplink = true; policySystemSetting.statsOutboundUplink = true;

View File

@@ -1,135 +0,0 @@
using Grpc.Core;
using Grpc.Net.Client;
using ProtosLib.Statistics;
namespace ServiceLib.Services.Statistics
{
public class StatisticsV2rayService
{
private Models.Config _config;
private GrpcChannel? _channel;
private StatsService.StatsServiceClient? _client;
private bool _exitFlag;
private Action<ServerSpeedItem>? _updateFunc;
public StatisticsV2rayService(Models.Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_exitFlag = false;
GrpcInit();
Task.Run(Run);
}
private void GrpcInit()
{
if (_channel is null)
{
try
{
_channel = GrpcChannel.ForAddress($"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}");
_client = new StatsService.StatsServiceClient(_channel);
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
}
}
public void Close()
{
_exitFlag = true;
}
private async void Run()
{
while (!_exitFlag)
{
await Task.Delay(1000);
try
{
if (!_config.IsRunningCore(ECoreType.Xray))
{
continue;
}
if (_channel?.State == ConnectivityState.Ready)
{
QueryStatsResponse? res = null;
try
{
if (_client != null)
res = await _client.QueryStatsAsync(new QueryStatsRequest() { Pattern = "", Reset = true });
}
catch
{
}
if (res != null)
{
ParseOutput(res.Stat, out ServerSpeedItem server);
_updateFunc?.Invoke(server);
}
}
if (_channel != null)
await _channel.ConnectAsync();
}
catch
{
}
}
}
private void ParseOutput(Google.Protobuf.Collections.RepeatedField<Stat> source, out ServerSpeedItem server)
{
server = new();
long aggregateProxyUp = 0;
long aggregateProxyDown = 0;
try
{
foreach (Stat stat in source)
{
string name = stat.Name;
long value = stat.Value / 1024; //KByte
string[] nStr = name.Split(">>>".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
string type = "";
name = name.Trim();
name = nStr[1];
type = nStr[3];
if (name.StartsWith(Global.ProxyTag))
{
if (type == "uplink")
{
aggregateProxyUp += value;
}
else if (type == "downlink")
{
aggregateProxyDown += value;
}
}
else if (name == Global.DirectTag)
{
if (type == "uplink")
{
server.DirectUp = value;
}
else if (type == "downlink")
{
server.DirectDown = value;
}
}
}
server.ProxyUp = aggregateProxyUp;
server.ProxyDown = aggregateProxyDown;
}
catch
{
}
}
}
}

View File

@@ -0,0 +1,106 @@
namespace ServiceLib.Services.Statistics
{
public class StatisticsXrayService
{
private const long linkBase = 1024;
private string _url;
private ServerSpeedItem _serverSpeedItem = new();
private Config _config;
private bool _exitFlag;
private Action<ServerSpeedItem>? _updateFunc;
public StatisticsXrayService(Config config, Action<ServerSpeedItem> updateFunc)
{
_config = config;
_updateFunc = updateFunc;
_exitFlag = false;
_url = $"{Global.HttpProtocol}{Global.Loopback}:{AppHandler.Instance.StatePort}/debug/vars";
Task.Run(Run);
}
public void Close()
{
_exitFlag = true;
}
private async void Run()
{
while (!_exitFlag)
{
await Task.Delay(1000);
try
{
if (_config.RunningCoreType != ECoreType.Xray)
{
continue;
}
var result = await HttpClientHelper.Instance.TryGetAsync(_url);
if (result != null)
{
var server = ParseOutput(result) ?? new ServerSpeedItem();
_updateFunc?.Invoke(server);
}
}
catch
{
// ignored
}
}
}
private ServerSpeedItem? ParseOutput(string result)
{
try
{
var source = JsonUtils.Deserialize<V2rayMetricsVars>(result);
if (source?.stats?.outbound == null)
{
return null;
}
ServerSpeedItem server = new();
foreach (string key in source.stats.outbound.Keys)
{
var value = source.stats.outbound[key];
if (value == null) continue;
var state = JsonUtils.Deserialize<V2rayMetricsVarsLink>(value.ToString());
if (key.StartsWith(Global.ProxyTag))
{
server.ProxyUp += state.uplink / linkBase;
server.ProxyDown += state.downlink / linkBase;
}
else if (key == Global.DirectTag)
{
server.DirectUp = state.uplink / linkBase;
server.DirectDown = state.downlink / linkBase;
}
}
if (server.DirectDown < _serverSpeedItem.DirectDown || server.ProxyDown < _serverSpeedItem.ProxyDown)
{
_serverSpeedItem = new();
return null;
}
ServerSpeedItem curItem = new()
{
ProxyUp = server.ProxyUp - _serverSpeedItem.ProxyUp,
ProxyDown = server.ProxyDown - _serverSpeedItem.ProxyDown,
DirectUp = server.DirectUp - _serverSpeedItem.DirectUp,
DirectDown = server.DirectDown - _serverSpeedItem.DirectDown,
};
_serverSpeedItem = server;
return curItem;
}
catch
{
// ignored
}
return null;
}
}
}

View File

@@ -244,8 +244,17 @@ namespace ServiceLib.Services
public async Task RunAvailabilityCheck(Action<bool, string> updateFunc) public async Task RunAvailabilityCheck(Action<bool, string> updateFunc)
{ {
var time = await new DownloadService().RunAvailabilityCheck(null); var downloadHandle = new DownloadService();
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time)); var time = await downloadHandle.RunAvailabilityCheck(null);
var ip = Global.None;
if (time > 0)
{
var result = await downloadHandle.TryDownloadString(Global.IPAPIUrl, true, "ipapi");
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
ip = $"({ipInfo?.country}) {ipInfo?.ip}";
}
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time, ip));
} }
#region CheckUpdate private #region CheckUpdate private

View File

@@ -267,7 +267,7 @@ namespace ServiceLib.ViewModels
var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList(); var filesList = (new DirectoryInfo(toPath)).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList) foreach (var file in filesList)
{ {
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType)); await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower()));
} }
} }

View File

@@ -219,6 +219,7 @@ namespace ServiceLib.ViewModels
await Reload(); await Reload();
await AutoHideStartup(); await AutoHideStartup();
Locator.Current.GetService<StatusBarViewModel>()?.RefreshRoutingsMenu();
} }
#endregion Init #endregion Init
@@ -323,6 +324,7 @@ namespace ServiceLib.ViewModels
if (process.Id > 0) if (process.Id > 0)
{ {
await MyAppExitAsync(false); await MyAppExitAsync(false);
await MyAppExitAsync(false);
} }
} }
@@ -531,6 +533,10 @@ namespace ServiceLib.ViewModels
{ {
Utils.ProcessStart("nautilus", Utils.GetConfigPath()); Utils.ProcessStart("nautilus", Utils.GetConfigPath());
} }
else if (Utils.IsOSX())
{
Utils.ProcessStart("open", Utils.GetConfigPath());
}
} }
#endregion Setting #endregion Setting

View File

@@ -53,6 +53,7 @@ namespace ServiceLib.ViewModels
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; } [Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; } [Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; } [Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool Hide2TrayWhenClose { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; } [Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; } [Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; } [Reactive] public int AutoUpdateInterval { get; set; }
@@ -85,6 +86,7 @@ namespace ServiceLib.ViewModels
[Reactive] public int TunMtu { get; set; } [Reactive] public int TunMtu { get; set; }
[Reactive] public bool TunEnableExInbound { get; set; } [Reactive] public bool TunEnableExInbound { get; set; }
[Reactive] public bool TunEnableIPv6Address { get; set; } [Reactive] public bool TunEnableIPv6Address { get; set; }
[Reactive] public string TunLinuxSudoPassword { get; set; }
#endregion Tun mode #endregion Tun mode
@@ -165,6 +167,7 @@ namespace ServiceLib.ViewModels
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist; EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13; EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
AutoHideStartup = _config.UiItem.AutoHideStartup; AutoHideStartup = _config.UiItem.AutoHideStartup;
Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose;
EnableDragDropSort = _config.UiItem.EnableDragDropSort; EnableDragDropSort = _config.UiItem.EnableDragDropSort;
DoubleClick2Activate = _config.UiItem.DoubleClick2Activate; DoubleClick2Activate = _config.UiItem.DoubleClick2Activate;
AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval; AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval;
@@ -197,6 +200,7 @@ namespace ServiceLib.ViewModels
TunMtu = _config.TunModeItem.Mtu; TunMtu = _config.TunModeItem.Mtu;
TunEnableExInbound = _config.TunModeItem.EnableExInbound; TunEnableExInbound = _config.TunModeItem.EnableExInbound;
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address; TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
#endregion Tun mode #endregion Tun mode
@@ -314,6 +318,7 @@ namespace ServiceLib.ViewModels
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist; _config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13; _config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.UiItem.AutoHideStartup = AutoHideStartup; _config.UiItem.AutoHideStartup = AutoHideStartup;
_config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose;
_config.GuiItem.AutoUpdateInterval = AutoUpdateInterval; _config.GuiItem.AutoUpdateInterval = AutoUpdateInterval;
_config.UiItem.EnableDragDropSort = EnableDragDropSort; _config.UiItem.EnableDragDropSort = EnableDragDropSort;
_config.UiItem.DoubleClick2Activate = DoubleClick2Activate; _config.UiItem.DoubleClick2Activate = DoubleClick2Activate;
@@ -340,6 +345,10 @@ namespace ServiceLib.ViewModels
_config.TunModeItem.Mtu = TunMtu; _config.TunModeItem.Mtu = TunMtu;
_config.TunModeItem.EnableExInbound = TunEnableExInbound; _config.TunModeItem.EnableExInbound = TunEnableExInbound;
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address; _config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
{
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
}
//coreType //coreType
await SaveCoreType(); await SaveCoreType();

View File

@@ -479,7 +479,10 @@ namespace ServiceLib.ViewModels
await ConfigHandler.RemoveServer(_config, lstSelecteds); await ConfigHandler.RemoveServer(_config, lstSelecteds);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
if (lstSelecteds.Count == _profileItems.Count)
{
_profileItems.Clear();
}
RefreshServers(); RefreshServers();
if (exists) if (exists)
{ {
@@ -726,7 +729,7 @@ namespace ServiceLib.ViewModels
{ {
return; return;
} }
var result = await CoreConfigHandler.GenerateClientConfig(item, null); var result = await CoreConfigHandler.GenerateClientConfig(item, fileName);
if (result.Success != true) if (result.Success != true)
{ {
NoticeHandler.Instance.Enqueue(result.Msg); NoticeHandler.Instance.Enqueue(result.Msg);

View File

@@ -86,7 +86,7 @@ namespace ServiceLib.ViewModels
return; return;
} }
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); //NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null); await _updateView?.Invoke(EViewAction.CloseWindow, null);
} }
} }
} }

View File

@@ -7,9 +7,6 @@ namespace ServiceLib.ViewModels
{ {
public class RoutingSettingViewModel : MyReactiveObject public class RoutingSettingViewModel : MyReactiveObject
{ {
private RoutingItem _lockedItem;
private List<RulesItem> _lockedRules;
#region Reactive #region Reactive
private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>(); private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>();
@@ -20,12 +17,6 @@ namespace ServiceLib.ViewModels
public IList<RoutingItemModel> SelectedSources { get; set; } public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive]
public bool enableRoutingAdvanced { get; set; }
[Reactive]
public bool enableRoutingBasic { get; set; }
[Reactive] [Reactive]
public string domainStrategy { get; set; } public string domainStrategy { get; set; }
@@ -35,25 +26,6 @@ namespace ServiceLib.ViewModels
[Reactive] [Reactive]
public string domainStrategy4Singbox { get; set; } public string domainStrategy4Singbox { get; set; }
[Reactive]
public string ProxyDomain { get; set; }
[Reactive]
public string ProxyIP { get; set; }
[Reactive]
public string DirectDomain { get; set; }
[Reactive]
public string DirectIP { get; set; }
[Reactive]
public string BlockDomain { get; set; }
[Reactive]
public string BlockIP { get; set; }
public ReactiveCommand<Unit, Unit> RoutingBasicImportRulesCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedAddCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedRemoveCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; } public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
@@ -73,15 +45,6 @@ namespace ServiceLib.ViewModels
x => x.SelectedSource, x => x.SelectedSource,
selectedSource => selectedSource != null && !selectedSource.Remarks.IsNullOrEmpty()); selectedSource => selectedSource != null && !selectedSource.Remarks.IsNullOrEmpty());
this.WhenAnyValue(
x => x.enableRoutingAdvanced)
.Subscribe(c => enableRoutingBasic = !enableRoutingAdvanced);
RoutingBasicImportRulesCmd = ReactiveCommand.CreateFromTask(async () =>
{
await RoutingBasicImportRules();
});
RoutingAdvancedAddCmd = ReactiveCommand.CreateFromTask(async () => RoutingAdvancedAddCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
await RoutingAdvancedEditAsync(true); await RoutingAdvancedEditAsync(true);
@@ -111,67 +74,14 @@ namespace ServiceLib.ViewModels
{ {
SelectedSource = new(); SelectedSource = new();
enableRoutingAdvanced = true;//TODO _config.RoutingBasicItem.EnableRoutingAdvanced;
domainStrategy = _config.RoutingBasicItem.DomainStrategy; domainStrategy = _config.RoutingBasicItem.DomainStrategy;
domainMatcher = _config.RoutingBasicItem.DomainMatcher; domainMatcher = _config.RoutingBasicItem.DomainMatcher;
domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox; domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config); await ConfigHandler.InitBuiltinRouting(_config);
await RefreshRoutingItems(); await RefreshRoutingItems();
await BindingLockedData();
} }
#region locked
private async Task BindingLockedData()
{
_lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (_lockedItem == null)
{
_lockedItem = new RoutingItem()
{
Remarks = "locked",
Url = string.Empty,
Locked = true,
};
await ConfigHandler.AddBatchRoutingRules(_lockedItem, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
}
if (_lockedItem != null)
{
_lockedRules = JsonUtils.Deserialize<List<RulesItem>>(_lockedItem.RuleSet);
ProxyDomain = Utils.List2String(_lockedRules[0].Domain, true);
ProxyIP = Utils.List2String(_lockedRules[0].Ip, true);
DirectDomain = Utils.List2String(_lockedRules[1].Domain, true);
DirectIP = Utils.List2String(_lockedRules[1].Ip, true);
BlockDomain = Utils.List2String(_lockedRules[2].Domain, true);
BlockIP = Utils.List2String(_lockedRules[2].Ip, true);
}
}
private async Task EndBindingLockedData()
{
if (_lockedItem != null)
{
_lockedRules[0].Domain = Utils.String2List(Utils.Convert2Comma(ProxyDomain.TrimEx()));
_lockedRules[0].Ip = Utils.String2List(Utils.Convert2Comma(ProxyIP.TrimEx()));
_lockedRules[1].Domain = Utils.String2List(Utils.Convert2Comma(DirectDomain.TrimEx()));
_lockedRules[1].Ip = Utils.String2List(Utils.Convert2Comma(DirectIP.TrimEx()));
_lockedRules[2].Domain = Utils.String2List(Utils.Convert2Comma(BlockDomain.TrimEx()));
_lockedRules[2].Ip = Utils.String2List(Utils.Convert2Comma(BlockIP.TrimEx()));
_lockedItem.RuleSet = JsonUtils.Serialize(_lockedRules, false);
await ConfigHandler.SaveRoutingItem(_config, _lockedItem);
}
}
#endregion locked
#region Refresh Save #region Refresh Save
public async Task RefreshRoutingItems() public async Task RefreshRoutingItems()
@@ -205,12 +115,9 @@ namespace ServiceLib.ViewModels
private async Task SaveRoutingAsync() private async Task SaveRoutingAsync()
{ {
_config.RoutingBasicItem.DomainStrategy = domainStrategy; _config.RoutingBasicItem.DomainStrategy = domainStrategy;
_config.RoutingBasicItem.EnableRoutingAdvanced = enableRoutingAdvanced;
_config.RoutingBasicItem.DomainMatcher = domainMatcher; _config.RoutingBasicItem.DomainMatcher = domainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox; _config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox;
await EndBindingLockedData();
if (await ConfigHandler.SaveConfig(_config) == 0) if (await ConfigHandler.SaveConfig(_config) == 0)
{ {
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess); NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
@@ -224,18 +131,6 @@ namespace ServiceLib.ViewModels
#endregion Refresh Save #endregion Refresh Save
private async Task RoutingBasicImportRules()
{
//Extra to bypass the mainland
ProxyDomain = "geosite:google";
DirectDomain = "geosite:cn";
DirectIP = "geoip:private,geoip:cn";
BlockDomain = "geosite:category-ads-all";
//NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
}
public async Task RoutingAdvancedEditAsync(bool blNew) public async Task RoutingAdvancedEditAsync(bool blNew)
{ {
RoutingItem item; RoutingItem item;

View File

@@ -108,7 +108,7 @@ namespace ServiceLib.ViewModels
SelectedServer = new(); SelectedServer = new();
RunningServerToolTipText = "-"; RunningServerToolTipText = "-";
if (_config.TunModeItem.EnableTun && AppHandler.Instance.IsAdministrator) if (_config.TunModeItem.EnableTun && AllowEnableTun())
{ {
EnableTun = true; EnableTun = true;
} }
@@ -347,11 +347,6 @@ namespace ServiceLib.ViewModels
public async Task RefreshRoutingsMenu() public async Task RefreshRoutingsMenu()
{ {
_routingItems.Clear(); _routingItems.Clear();
if (!_config.RoutingBasicItem.EnableRoutingAdvanced)
{
BlRouting = false;
return;
}
BlRouting = true; BlRouting = true;
var routings = await AppHandler.Instance.RoutingItems(); var routings = await AppHandler.Instance.RoutingItems();
@@ -414,17 +409,37 @@ namespace ServiceLib.ViewModels
{ {
_config.TunModeItem.EnableTun = EnableTun; _config.TunModeItem.EnableTun = EnableTun;
// When running as a non-administrator, reboot to administrator mode // When running as a non-administrator, reboot to administrator mode
if (EnableTun && !AppHandler.Instance.IsAdministrator) if (EnableTun && AllowEnableTun() == false)
{ {
_config.TunModeItem.EnableTun = false; if (Utils.IsWindows())
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin(); {
return; _config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
//else if (Utils.IsLinux())
//{
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
//}
} }
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload(); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
} }
private bool AllowEnableTun()
{
if (Utils.IsWindows())
{
return AppHandler.Instance.IsAdministrator;
}
else if (Utils.IsLinux())
{
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
}
return false;
}
#endregion System proxy and Routings #endregion System proxy and Routings
#region UI #region UI
@@ -454,7 +469,7 @@ namespace ServiceLib.ViewModels
} }
else else
{ {
InboundLanDisplay = $"{ResUI.LabLAN}:None"; InboundLanDisplay = $"{ResUI.LabLAN}:{Global.None}";
} }
} }

View File

@@ -13,6 +13,7 @@ namespace v2rayN.Desktop.ViewModels
public class ThemeSettingViewModel : MyReactiveObject public class ThemeSettingViewModel : MyReactiveObject
{ {
[Reactive] public bool ColorModeDark { get; set; } [Reactive] public bool ColorModeDark { get; set; }
[Reactive] public bool FollowSystemTheme { get; set; }
[Reactive] public int CurrentFontSize { get; set; } [Reactive] public int CurrentFontSize { get; set; }
@@ -28,13 +29,14 @@ namespace v2rayN.Desktop.ViewModels
private void RestoreUI() private void RestoreUI()
{ {
ModifyTheme(_config.UiItem.ColorModeDark); ModifyTheme();
ModifyFontFamily(); ModifyFontFamily();
} }
private void BindingUI() private void BindingUI()
{ {
ColorModeDark = _config.UiItem.ColorModeDark; ColorModeDark = _config.UiItem.ColorModeDark;
FollowSystemTheme = _config.UiItem.FollowSystemTheme;
CurrentFontSize = _config.UiItem.CurrentFontSize; CurrentFontSize = _config.UiItem.CurrentFontSize;
CurrentLanguage = _config.UiItem.CurrentLanguage; CurrentLanguage = _config.UiItem.CurrentLanguage;
@@ -44,7 +46,18 @@ namespace v2rayN.Desktop.ViewModels
if (_config.UiItem.ColorModeDark != ColorModeDark) if (_config.UiItem.ColorModeDark != ColorModeDark)
{ {
_config.UiItem.ColorModeDark = ColorModeDark; _config.UiItem.ColorModeDark = ColorModeDark;
ModifyTheme(ColorModeDark); ModifyTheme();
ConfigHandler.SaveConfig(_config);
}
});
this.WhenAnyValue(x => x.FollowSystemTheme,
y => y == true)
.Subscribe(c =>
{
if (_config.UiItem.FollowSystemTheme != FollowSystemTheme)
{
_config.UiItem.FollowSystemTheme = FollowSystemTheme;
ModifyTheme();
ConfigHandler.SaveConfig(_config); ConfigHandler.SaveConfig(_config);
} }
}); });
@@ -59,7 +72,6 @@ namespace v2rayN.Desktop.ViewModels
_config.UiItem.CurrentFontSize = CurrentFontSize; _config.UiItem.CurrentFontSize = CurrentFontSize;
double size = CurrentFontSize; double size = CurrentFontSize;
ModifyFontSize(size); ModifyFontSize(size);
ConfigHandler.SaveConfig(_config); ConfigHandler.SaveConfig(_config);
} }
}); });
@@ -79,12 +91,12 @@ namespace v2rayN.Desktop.ViewModels
}); });
} }
private void ModifyTheme(bool isDarkTheme) private void ModifyTheme()
{ {
var app = Application.Current; var app = Application.Current;
if (app is not null) if (app is not null)
{ {
app.RequestedThemeVariant = isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light; app.RequestedThemeVariant = FollowSystemTheme ? ThemeVariant.Default : (ColorModeDark ? ThemeVariant.Dark : ThemeVariant.Light);
} }
} }

View File

@@ -112,7 +112,7 @@
x:Name="txtPort" x:Name="txtPort"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" /> Classes="Margin8" />
</Grid> </Grid>
@@ -164,7 +164,7 @@
x:Name="txtAlterId" x:Name="txtAlterId"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" /> Classes="Margin8" />
@@ -458,7 +458,7 @@
x:Name="cmbHeaderType8" x:Name="cmbHeaderType8"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Classes="Margin8" /> Classes="Margin8" />
</Grid> </Grid>
<Grid <Grid
@@ -541,7 +541,7 @@
x:Name="txtShortId9" x:Name="txtShortId9"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" /> Classes="Margin8" />
</Grid> </Grid>
@@ -584,7 +584,7 @@
x:Name="cmbNetwork" x:Name="cmbNetwork"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Classes="Margin8" /> Classes="Margin8" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
@@ -600,12 +600,50 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Classes="Margin8" Classes="Margin8"
Text="{x:Static resx:ResUI.TbHeaderType}" /> Text="{x:Static resx:ResUI.TbHeaderType}" />
<ComboBox <StackPanel
x:Name="cmbHeaderType"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="100" VerticalAlignment="Center"
Classes="Margin8" /> Orientation="Horizontal">
<ComboBox
x:Name="cmbHeaderType"
Width="200"
Classes="Margin8" />
<Button
x:Name="btnExtra"
Width="30"
Height="30"
Margin="10,0"
Theme="{DynamicResource BorderlessButton}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_more}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TransportExtraTip}" />
<TextBox
x:Name="txtExtra"
Width="400"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="6"
TextWrapping="Wrap" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
</StackPanel>
<TextBlock <TextBlock
x:Name="tipHeaderType" x:Name="tipHeaderType"
Grid.Row="2" Grid.Row="2"
@@ -680,7 +718,7 @@
x:Name="cmbStreamSecurity" x:Name="cmbStreamSecurity"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Classes="Margin8" /> Classes="Margin8" />
</Grid> </Grid>
<Grid <Grid
@@ -749,7 +787,7 @@
x:Name="cmbAllowInsecure" x:Name="cmbAllowInsecure"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Classes="Margin8" /> Classes="Margin8" />
</Grid> </Grid>
<Grid <Grid

View File

@@ -208,6 +208,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
@@ -299,6 +300,13 @@ namespace v2rayN.Desktop.Views
cmbHeaderType.Items.Add(it); cmbHeaderType.Items.Add(it);
}); });
} }
else if (network is nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
}
else if (network == nameof(ETransport.grpc)) else if (network == nameof(ETransport.grpc))
{ {
cmbHeaderType.Items.Add(Global.GrpcGunMode); cmbHeaderType.Items.Add(Global.GrpcGunMode);
@@ -319,6 +327,7 @@ namespace v2rayN.Desktop.Views
network = Global.DefaultNetwork; network = Global.DefaultNetwork;
} }
labHeaderType.IsVisible = true; labHeaderType.IsVisible = true;
btnExtra.IsVisible = false;
tipRequestHost.Text = tipRequestHost.Text =
tipPath.Text = tipPath.Text =
tipHeaderType.Text = string.Empty; tipHeaderType.Text = string.Empty;
@@ -337,11 +346,19 @@ namespace v2rayN.Desktop.Views
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2; tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1; tipPath.Text = ResUI.TransportPathTip1;
break; break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
labHeaderType.IsVisible = false;
btnExtra.IsVisible = true;
break;
case nameof(ETransport.h2): case nameof(ETransport.h2):
tipRequestHost.Text = ResUI.TransportRequestHostTip3; tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2; tipPath.Text = ResUI.TransportPathTip2;

View File

@@ -50,7 +50,7 @@
<Border <Border
Width="500" Width="500"
Height="80" Height="80"
Margin="0" Margin="-2"
VerticalAlignment="Center" VerticalAlignment="Center"
Theme="{StaticResource CardBorder}"> Theme="{StaticResource CardBorder}">
<Grid> <Grid>

View File

@@ -117,6 +117,11 @@ namespace v2rayN.Desktop.Views
} }
else else
{ {
if (AppHandler.Instance.IsAdministrator)
{
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
}
menuRebootAsAdmin.IsVisible = false; menuRebootAsAdmin.IsVisible = false;
menuSettingsSetUWP.IsVisible = false; menuSettingsSetUWP.IsVisible = false;
menuGlobalHotkeySetting.IsVisible = false; menuGlobalHotkeySetting.IsVisible = false;
@@ -282,6 +287,7 @@ namespace v2rayN.Desktop.Views
e.Cancel = true; e.Cancel = true;
ShowHideWindow(false); ShowHideWindow(false);
break; break;
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown: case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
await ViewModel?.MyAppExitAsync(true); await ViewModel?.MyAppExitAsync(true);
break; break;
@@ -392,7 +398,7 @@ namespace v2rayN.Desktop.Views
} }
else else
{ {
if (Utils.IsWindows()) if (_config.UiItem.Hide2TrayWhenClose)
{ {
this.Hide(); this.Hide();
} }

View File

@@ -489,7 +489,19 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" /> Classes="Margin8" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsHide2TrayWhenClose}" />
<ToggleSwitch
x:Name="togHide2TrayWhenClose"
Grid.Row="9"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock <TextBlock
Grid.Row="11" Grid.Row="11"
@@ -721,6 +733,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -794,6 +807,27 @@
Grid.Column="1" Grid.Column="1"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Classes="Margin8" /> Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
<TextBox
x:Name="txtLinuxSudoPassword"
Grid.Row="7"
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="7"
Grid.Column="2"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
TextWrapping="Wrap" />
</Grid> </Grid>
</DockPanel> </DockPanel>
</TabItem> </TabItem>

View File

@@ -131,6 +131,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);
@@ -152,6 +153,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);

View File

@@ -61,6 +61,7 @@
Width="54" Width="54"
Height="30" Height="30"
Margin="20,0" Margin="20,0"
Padding="2"
Classes="Tertiary" Classes="Tertiary"
Theme="{DynamicResource BorderlessSplitButton}" Theme="{DynamicResource BorderlessSplitButton}"
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"> ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">

View File

@@ -198,7 +198,7 @@ namespace v2rayN.Desktop.Views
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e) private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
{ {
var source = e.Source as Border; var source = e.Source as Border;
if (source == null || source.Name != "CellBorder") return; if (source?.Name == "HeaderBackground") return;
if (_config.UiItem.DoubleClick2Activate) if (_config.UiItem.DoubleClick2Activate)
{ {
ViewModel?.SetDefaultServer(); ViewModel?.SetDefaultServer();
@@ -356,7 +356,7 @@ namespace v2rayN.Desktop.Views
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel); item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel);
item2.DisplayIndex = displayIndex++; item2.DisplayIndex = displayIndex++;
} }
if (item.Name.StartsWith("to")) if (item.Name.ToLower().StartsWith("to"))
{ {
if (!_config.GuiItem.EnableStatistics) if (!_config.GuiItem.EnableStatistics)
{ {

View File

@@ -43,11 +43,11 @@ namespace v2rayN.Desktop.Views
{ {
rulesItem.Protocol?.ForEach(it => rulesItem.Protocol?.ForEach(it =>
{ {
clbProtocol.SelectedItems.Add(it); clbProtocol?.SelectedItems?.Add(it);
}); });
rulesItem.InboundTag?.ForEach(it => rulesItem.InboundTag?.ForEach(it =>
{ {
clbInboundTag.SelectedItems.Add(it); clbInboundTag?.SelectedItems?.Add(it);
}); });
} }

View File

@@ -15,7 +15,6 @@
mc:Ignorable="d"> mc:Ignorable="d">
<DockPanel> <DockPanel>
<StackPanel <StackPanel
Classes="Margin8" Classes="Margin8"
DockPanel.Dock="Top" DockPanel.Dock="Top"
@@ -55,7 +54,6 @@
Margin="8,0,0,0" /> Margin="8,0,0,0" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
HorizontalAlignment="Right" HorizontalAlignment="Right"
Classes="Margin8" Classes="Margin8"
@@ -134,9 +132,6 @@
</DataGrid> </DataGrid>
</TabItem> </TabItem>
</TabControl> </TabControl>
</DockPanel> </DockPanel>
</DockPanel> </DockPanel>
</Window> </Window>

View File

@@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
@@ -41,7 +42,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
}); });
spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator); //spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
@@ -77,6 +78,9 @@ namespace v2rayN.Desktop.Views
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{ {
desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.SystemProxyItem.SysProxyType); desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.SystemProxyItem.SysProxyType);
var iconslist = TrayIcon.GetIcons(Application.Current);
iconslist[0].Icon = desktop.MainWindow.Icon;
TrayIcon.SetIcons(Application.Current, iconslist);
} }
} }

View File

@@ -95,6 +95,41 @@
Classes="Margin8" Classes="Margin8"
TextWrapping="Wrap" TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" /> Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<Button
Grid.Row="2"
Grid.Column="2"
Width="30"
Height="30"
Margin="10,0"
Theme="{DynamicResource BorderlessButton}">
<Button.Content>
<PathIcon
Width="20"
Height="20"
Data="{StaticResource building_more}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Button.Content>
<Button.Flyout>
<Flyout>
<StackPanel>
<TextBlock
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
<TextBox
x:Name="txtMoreUrl"
Width="400"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="4"
TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@@ -245,24 +280,6 @@
Classes="Margin8" Classes="Margin8"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
Grid.Row="13"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
<TextBox
x:Name="txtMoreUrl"
Grid.Row="14"
Grid.Column="1"
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin8"
MinLines="4"
TextWrapping="Wrap"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</DockPanel> </DockPanel>

View File

@@ -33,7 +33,14 @@
Text="{x:Static resx:ResUI.TbSettingsColorMode}" /> Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
<ToggleSwitch x:Name="togDarkMode" Classes="Margin8" /> <ToggleSwitch x:Name="togDarkMode" Classes="Margin8" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Width="100"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsFollowSystemTheme}" />
<ToggleSwitch x:Name="togFollowSystemTheme" Classes="Margin8" />
</StackPanel>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBlock <TextBlock
Width="100" Width="100"

View File

@@ -29,6 +29,7 @@ namespace v2rayN.Desktop.Views
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.togFollowSystemTheme.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.SelectedValue).DisposeWith(disposables);
}); });

View File

@@ -20,16 +20,16 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.0" /> <PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.0" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.1" />
<PackageReference Include="Avalonia.Desktop" Version="11.2.0" /> <PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.0" /> <PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.0" /> <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.0" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" /> <PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
<PackageReference Include="MessageBox.Avalonia" Version="3.2.0" /> <PackageReference Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageReference Include="Semi.Avalonia" Version="11.2.0" /> <PackageReference Include="Semi.Avalonia" Version="11.2.1" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.2.0" /> <PackageReference Include="Semi.Avalonia.DataGrid" Version="11.2.1" />
<PackageReference Include="ReactiveUI" Version="20.1.63" /> <PackageReference Include="ReactiveUI" Version="20.1.63" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
</ItemGroup> </ItemGroup>

View File

@@ -5,8 +5,6 @@ VisualStudioVersion = 17.3.32811.315
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN", "v2rayN\v2rayN.csproj", "{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN", "v2rayN\v2rayN.csproj", "{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtosLib", "ProtosLib\ProtosLib.csproj", "{C5F24BB0-9CC1-44DD-82FF-D545F081819B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PacLib", "PacLib\PacLib.csproj", "{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PacLib", "PacLib\PacLib.csproj", "{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceLib", "ServiceLib\ServiceLib.csproj", "{1B6456C4-FFAA-4298-80F6-7B689A6E9243}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceLib", "ServiceLib\ServiceLib.csproj", "{1B6456C4-FFAA-4298-80F6-7B689A6E9243}"
@@ -25,10 +23,6 @@ Global
{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.Build.0 = Release|Any CPU {6DE127CA-1763-4236-B297-D2EF9CB2EC9B}.Release|Any CPU.Build.0 = Release|Any CPU
{C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5F24BB0-9CC1-44DD-82FF-D545F081819B}.Release|Any CPU.Build.0 = Release|Any CPU
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -1,9 +1,9 @@
<Application <Application
x:Class="v2rayN.App" x:Class="v2rayN.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:v2rayN.Converters" xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown" ShutdownMode="OnExplicitShutdown"
StartupUri="Views/MainWindow.xaml"> StartupUri="Views/MainWindow.xaml">
<Application.Resources> <Application.Resources>

View File

@@ -62,11 +62,12 @@ namespace v2rayN
BitmapSizeOptions.FromEmptyOptions()); BitmapSizeOptions.FromEmptyOptions());
} }
public static bool IsLightTheme() public static bool IsDarkTheme()
{ {
using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
var value = key?.GetValue("AppsUseLightTheme"); var obj = key?.GetValue("AppsUseLightTheme");
return value is int i && i > 0; int.TryParse(obj?.ToString(), out var value);
return value == 0;
} }
public static void RemoveTunDevice() public static void RemoveTunDevice()

View File

@@ -54,11 +54,6 @@ namespace v2rayN.Handler
{ {
try try
{ {
if (!config.RoutingBasicItem.EnableRoutingAdvanced)
{
return null;
}
var item = await ConfigHandler.GetDefaultRouting(config); var item = await ConfigHandler.GetDefaultRouting(config);
if (item == null || Utils.IsNullOrEmpty(item.CustomIcon) || !File.Exists(item.CustomIcon)) if (item == null || Utils.IsNullOrEmpty(item.CustomIcon) || !File.Exists(item.CustomIcon))
{ {

View File

@@ -38,7 +38,7 @@ namespace v2rayN.ViewModels
{ {
_config = AppHandler.Instance.Config; _config = AppHandler.Instance.Config;
RegisterSystemColorSet(_config, Application.Current.MainWindow, (bool bl) => { ModifyTheme(bl); }); RegisterSystemColorSet(_config, Application.Current.MainWindow, ModifyTheme);
BindingUI(); BindingUI();
RestoreUI(); RestoreUI();
@@ -46,15 +46,7 @@ namespace v2rayN.ViewModels
private void RestoreUI() private void RestoreUI()
{ {
if (FollowSystemTheme) ModifyTheme();
{
ModifyTheme(!WindowsUtils.IsLightTheme());
}
else
{
ModifyTheme(_config.UiItem.ColorModeDark);
}
if (!_config.UiItem.ColorPrimaryName.IsNullOrEmpty()) if (!_config.UiItem.ColorPrimaryName.IsNullOrEmpty())
{ {
var swatch = new SwatchesProvider().Swatches.FirstOrDefault(t => t.Name == _config.UiItem.ColorPrimaryName); var swatch = new SwatchesProvider().Swatches.FirstOrDefault(t => t.Name == _config.UiItem.ColorPrimaryName);
@@ -87,7 +79,7 @@ namespace v2rayN.ViewModels
if (_config.UiItem.ColorModeDark != ColorModeDark) if (_config.UiItem.ColorModeDark != ColorModeDark)
{ {
_config.UiItem.ColorModeDark = ColorModeDark; _config.UiItem.ColorModeDark = ColorModeDark;
ModifyTheme(ColorModeDark); ModifyTheme();
ConfigHandler.SaveConfig(_config); ConfigHandler.SaveConfig(_config);
} }
}); });
@@ -99,15 +91,8 @@ namespace v2rayN.ViewModels
if (_config.UiItem.FollowSystemTheme != FollowSystemTheme) if (_config.UiItem.FollowSystemTheme != FollowSystemTheme)
{ {
_config.UiItem.FollowSystemTheme = FollowSystemTheme; _config.UiItem.FollowSystemTheme = FollowSystemTheme;
ModifyTheme();
ConfigHandler.SaveConfig(_config); ConfigHandler.SaveConfig(_config);
if (FollowSystemTheme)
{
ModifyTheme(!WindowsUtils.IsLightTheme());
}
else
{
ModifyTheme(ColorModeDark);
}
} }
}); });
@@ -163,10 +148,11 @@ namespace v2rayN.ViewModels
}); });
} }
public void ModifyTheme(bool isDarkTheme) public void ModifyTheme()
{ {
var theme = _paletteHelper.GetTheme(); var theme = _paletteHelper.GetTheme();
var isDarkTheme = FollowSystemTheme ? WindowsUtils.IsDarkTheme() : ColorModeDark;
theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light); theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light);
_paletteHelper.SetTheme(theme); _paletteHelper.SetTheme(theme);
WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme); WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
@@ -183,7 +169,7 @@ namespace v2rayN.ViewModels
_paletteHelper.SetTheme(theme); _paletteHelper.SetTheme(theme);
} }
public void RegisterSystemColorSet(Config config, Window window, Action<bool> updateFunc) public void RegisterSystemColorSet(Config config, Window window, Action updateFunc)
{ {
var helper = new WindowInteropHelper(window); var helper = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle()); var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
@@ -196,7 +182,7 @@ namespace v2rayN.ViewModels
{ {
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
{ {
updateFunc?.Invoke(!WindowsUtils.IsLightTheme()); updateFunc?.Invoke();
} }
} }
} }

View File

@@ -34,7 +34,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -17,6 +17,13 @@
Style="{StaticResource WindowGlobal}" Style="{StaticResource WindowGlobal}"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
mc:Ignorable="d"> mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Popupbox.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<DockPanel Margin="{StaticResource Margin8}"> <DockPanel Margin="{StaticResource Margin8}">
<StackPanel <StackPanel
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
@@ -128,7 +135,7 @@
x:Name="txtPort" x:Name="txtPort"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
@@ -188,7 +195,7 @@
x:Name="txtAlterId" x:Name="txtAlterId"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
@@ -513,7 +520,7 @@
x:Name="cmbHeaderType8" x:Name="cmbHeaderType8"
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
@@ -606,7 +613,7 @@
x:Name="txtShortId9" x:Name="txtShortId9"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
@@ -653,7 +660,7 @@
x:Name="cmbNetwork" x:Name="cmbNetwork"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
@@ -672,13 +679,40 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbHeaderType}" /> Text="{x:Static resx:ResUI.TbHeaderType}" />
<ComboBox <StackPanel
x:Name="cmbHeaderType"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="100" VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Orientation="Horizontal">
Style="{StaticResource DefComboBox}" /> <ComboBox
x:Name="cmbHeaderType"
Width="200"
Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" />
<materialDesign:PopupBox
x:Name="popExtra"
HorizontalAlignment="Right"
StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}">
<StackPanel>
<TextBlock
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TransportExtraTip}" />
<TextBox
x:Name="txtExtra"
Width="400"
Margin="{StaticResource Margin4}"
VerticalAlignment="Top"
AcceptsReturn="True"
MinLines="6"
Style="{StaticResource MyOutlinedTextBox}"
TextWrapping="Wrap" />
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
<TextBlock <TextBlock
x:Name="tipHeaderType" x:Name="tipHeaderType"
Grid.Row="2" Grid.Row="2"
@@ -764,7 +798,7 @@
x:Name="cmbStreamSecurity" x:Name="cmbStreamSecurity"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
@@ -842,7 +876,7 @@
x:Name="cmbAllowInsecure" x:Name="cmbAllowInsecure"
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="100" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
</Grid> </Grid>

View File

@@ -202,6 +202,7 @@ namespace v2rayN.Views
this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.HeaderType, v => v.cmbHeaderType.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.RequestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
@@ -219,7 +220,7 @@ namespace v2rayN.Views
}); });
this.Title = $"{profileItem.ConfigType}"; this.Title = $"{profileItem.ConfigType}";
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
@@ -294,6 +295,13 @@ namespace v2rayN.Views
cmbHeaderType.Items.Add(it); cmbHeaderType.Items.Add(it);
}); });
} }
else if (network is nameof(ETransport.splithttp) or nameof(ETransport.xhttp))
{
Global.XhttpMode.ForEach(it =>
{
cmbHeaderType.Items.Add(it);
});
}
else if (network == nameof(ETransport.grpc)) else if (network == nameof(ETransport.grpc))
{ {
cmbHeaderType.Items.Add(Global.GrpcGunMode); cmbHeaderType.Items.Add(Global.GrpcGunMode);
@@ -314,6 +322,7 @@ namespace v2rayN.Views
network = Global.DefaultNetwork; network = Global.DefaultNetwork;
} }
labHeaderType.Visibility = Visibility.Visible; labHeaderType.Visibility = Visibility.Visible;
popExtra.Visibility = Visibility.Hidden;
tipRequestHost.Text = tipRequestHost.Text =
tipPath.Text = tipPath.Text =
tipHeaderType.Text = string.Empty; tipHeaderType.Text = string.Empty;
@@ -332,11 +341,19 @@ namespace v2rayN.Views
case nameof(ETransport.ws): case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade): case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2; tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1; tipPath.Text = ResUI.TransportPathTip1;
break; break;
case nameof(ETransport.splithttp):
case nameof(ETransport.xhttp):
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
tipPath.Text = ResUI.TransportPathTip1;
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
labHeaderType.Visibility = Visibility.Hidden;
popExtra.Visibility = Visibility.Visible;
break;
case nameof(ETransport.h2): case nameof(ETransport.h2):
tipRequestHost.Text = ResUI.TransportRequestHostTip3; tipRequestHost.Text = ResUI.TransportRequestHostTip3;
tipPath.Text = ResUI.TransportPathTip2; tipPath.Text = ResUI.TransportPathTip2;

View File

@@ -119,7 +119,6 @@
Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" /> Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
<materialDesign:PopupBox <materialDesign:PopupBox
Padding="8,0"
HorizontalAlignment="Right" HorizontalAlignment="Right"
StaysOpen="True" StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}"> Style="{StaticResource MaterialDesignToolForegroundPopupBox}">

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveUserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashConnectionsView" x:Class="v2rayN.Views.ClashConnectionsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450" d:DesignHeight="450"

View File

@@ -1,14 +1,14 @@
<reactiveui:ReactiveUserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashProxiesView" x:Class="v2rayN.Views.ClashProxiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
xmlns:converters="clr-namespace:v2rayN.Converters"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="vms:ClashProxiesViewModel" x:TypeArguments="vms:ClashProxiesViewModel"

View File

@@ -50,7 +50,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -30,7 +30,7 @@ namespace v2rayN.Views
HotkeyHandler.Instance.IsPause = true; HotkeyHandler.Instance.IsPause = true;
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
WindowsUtils.SetDarkBorder(this, _config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : _config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, _config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : _config.UiItem.ColorModeDark);
InitData(); InitData();
} }

View File

@@ -277,7 +277,7 @@
</Menu> </Menu>
<materialDesign:PopupBox <materialDesign:PopupBox
Padding="8,0" Padding="-2"
HorizontalAlignment="Right" HorizontalAlignment="Right"
StaysOpen="True" StaysOpen="True"
Style="{StaticResource MaterialDesignToolForegroundPopupBox}"> Style="{StaticResource MaterialDesignToolForegroundPopupBox}">

View File

@@ -76,8 +76,10 @@
HorizontalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
IsReadOnly="True" IsReadOnly="True"
IsReadOnlyCaretVisible="True" IsReadOnlyCaretVisible="True"
IsUndoEnabled="False"
TextAlignment="Left" TextAlignment="Left"
TextWrapping="Wrap" TextWrapping="Wrap"
UndoLimit="0"
VerticalScrollBarVisibility="Visible"> VerticalScrollBarVisibility="Visible">
<TextBox.ContextMenu> <TextBox.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}"> <ContextMenu Style="{StaticResource DefContextMenu}">

View File

@@ -175,7 +175,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -338,7 +338,7 @@ namespace v2rayN.Views
item2.Width = item.Width; item2.Width = item.Width;
item2.DisplayIndex = displayIndex++; item2.DisplayIndex = displayIndex++;
} }
if (item.Name.StartsWith("to")) if (item.Name.ToLower().StartsWith("to"))
{ {
if (!_config.GuiItem.EnableStatistics) if (!_config.GuiItem.EnableStatistics)
{ {

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow <reactiveui:ReactiveWindow
x:Class="v2rayN.Views.RoutingRuleDetailsWindow" x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}" Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}"

View File

@@ -58,7 +58,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow <reactiveui:ReactiveWindow
x:Class="v2rayN.Views.RoutingRuleSettingWindow" x:Class="v2rayN.Views.RoutingRuleSettingWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}" Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"

View File

@@ -60,7 +60,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -28,23 +28,6 @@
VerticalAlignment="Center" VerticalAlignment="Center"
ClipToBounds="True" ClipToBounds="True"
Style="{StaticResource MaterialDesignToolBar}"> Style="{StaticResource MaterialDesignToolBar}">
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuRoutingBasic" Padding="8,0">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon
Margin="{StaticResource MarginRight8}"
VerticalAlignment="Center"
Kind="Server" />
<TextBlock Text="{x:Static resx:ResUI.menuRoutingBasic}" />
</StackPanel>
</MenuItem.Header>
<MenuItem
x:Name="menuRoutingBasicImportRules"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRoutingBasicImportRules}" />
</MenuItem>
</Menu>
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0"> <MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
<MenuItem.Header> <MenuItem.Header>
@@ -66,16 +49,6 @@
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" /> Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
</MenuItem> </MenuItem>
</Menu> </Menu>
<!--<Separator />
<TextBlock
Margin="{StaticResource MarginLeft8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbenableRoutingAdvanced}" />
<ToggleButton
x:Name="togenableRoutingAdvanced"
Margin="{StaticResource MarginLeft8}"
HorizontalAlignment="Left" />-->
<Separator /> <Separator />
<TextBlock <TextBlock
Margin="{StaticResource MarginLeft8}" Margin="{StaticResource MarginLeft8}"
@@ -224,107 +197,6 @@
</DataGrid> </DataGrid>
</TabItem> </TabItem>
</TabControl> </TabControl>
<TabControl x:Name="tabBasic">
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabProxy}">
<Grid Margin="{StaticResource Margin8}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="Domain"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyDomain"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="IP"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtProxyIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabDirect}">
<Grid Margin="{StaticResource Margin8}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="Domain"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectDomain"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="IP"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtDirectIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
</TabItem>
<TabItem Header="{x:Static resx:ResUI.TbRoutingTabBlock}">
<Grid Margin="{StaticResource Margin8}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<GroupBox
Grid.Column="0"
Header="Domain"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtBlockDomain"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
<GroupBox
Grid.Column="2"
Header="IP"
Style="{StaticResource MyGroupBox}">
<TextBox
Name="txtBlockIP"
AcceptsReturn="True"
Style="{StaticResource DefTextBox}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</GroupBox>
</Grid>
</TabItem>
</TabControl>
</DockPanel> </DockPanel>
</DockPanel> </DockPanel>
</reactiveui:ReactiveWindow> </reactiveui:ReactiveWindow>

View File

@@ -39,24 +39,10 @@ namespace v2rayN.Views
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.lstRoutings.ItemsSource).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.lstRoutings.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
//this.Bind(ViewModel, vm => vm.enableRoutingAdvanced, v => v.togenableRoutingAdvanced.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainStrategy, v => v.cmbdomainStrategy.Text).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.domainMatcher, v => v.cmbdomainMatcher.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.domainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyDomain, v => v.txtProxyDomain.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ProxyIP, v => v.txtProxyIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectDomain, v => v.txtDirectDomain.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DirectIP, v => v.txtDirectIP.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BlockDomain, v => v.txtBlockDomain.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.BlockIP, v => v.txtBlockIP.Text).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.enableRoutingBasic, v => v.menuRoutingBasic.Visibility).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.enableRoutingAdvanced, v => v.menuRoutingAdvanced.Visibility).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.enableRoutingBasic, v => v.tabBasic.Visibility).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.enableRoutingAdvanced, v => v.tabAdvanced.Visibility).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingBasicImportRulesCmd, v => v.menuRoutingBasicImportRules).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedRemoveCmd, v => v.menuRoutingAdvancedRemove).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RoutingAdvancedRemoveCmd, v => v.menuRoutingAdvancedRemove).DisposeWith(disposables);
@@ -66,7 +52,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
@@ -102,11 +88,6 @@ namespace v2rayN.Views
private void RoutingSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e) private void RoutingSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{ {
if (ViewModel?.enableRoutingBasic ?? false)
{
return;
}
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{ {
if (e.Key == Key.A) if (e.Key == Key.A)

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow <reactiveui:ReactiveWindow
x:Class="v2rayN.Views.SubEditWindow" x:Class="v2rayN.Views.SubEditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net" xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuSubSetting}" Title="{x:Static resx:ResUI.menuSubSetting}"

View File

@@ -38,7 +38,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -31,7 +31,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? !WindowsUtils.IsLightTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark); WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.FollowSystemTheme ? WindowsUtils.IsDarkTheme() : AppHandler.Instance.Config.UiItem.ColorModeDark);
} }
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)

View File

@@ -1,10 +1,10 @@
<reactiveui:ReactiveUserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ThemeSettingView" x:Class="v2rayN.Views.ThemeSettingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:v2rayN.ViewModels" xmlns:vms="clr-namespace:v2rayN.ViewModels"
d:DesignHeight="450" d:DesignHeight="450"
@@ -44,7 +44,7 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsFollowSystemTheme}" /> Text="{x:Static resx:ResUI.TbSettingsFollowSystemTheme}" />
<ToggleButton <ToggleButton
x:Name="followSystemTheme" x:Name="togFollowSystemTheme"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Margin="{StaticResource Margin8}" /> Margin="{StaticResource Margin8}" />

View File

@@ -27,7 +27,7 @@ namespace v2rayN.Views
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.followSystemTheme.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.togFollowSystemTheme.IsChecked).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);