Compare commits

...

28 Commits
7.1.1 ... 7.2.0

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

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

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

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

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

* fix

* 移除自述

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

* 小修正

* 修正

* 更正自述

* 应该完成了

* 内嵌资源

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

* fix

* 移除自述

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

* 小修正

* 修正

* 更正自述

* 应该完成了
2024-11-17 19:42:14 +08:00
2dust
30a838df77 Bug fix
https://github.com/2dust/v2rayN/issues/6092
2024-11-17 16:18:46 +08:00
2dust
7cf9b9f57e up 7.1.2 2024-11-17 14:15:37 +08:00
2dust
736d995d4c up PackageReference 2024-11-17 14:11:51 +08:00
2dust
e335b2c0d6 Fix with AppendQuotes 2024-11-17 14:11:17 +08:00
2dust
96ae5517f6 Improve core msg 2024-11-17 09:58:57 +08:00
Slnanx
fb4b8d923a 可以通过判断系统语言来显示对应语言 (#6083) 2024-11-17 09:42:40 +08:00
2dust
2ade705e51 Bug fix 2024-11-16 20:15:05 +08:00
NagisaEfi
e0086b4b79 Update ResUI.zh-Hant.resx (#6080) 2024-11-16 10:34:55 +08:00
2dust
8f6d443104 Hide to tray when closing the window
https://github.com/2dust/v2rayN/issues/6076
2024-11-15 19:50:37 +08:00
75 changed files with 460 additions and 791 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,6 +20,7 @@
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
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 IPAPIUrl = "https://ipapi.co/json";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json";

View File

@@ -211,12 +211,12 @@
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)
{
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()

View File

@@ -65,10 +65,8 @@ namespace ServiceLib.Handler
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString();
}
}
config.RoutingBasicItem ??= new()
{
EnableRoutingAdvanced = true
};
config.RoutingBasicItem ??= new();
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
{
@@ -959,7 +957,6 @@ namespace ServiceLib.Handler
&& o.Address == n.Address
&& o.Port == n.Port
&& o.Id == n.Id
&& o.AlterId == n.AlterId
&& o.Security == n.Security
&& o.Network == n.Network
&& o.HeaderType == n.HeaderType
@@ -968,6 +965,10 @@ namespace ServiceLib.Handler
&& (o.ConfigType == EConfigType.Trojan || o.StreamSecurity == n.StreamSecurity)
&& o.Flow == n.Flow
&& o.Sni == n.Sni
&& o.Alpn == n.Alpn
&& o.Fingerprint == n.Fingerprint
&& o.PublicKey == n.PublicKey
&& o.ShortId == n.ShortId
&& (!remarks || o.Remarks == n.Remarks);
}
@@ -1295,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;
}
@@ -1597,7 +1612,7 @@ namespace ServiceLib.Handler
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
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);
return item2;
}
@@ -1671,6 +1686,15 @@ namespace ServiceLib.Handler
{
var ver = "V3-";
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)
{
return 0;
@@ -1711,11 +1735,6 @@ namespace ServiceLib.Handler
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)
{
await SQLiteHelper.Instance.DeleteAsync(routingItem);

View File

@@ -59,14 +59,16 @@ namespace ServiceLib.Handler
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
ShowMsg(true, result.Msg);
if (result.Success != true)
{
ShowMsg(true, result.Msg);
return;
}
else
{
ShowMsg(true, $"{node.GetSummary()}");
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
await CoreStop();
await Task.Delay(100);
await CoreStart(node);
@@ -100,6 +102,8 @@ namespace ServiceLib.Handler
ShowMsg(false, result.Msg);
if (result.Success)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
pid = await CoreStartSpeedtest(configPath, coreType);
}
return pid;
@@ -167,9 +171,6 @@ namespace ServiceLib.Handler
private async Task CoreStart(ProfileItem node)
{
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
_config.RunningCoreType = coreType;
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
@@ -229,9 +230,6 @@ namespace ServiceLib.Handler
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
{
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
ShowMsg(false, configPath);
try
{
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
@@ -261,7 +259,7 @@ namespace ServiceLib.Handler
return _config.TunModeItem.EnableTun
&& eCoreType == ECoreType.sing_box
&& Utils.IsLinux()
&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
;
}
@@ -277,7 +275,6 @@ namespace ServiceLib.Handler
return null;
}
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
try
{
Process proc = new()
@@ -296,13 +293,10 @@ namespace ServiceLib.Handler
}
};
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
if (isNeedSudo)
{
proc.StartInfo.FileName = $"/bin/sudo";
proc.StartInfo.Arguments = $"-S {fileName} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath))}";
proc.StartInfo.WorkingDirectory = null;
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
proc.StartInfo.RedirectStandardInput = true;
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
}
var startUpErrorMessage = new StringBuilder();
@@ -327,7 +321,7 @@ namespace ServiceLib.Handler
}
proc.Start();
if (isNeedSudo)
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
{
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
await Task.Delay(10);
@@ -363,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)
{
if (proc is null)

View File

@@ -165,7 +165,7 @@
private string PortableMode()
{
return $" -d \"{Utils.GetBinPath("")}\"";
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
}
}
}

View File

@@ -9,7 +9,7 @@
private ServerStatItem? _serverStatItem;
private List<ServerStatItem> _lstServerStat;
private Action<ServerSpeedItem>? _updateFunc;
//private StatisticsV2rayService? _statisticsV2Ray;
private StatisticsXrayService? _statisticsXray;
private StatisticsSingboxService? _statisticsSingbox;
@@ -26,7 +26,6 @@
await InitData();
//_statisticsV2Ray = new StatisticsV2rayService(config, UpdateServerStatHandler);
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
}
@@ -35,7 +34,6 @@
{
try
{
//_statisticsV2Ray?.Close();
_statisticsXray?.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()
{
await SQLiteHelper.Instance.ExecuteAsync($"delete from ServerStatItem where indexId not in ( select indexId from ProfileItem )");

View File

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

View File

@@ -20,6 +20,7 @@
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:
return true;
default:
return false;
}

View File

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

View File

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

View File

@@ -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>
/// 查找类似 RoutingRuleDetailsSetting 的本地化字符串。
/// </summary>
@@ -3103,6 +3085,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Hide to tray when closing the window 的本地化字符串。
/// </summary>
public static string TbSettingsHide2TrayWhenClose {
get {
return ResourceManager.GetString("TbSettingsHide2TrayWhenClose", resourceCulture);
}
}
/// <summary>
/// 查找类似 HTTP Port 的本地化字符串。
/// </summary>
@@ -3635,7 +3626,7 @@ namespace ServiceLib.Resx {
}
/// <summary>
/// 查找类似 The ping of current service: {0} ms 的本地化字符串。
/// 查找类似 The delay : {0} ms, {1} 的本地化字符串。
/// </summary>
public static string TestMeOutput {
get {

View File

@@ -302,7 +302,7 @@
<value>اسکن URL وارد کردن با موفقیت</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>پینگ سرویس فعلی: {0} ms</value>
<value>پینگ سرویس فعلی: {0} ms, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>موفقیت عملیات</value>
@@ -847,12 +847,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule</value>
</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">
<value>تطبیق دامنه</value>
</data>
@@ -1387,4 +1381,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -302,7 +302,7 @@
<value>Scan import the shared link successfully</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>The ping of current service: {0} ms</value>
<value>The delay : {0} ms, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>Operation success</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Set as active rule(Enter)</value>
</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">
<value>Domain Matcher</value>
</data>
@@ -1387,4 +1381,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -302,7 +302,7 @@
<value>Сканирование URL-адреса импорта успешна.</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>Задержка текущего сервера: {0} мс</value>
<value>Задержка текущего сервера: {0} мс, {1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>Операция успешна</value>
@@ -856,12 +856,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>Установить как активное правило</value>
</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">
<value>Сопоставитель доменов</value>
</data>
@@ -1387,4 +1381,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra raw JSON, format: { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>Hide to tray when closing the window</value>
</data>
</root>

View File

@@ -302,7 +302,7 @@
<value>扫描导入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>当前服务的真连接延迟: {0} ms</value>
<value>当前延迟: {0} ms{1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>设为活动规则 (Enter)</value>
</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">
<value>域名匹配算法</value>
</data>
@@ -1370,7 +1364,7 @@
<value>Linux系统的sudo密码</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密码已加密且只存储在本地文件中,无密码无法开启Tun</value>
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>请先在Tun模式设置中设置sudo密码</value>
@@ -1384,4 +1378,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>关闭窗口时隐藏至托盘</value>
</data>
</root>

View File

@@ -127,7 +127,7 @@
<value>設定格式不正確</value>
</data>
<data name="CustomServerTips" xml:space="preserve">
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
<value>注意,自訂設定完全依賴您自己的設定,不能使用所有設定功能。如需使用系統代理請手動修改聽埠。</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>下載開始...</value>
@@ -157,7 +157,7 @@
<value>請填寫正確格式伺服器埠</value>
</data>
<data name="FillLocalListeningPort" xml:space="preserve">
<value>請填寫本機聽埠</value>
<value>請填寫本機聽埠</value>
</data>
<data name="FillPassword" xml:space="preserve">
<value>請填寫密碼</value>
@@ -301,7 +301,7 @@
<value>掃描匯入分享链接成功</value>
</data>
<data name="TestMeOutput" xml:space="preserve">
<value>目前服務的真連線延遲: {0} ms</value>
<value>目前延遲: {0} ms{1}</value>
</data>
<data name="OperationSuccess" xml:space="preserve">
<value>操作成功</value>
@@ -722,7 +722,7 @@
<value>例外. 對於下列字元開頭的位址不使用代理設定檔:使用分號(;)分隔</value>
</data>
<data name="TbSettingsHttpPort" xml:space="preserve">
<value>本機HTTP聽埠</value>
<value>本機HTTP聽埠</value>
</data>
<data name="TbSettingsIgnoreGeoUpdateCore" xml:space="preserve">
<value>更新Core時忽略Geo檔案</value>
@@ -755,7 +755,7 @@
<value>開啟流量探測</value>
</data>
<data name="TbSettingsSocksPort" xml:space="preserve">
<value>本機SOCKS聽埠</value>
<value>本機SOCKS聽埠</value>
</data>
<data name="TbSettingsStartBoot" xml:space="preserve">
<value>開機啟動(可能會不成功)</value>
@@ -850,12 +850,6 @@
<data name="menuRoutingAdvancedSetDefault" xml:space="preserve">
<value>設為活動規則 (Enter)</value>
</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">
<value>域名匹配演算法</value>
</data>
@@ -998,7 +992,7 @@
<value>複製字型TTF/TTC檔案到目錄guiFonts重啟設定</value>
</data>
<data name="TbSettingsSocksPortTip" xml:space="preserve">
<value>http端口= +1Pac端口= +4*ray API端口= +5mihomo API端口= +6</value>
<value>http連接埠= +1Pac連接埠= +4*ray API連接埠= +5mihomo API連接埠= +6</value>
</data>
<data name="TbSettingsStartBootTip" xml:space="preserve">
<value>以管理員權限設定此項,在啟動後獲得管理員權限</value>
@@ -1094,7 +1088,7 @@
<value>請確保別名存在並且唯一</value>
</data>
<data name="TbSettingsEnableExInbound" xml:space="preserve">
<value>啟用額外監聽端口</value>
<value>啟用額外偵聽連接埠</value>
</data>
<data name="TbSettingsEnableIPv6Address" xml:space="preserve">
<value>啟用IPv6</value>
@@ -1154,7 +1148,7 @@
<value>您目前運行的是獨立包,請手動下載 SelfContained.7z檔案解壓縮覆蓋!</value>
</data>
<data name="TbPreSocksPort4Sub" xml:space="preserve">
<value>自訂設定的Socks端口</value>
<value>自訂設定的Socks連接埠</value>
</data>
<data name="menuBackupAndRestore" xml:space="preserve">
<value>備份和還原</value>
@@ -1370,7 +1364,7 @@
<value>Linux系統的sudo密碼</value>
</data>
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
<value>密碼已加密且只儲存在本機檔案中,無密碼無法開啟Tun</value>
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
</data>
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
<value>請先在Tun模式設定中設定sudo密碼</value>
@@ -1384,4 +1378,7 @@
<data name="TransportExtraTip" xml:space="preserve">
<value>XHTTP Extra 原始 JSON格式 { XHTTPObject }</value>
</data>
<data name="TbSettingsHide2TrayWhenClose" xml:space="preserve">
<value>關閉視窗時隱藏至托盤</value>
</data>
</root>

View File

@@ -4,11 +4,11 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>7.1.1</Version>
<Version>7.2.0</Version>
</PropertyGroup>
<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.Fody" Version="19.5.41" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
@@ -49,7 +49,6 @@
<ItemGroup>
<ProjectReference Include="..\PacLib\PacLib.csproj" />
<ProjectReference Include="..\ProtosLib\ProtosLib.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -90,8 +90,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.SingboxSampleClient);
string txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
var result = Utils.GetEmbedText(Global.SingboxSampleClient);
var txtOutbound = Utils.GetEmbedText(Global.SingboxSampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -119,10 +119,10 @@ namespace ServiceLib.Services.CoreConfig
await GenLog(singboxConfig);
//GenDns(new(), singboxConfig);
singboxConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
singboxConfig.inbounds.Clear();
singboxConfig.outbounds.RemoveAt(0);
int httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
var httpPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
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.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);
if (Utils.IsNotEmpty(routing.DomainStrategy4Singbox))
{
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
inbound.domain_strategy = routing.DomainStrategy4Singbox;
}
//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);
if (routing != null)
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules ?? [])
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
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 ?? [])
if (item.Enabled)
{
await GenRoutingUserRule(item, singboxConfig.route.rules);
}
@@ -1334,20 +1316,18 @@ namespace ServiceLib.Services.CoreConfig
//load custom ruleset file
List<Ruleset4Sbox> customRulesets = [];
if (_config.RoutingBasicItem.EnableRoutingAdvanced)
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
{
var routing = await ConfigHandler.GetDefaultRouting(_config);
if (Utils.IsNotEmpty(routing.CustomRulesetPath4Singbox))
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(result))
{
var result = Utils.LoadResource(routing.CustomRulesetPath4Singbox);
if (Utils.IsNotEmpty(result))
{
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
.Where(t => t.tag != null)
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
.Where(t => t.tag != null)
.Where(t => t.type != null)
.Where(t => t.format != null)
.ToList();
}
}

View File

@@ -216,8 +216,8 @@ namespace ServiceLib.Services.CoreConfig
ret.Msg = ResUI.InitialConfiguration;
string result = Utils.GetEmbedText(Global.V2raySampleClient);
string txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
var result = Utils.GetEmbedText(Global.V2raySampleClient);
var txtOutbound = Utils.GetEmbedText(Global.V2raySampleOutbound);
if (Utils.IsNullOrEmpty(result) || txtOutbound.IsNullOrEmpty())
{
ret.Msg = ResUI.FailedGetDefaultConfiguration;
@@ -244,10 +244,11 @@ namespace ServiceLib.Services.CoreConfig
}
await GenLog(v2rayConfig);
v2rayConfig.inbounds.Clear(); // Remove "proxy" service for speedtest, avoiding port conflicts.
v2rayConfig.outbounds.RemoveAt(0);
v2rayConfig.inbounds.Clear();
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)
{
@@ -270,7 +271,7 @@ namespace ServiceLib.Services.CoreConfig
//find unused port
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)
{
@@ -294,16 +295,6 @@ namespace ServiceLib.Services.CoreConfig
it.Port = port;
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
if (item is null)
{
@@ -326,6 +317,16 @@ namespace ServiceLib.Services.CoreConfig
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);
await GenOutbound(item, outbound);
outbound.tag = Global.ProxyTag + inbound.port.ToString();
@@ -466,33 +467,17 @@ namespace ServiceLib.Services.CoreConfig
v2rayConfig.routing.domainStrategy = _config.RoutingBasicItem.DomainStrategy;
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 (routing != null)
if (Utils.IsNotEmpty(routing.DomainStrategy))
{
if (Utils.IsNotEmpty(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);
}
}
v2rayConfig.routing.domainStrategy = routing.DomainStrategy;
}
}
else
{
var lockedItem = await ConfigHandler.GetLockedRoutingItem(_config);
if (lockedItem != null)
var rules = JsonUtils.Deserialize<List<RulesItem>>(routing.RuleSet);
foreach (var item in rules)
{
var rules = JsonUtils.Deserialize<List<RulesItem>>(lockedItem.RuleSet);
foreach (var item in rules)
if (item.Enabled)
{
var item2 = JsonUtils.Deserialize<RulesItem4Ray>(JsonUtils.Serialize(item));
await GenRoutingUserRule(item2, v2rayConfig);
@@ -1024,18 +1009,17 @@ namespace ServiceLib.Services.CoreConfig
//request Host
string request = Utils.GetEmbedText(Global.V2raySampleHttpRequestFileName);
string[] arrHost = host.Split(',');
string host2 = string.Join("\",\"", arrHost);
request = request.Replace("$requestHost$", $"\"{host2}\"");
//request = request.Replace("$requestHost$", string.Format("\"{0}\"", config.requestHost()));
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
string host2 = string.Join(",".AppendQuotes(), arrHost);
request = request.Replace("$requestHost$", $"{host2.AppendQuotes()}");
request = request.Replace("$requestUserAgent$", $"{useragent.AppendQuotes()}");
//Path
string pathHttp = @"/";
if (Utils.IsNotEmpty(node.Path))
{
string[] arrPath = node.Path.Split(',');
pathHttp = string.Join("\",\"", arrPath);
pathHttp = string.Join(",".AppendQuotes(), arrPath);
}
request = request.Replace("$requestPath$", $"\"{pathHttp}\"");
request = request.Replace("$requestPath$", $"{pathHttp.AppendQuotes()}");
tcpSettings.header.request = JsonUtils.Deserialize<object>(request);
streamSettings.tcpSettings = tcpSettings;

View File

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

View File

@@ -244,8 +244,17 @@ namespace ServiceLib.Services
public async Task RunAvailabilityCheck(Action<bool, string> updateFunc)
{
var time = await new DownloadService().RunAvailabilityCheck(null);
updateFunc?.Invoke(false, string.Format(ResUI.TestMeOutput, time));
var downloadHandle = new DownloadService();
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

View File

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

View File

@@ -324,6 +324,7 @@ namespace ServiceLib.ViewModels
if (process.Id > 0)
{
await MyAppExitAsync(false);
await MyAppExitAsync(false);
}
}

View File

@@ -53,6 +53,7 @@ namespace ServiceLib.ViewModels
[Reactive] public bool EnableUpdateSubOnlyRemarksExist { get; set; }
[Reactive] public bool EnableSecurityProtocolTls13 { get; set; }
[Reactive] public bool AutoHideStartup { get; set; }
[Reactive] public bool Hide2TrayWhenClose { get; set; }
[Reactive] public bool EnableDragDropSort { get; set; }
[Reactive] public bool DoubleClick2Activate { get; set; }
[Reactive] public int AutoUpdateInterval { get; set; }
@@ -166,6 +167,7 @@ namespace ServiceLib.ViewModels
EnableUpdateSubOnlyRemarksExist = _config.UiItem.EnableUpdateSubOnlyRemarksExist;
EnableSecurityProtocolTls13 = _config.GuiItem.EnableSecurityProtocolTls13;
AutoHideStartup = _config.UiItem.AutoHideStartup;
Hide2TrayWhenClose = _config.UiItem.Hide2TrayWhenClose;
EnableDragDropSort = _config.UiItem.EnableDragDropSort;
DoubleClick2Activate = _config.UiItem.DoubleClick2Activate;
AutoUpdateInterval = _config.GuiItem.AutoUpdateInterval;
@@ -316,6 +318,7 @@ namespace ServiceLib.ViewModels
_config.UiItem.EnableUpdateSubOnlyRemarksExist = EnableUpdateSubOnlyRemarksExist;
_config.GuiItem.EnableSecurityProtocolTls13 = EnableSecurityProtocolTls13;
_config.UiItem.AutoHideStartup = AutoHideStartup;
_config.UiItem.Hide2TrayWhenClose = Hide2TrayWhenClose;
_config.GuiItem.AutoUpdateInterval = AutoUpdateInterval;
_config.UiItem.EnableDragDropSort = EnableDragDropSort;
_config.UiItem.DoubleClick2Activate = DoubleClick2Activate;

View File

@@ -729,7 +729,7 @@ namespace ServiceLib.ViewModels
{
return;
}
var result = await CoreConfigHandler.GenerateClientConfig(item, null);
var result = await CoreConfigHandler.GenerateClientConfig(item, fileName);
if (result.Success != true)
{
NoticeHandler.Instance.Enqueue(result.Msg);

View File

@@ -7,9 +7,6 @@ namespace ServiceLib.ViewModels
{
public class RoutingSettingViewModel : MyReactiveObject
{
private RoutingItem _lockedItem;
private List<RulesItem> _lockedRules;
#region Reactive
private IObservableCollection<RoutingItemModel> _routingItems = new ObservableCollectionExtended<RoutingItemModel>();
@@ -20,12 +17,6 @@ namespace ServiceLib.ViewModels
public IList<RoutingItemModel> SelectedSources { get; set; }
[Reactive]
public bool enableRoutingAdvanced { get; set; }
[Reactive]
public bool enableRoutingBasic { get; set; }
[Reactive]
public string domainStrategy { get; set; }
@@ -35,25 +26,6 @@ namespace ServiceLib.ViewModels
[Reactive]
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> RoutingAdvancedRemoveCmd { get; }
public ReactiveCommand<Unit, Unit> RoutingAdvancedSetDefaultCmd { get; }
@@ -73,15 +45,6 @@ namespace ServiceLib.ViewModels
x => x.SelectedSource,
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 () =>
{
await RoutingAdvancedEditAsync(true);
@@ -111,67 +74,14 @@ namespace ServiceLib.ViewModels
{
SelectedSource = new();
enableRoutingAdvanced = true;//TODO _config.RoutingBasicItem.EnableRoutingAdvanced;
domainStrategy = _config.RoutingBasicItem.DomainStrategy;
domainMatcher = _config.RoutingBasicItem.DomainMatcher;
domainStrategy4Singbox = _config.RoutingBasicItem.DomainStrategy4Singbox;
await ConfigHandler.InitBuiltinRouting(_config);
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
public async Task RefreshRoutingItems()
@@ -205,12 +115,9 @@ namespace ServiceLib.ViewModels
private async Task SaveRoutingAsync()
{
_config.RoutingBasicItem.DomainStrategy = domainStrategy;
_config.RoutingBasicItem.EnableRoutingAdvanced = enableRoutingAdvanced;
_config.RoutingBasicItem.DomainMatcher = domainMatcher;
_config.RoutingBasicItem.DomainStrategy4Singbox = domainStrategy4Singbox;
await EndBindingLockedData();
if (await ConfigHandler.SaveConfig(_config) == 0)
{
NoticeHandler.Instance.Enqueue(ResUI.OperationSuccess);
@@ -224,18 +131,6 @@ namespace ServiceLib.ViewModels
#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)
{
RoutingItem item;

View File

@@ -347,11 +347,6 @@ namespace ServiceLib.ViewModels
public async Task RefreshRoutingsMenu()
{
_routingItems.Clear();
if (!_config.RoutingBasicItem.EnableRoutingAdvanced)
{
BlRouting = false;
return;
}
BlRouting = true;
var routings = await AppHandler.Instance.RoutingItems();
@@ -416,16 +411,16 @@ namespace ServiceLib.ViewModels
// When running as a non-administrator, reboot to administrator mode
if (EnableTun && AllowEnableTun() == false)
{
_config.TunModeItem.EnableTun = false;
if (Utils.IsWindows())
{
_config.TunModeItem.EnableTun = false;
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return;
}
else if (Utils.IsLinux())
{
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
}
return;
//else if (Utils.IsLinux())
//{
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
//}
}
await ConfigHandler.SaveConfig(_config);
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
@@ -474,7 +469,7 @@ namespace ServiceLib.ViewModels
}
else
{
InboundLanDisplay = $"{ResUI.LabLAN}:None";
InboundLanDisplay = $"{ResUI.LabLAN}:{Global.None}";
}
}

View File

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

View File

@@ -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.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.AllowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);

View File

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

View File

@@ -398,7 +398,7 @@ namespace v2rayN.Desktop.Views
}
else
{
if (Utils.IsWindows())
if (_config.UiItem.Hide2TrayWhenClose)
{
this.Hide();
}

View File

@@ -489,6 +489,18 @@
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbSettingsHide2TrayWhenClose}" />
<ToggleSwitch
x:Name="togHide2TrayWhenClose"
Grid.Row="9"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin8" />
<TextBlock

View File

@@ -131,6 +131,7 @@ namespace v2rayN.Desktop.Views
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
@@ -77,6 +78,9 @@ namespace v2rayN.Desktop.Views
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.SystemProxyItem.SysProxyType);
var iconslist = TrayIcon.GetIcons(Application.Current);
iconslist[0].Icon = desktop.MainWindow.Icon;
TrayIcon.SetIcons(Application.Current, iconslist);
}
}

View File

@@ -33,7 +33,14 @@
Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
<ToggleSwitch x:Name="togDarkMode" Classes="Margin8" />
</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">
<TextBlock
Width="100"

View File

@@ -29,6 +29,7 @@ namespace v2rayN.Desktop.Views
this.WhenActivated(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.CurrentLanguage, v => v.cmbCurrentLanguage.SelectedValue).DisposeWith(disposables);
});

View File

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

View File

@@ -5,8 +5,6 @@ VisualStudioVersion = 17.3.32811.315
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN", "v2rayN\v2rayN.csproj", "{6DE127CA-1763-4236-B297-D2EF9CB2EC9B}"
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}"
EndProject
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}.Release|Any CPU.ActiveCfg = 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.Build.0 = Debug|Any CPU
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -1,9 +1,9 @@
<Application
x:Class="v2rayN.App"
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:conv="clr-namespace:v2rayN.Converters"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
ShutdownMode="OnExplicitShutdown"
StartupUri="Views/MainWindow.xaml">
<Application.Resources>

View File

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

View File

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

View File

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

View File

@@ -34,7 +34,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.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)

View File

@@ -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.Path, v => v.txtPath.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Extra, v => v.txtExtra.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.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}";
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)

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashConnectionsView"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450"

View File

@@ -1,14 +1,14 @@
<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashProxiesView"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
xmlns:converters="clr-namespace:v2rayN.Converters"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="vms:ClashProxiesViewModel"

View File

@@ -50,7 +50,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.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)

View File

@@ -30,7 +30,7 @@ namespace v2rayN.Views
HotkeyHandler.Instance.IsPause = true;
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();
}

View File

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

View File

@@ -175,7 +175,7 @@ namespace v2rayN.Views
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)

View File

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

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow
x:Class="v2rayN.Views.RoutingRuleDetailsWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}"

View File

@@ -58,7 +58,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});
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)

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow
x:Class="v2rayN.Views.RoutingRuleSettingWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"

View File

@@ -60,7 +60,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});
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)

View File

@@ -28,23 +28,6 @@
VerticalAlignment="Center"
ClipToBounds="True"
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}">
<MenuItem x:Name="menuRoutingAdvanced" Padding="8,0">
<MenuItem.Header>
@@ -66,16 +49,6 @@
Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
</MenuItem>
</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 />
<TextBlock
Margin="{StaticResource MarginLeft8}"
@@ -224,107 +197,6 @@
</DataGrid>
</TabItem>
</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>
</reactiveui:ReactiveWindow>

View File

@@ -39,24 +39,10 @@ namespace v2rayN.Views
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.enableRoutingAdvanced, v => v.togenableRoutingAdvanced.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainStrategy, v => v.cmbdomainStrategy.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainMatcher, v => v.cmbdomainMatcher.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.domainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.Text).DisposeWith(disposables);
this.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.menuRoutingAdvancedAdd2).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);
});
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)
@@ -102,11 +88,6 @@ namespace v2rayN.Views
private void RoutingSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (ViewModel?.enableRoutingBasic ?? false)
{
return;
}
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
if (e.Key == Key.A)

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveWindow
x:Class="v2rayN.Views.SubEditWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
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:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuSubSetting}"

View File

@@ -38,7 +38,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
});
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)

View File

@@ -31,7 +31,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.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)

View File

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

View File

@@ -27,7 +27,7 @@ namespace v2rayN.Views
this.WhenActivated(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.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables);