Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05d446ed37 | ||
|
|
7a0b068642 | ||
|
|
c0ef8c09af | ||
|
|
a2db6dd468 | ||
|
|
471bc0f65d | ||
|
|
80f840a7c2 | ||
|
|
a2413fdf23 | ||
|
|
9cbe2b938c | ||
|
|
e915726c52 | ||
|
|
b11e68cfd8 | ||
|
|
bee66d06dd | ||
|
|
945a0add96 | ||
|
|
294cabcf05 | ||
|
|
22eb993ebf | ||
|
|
b5e1a297ae | ||
|
|
499a16feae | ||
|
|
1866a59d12 | ||
|
|
10513e0f3b | ||
|
|
2e32de2fbb | ||
|
|
30a838df77 |
18
README.md
18
README.md
@@ -1,5 +1,5 @@
|
|||||||
# v2rayN
|
# v2rayN
|
||||||
A GUI client for Windows and Linux, 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)
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/2dust/v2rayN/commits/master)
|
[](https://github.com/2dust/v2rayN/commits/master)
|
||||||
@@ -9,13 +9,19 @@ A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/
|
|||||||
|
|
||||||
|
|
||||||
## 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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
14
v2rayN/AmazTool/Assets/en-US.json
Normal file
14
v2rayN/AmazTool/Assets/en-US.json
Normal 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"
|
||||||
|
}
|
||||||
14
v2rayN/AmazTool/Assets/zh-CN.json
Normal file
14
v2rayN/AmazTool/Assets/zh-CN.json
Normal 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": "提示"
|
||||||
|
}
|
||||||
@@ -1,131 +1,59 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace AmazTool
|
namespace AmazTool
|
||||||
{
|
{
|
||||||
public class LocalizationHelper
|
public class LocalizationHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
private static Dictionary<string, string> _languageResources = [];
|
||||||
/// 获取系统当前语言的本地化字符串
|
|
||||||
/// </summary>
|
static LocalizationHelper()
|
||||||
/// <param name="key">要翻译的关键字</param>
|
|
||||||
/// <returns>对应语言的本地化字符串,如果没有找到则返回关键字</returns>
|
|
||||||
public static string GetLocalizedValue(string key)
|
|
||||||
{
|
{
|
||||||
// 定义支持的语言
|
// 加载语言资源
|
||||||
HashSet<string> supportedLanguages = ["zh", "en"];
|
LoadLanguageResources();
|
||||||
|
|
||||||
// 获取当前系统语言的 ISO 两字母代码
|
|
||||||
string currentLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
|
|
||||||
|
|
||||||
// 如果当前语言不在支持的语言列表中,默认使用英文
|
|
||||||
if (!supportedLanguages.Contains(currentLanguage))
|
|
||||||
{
|
|
||||||
currentLanguage = "en";
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试获取对应语言的翻译
|
|
||||||
if (languageResources.TryGetValue(key, out var translations))
|
|
||||||
{
|
|
||||||
if (translations.TryGetValue(currentLanguage, out var translation))
|
|
||||||
{
|
|
||||||
return translation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果未找到翻译,返回关键字本身
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static void LoadLanguageResources()
|
||||||
/// 存储不同语言的本地化资源
|
|
||||||
/// </summary>
|
|
||||||
public static Dictionary<string, Dictionary<string, string>> languageResources = new()
|
|
||||||
{
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
"Guidelines", new Dictionary<string, string>
|
var currentLanguage = CultureInfo.CurrentCulture.Name;
|
||||||
|
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
||||||
{
|
{
|
||||||
{ "en", "Please run it from the main application." },
|
currentLanguage = "en-US";
|
||||||
{ "zh", "请从主应用运行!" }
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
var resourceName = $"AmazTool.Assets.{currentLanguage}.json";
|
||||||
"Upgrade_File_Not_Found", new Dictionary<string, string>
|
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))
|
||||||
{
|
{
|
||||||
{ "en", "Upgrade failed, file not found." },
|
_languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
|
||||||
{ "zh", "升级失败,文件不存在!" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"In_Progress", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "In progress, please wait..." },
|
|
||||||
{ "zh", "正在进行中,请等待..." }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Try_Terminate_Process", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Try to terminate the v2rayN process." },
|
|
||||||
{ "zh", "尝试结束 v2rayN 进程..." }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Failed_Terminate_Process", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail." },
|
|
||||||
{ "zh", "请手动关闭正在运行的v2rayN,否则可能升级失败。" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Start_Unzipping", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Start extracting the update package." },
|
|
||||||
{ "zh", "开始解压缩更新包..." }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Success_Unzipping", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Successfully extracted the update package!" },
|
|
||||||
{ "zh", "解压缩更新包成功!" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Failed_Unzipping", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Failed to extract the update package!" },
|
|
||||||
{ "zh", "解压缩更新包失败!" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Failed_Upgrade", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Upgrade failed!" },
|
|
||||||
{ "zh", "升级失败!" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Success_Upgrade", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Upgrade success!" },
|
|
||||||
{ "zh", "升级成功!" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Information", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Information" },
|
|
||||||
{ "zh", "提示" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Restart_v2rayN", new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "en", "Start v2rayN, please wait..." },
|
|
||||||
{ "zh", "正在重启,请等待..." }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
namespace AmazTool
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace AmazTool
|
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace AmazTool
|
namespace AmazTool
|
||||||
{
|
{
|
||||||
@@ -11,9 +8,9 @@ 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}");
|
||||||
|
|
||||||
Thread.Sleep(9000);
|
Waiting(9);
|
||||||
|
|
||||||
if (!File.Exists(fileName))
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
@@ -27,8 +24,12 @@ namespace AmazTool
|
|||||||
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)
|
||||||
@@ -90,7 +91,7 @@ namespace AmazTool
|
|||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
|
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
|
||||||
Thread.Sleep(9000);
|
Waiting(9);
|
||||||
Process process = new()
|
Process process = new()
|
||||||
{
|
{
|
||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
@@ -123,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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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>
|
|
||||||
@@ -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 {}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using ProtosLib.Statistics;
|
|
||||||
|
|
||||||
namespace ProtosLib
|
|
||||||
{
|
|
||||||
public class Tests
|
|
||||||
{
|
|
||||||
private StatsService.StatsServiceClient client_;
|
|
||||||
|
|
||||||
public Tests()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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";
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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))
|
||||||
{
|
{
|
||||||
@@ -1298,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1600,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;
|
||||||
}
|
}
|
||||||
@@ -1674,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;
|
||||||
@@ -1714,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);
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ namespace ServiceLib.Handler
|
|||||||
return _config.TunModeItem.EnableTun
|
return _config.TunModeItem.EnableTun
|
||||||
&& eCoreType == ECoreType.sing_box
|
&& eCoreType == ECoreType.sing_box
|
||||||
&& Utils.IsLinux()
|
&& Utils.IsLinux()
|
||||||
&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +275,6 @@ namespace ServiceLib.Handler
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process proc = new()
|
Process proc = new()
|
||||||
@@ -294,14 +293,10 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||||
if (isNeedSudo)
|
if (isNeedSudo)
|
||||||
{
|
{
|
||||||
proc.StartInfo.FileName = $"/bin/sudo";
|
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
|
||||||
proc.StartInfo.Arguments = $"-S {fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
|
||||||
proc.StartInfo.WorkingDirectory = null;
|
|
||||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
|
||||||
proc.StartInfo.RedirectStandardInput = true;
|
|
||||||
Logging.SaveLog(proc.StartInfo.Arguments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var startUpErrorMessage = new StringBuilder();
|
var startUpErrorMessage = new StringBuilder();
|
||||||
@@ -326,7 +321,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
proc.Start();
|
proc.Start();
|
||||||
|
|
||||||
if (isNeedSudo)
|
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
@@ -362,6 +357,37 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
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 StatisticsXrayService? _statisticsXray;
|
||||||
private StatisticsSingboxService? _statisticsSingbox;
|
private StatisticsSingboxService? _statisticsSingbox;
|
||||||
|
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
await InitData();
|
await InitData();
|
||||||
|
|
||||||
//_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
|
|
||||||
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
||||||
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,6 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//_statisticsV2Ray?.Close();
|
|
||||||
_statisticsXray?.Close();
|
_statisticsXray?.Close();
|
||||||
_statisticsSingbox?.Close();
|
_statisticsSingbox?.Close();
|
||||||
}
|
}
|
||||||
@@ -67,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 )");
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,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]
|
||||||
|
|||||||
13
v2rayN/ServiceLib/Models/IPAPIInfo.cs
Normal file
13
v2rayN/ServiceLib/Models/IPAPIInfo.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
20
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
20
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -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>
|
||||||
@@ -3644,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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -1370,7 +1364,7 @@
|
|||||||
<value>Linux系统的sudo密码</value>
|
<value>Linux系统的sudo密码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>密码已加密且只存储在本地文件中,无密码无法开启Tun</value>
|
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>请先在Tun模式设置中设置sudo密码</value>
|
<value>请先在Tun模式设置中设置sudo密码</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>
|
||||||
@@ -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>
|
||||||
@@ -1370,7 +1364,7 @@
|
|||||||
<value>Linux系統的sudo密碼</value>
|
<value>Linux系統的sudo密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>密碼已加密且只儲存在本機檔案中,無密碼無法開啟Tun</value>
|
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>請先在Tun模式設定中設定sudo密碼</value>
|
<value>請先在Tun模式設定中設定sudo密碼</value>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>7.1.2</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" />
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -216,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;
|
||||||
@@ -244,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)
|
||||||
{
|
{
|
||||||
@@ -270,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)
|
||||||
{
|
{
|
||||||
@@ -294,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)
|
||||||
{
|
{
|
||||||
@@ -326,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();
|
||||||
@@ -466,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);
|
||||||
|
|||||||
@@ -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
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ namespace ServiceLib.ViewModels
|
|||||||
if (process.Id > 0)
|
if (process.Id > 0)
|
||||||
{
|
{
|
||||||
await MyAppExitAsync(false);
|
await MyAppExitAsync(false);
|
||||||
|
await MyAppExitAsync(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -729,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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -416,16 +411,16 @@ namespace ServiceLib.ViewModels
|
|||||||
// When running as a non-administrator, reboot to administrator mode
|
// When running as a non-administrator, reboot to administrator mode
|
||||||
if (EnableTun && AllowEnableTun() == false)
|
if (EnableTun && AllowEnableTun() == false)
|
||||||
{
|
{
|
||||||
_config.TunModeItem.EnableTun = false;
|
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
|
_config.TunModeItem.EnableTun = false;
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
//else if (Utils.IsLinux())
|
||||||
{
|
//{
|
||||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||||
}
|
//}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
await ConfigHandler.SaveConfig(_config);
|
await ConfigHandler.SaveConfig(_config);
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||||
@@ -474,7 +469,7 @@ namespace ServiceLib.ViewModels
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InboundLanDisplay = $"{ResUI.LabLAN}:None";
|
InboundLanDisplay = $"{ResUI.LabLAN}:{Global.None}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
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.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);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ namespace v2rayN.Desktop.Views
|
|||||||
#endregion Event
|
#endregion Event
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
public void ShowHideWindow(bool? blShow)
|
public void ShowHideWindow(bool? blShow)
|
||||||
{
|
{
|
||||||
var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
|
var bl = blShow ?? !_config.UiItem.ShowInTaskbar;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ namespace v2rayN.Views
|
|||||||
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.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);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.Text).DisposeWith(disposables);
|
||||||
@@ -220,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)
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}">
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}" />
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user