mirror of
https://github.com/2dust/v2rayN.git
synced 2025-05-10 18:31:54 +00:00
Compare commits
No commits in common. "master" and "7.11.2" have entirely different histories.
46 changed files with 368 additions and 623 deletions
|
@ -5,83 +5,21 @@ internal static class Program
|
||||||
[STAThread]
|
[STAThread]
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
try
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
// If no arguments are provided, display usage guidelines and exit
|
Console.WriteLine(Resx.Resource.Guidelines);
|
||||||
if (args.Length == 0)
|
Thread.Sleep(5000);
|
||||||
{
|
return;
|
||||||
ShowHelp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log all arguments for debugging purposes
|
|
||||||
foreach (var arg in args)
|
|
||||||
{
|
|
||||||
Console.WriteLine(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse command based on first argument
|
|
||||||
switch (args[0].ToLowerInvariant())
|
|
||||||
{
|
|
||||||
case "rebootas":
|
|
||||||
// Handle application restart
|
|
||||||
HandleRebootAsync();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "help":
|
|
||||||
case "--help":
|
|
||||||
case "-h":
|
|
||||||
case "/?":
|
|
||||||
// Display help information
|
|
||||||
ShowHelp();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Default behavior: handle as upgrade data
|
|
||||||
// Maintain backward compatibility with existing usage pattern
|
|
||||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
|
||||||
HandleUpgrade(argData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||||
|
if (argData.Equals("rebootas"))
|
||||||
{
|
{
|
||||||
// Global exception handling
|
Thread.Sleep(1000);
|
||||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
Utils.StartV2RayN();
|
||||||
Console.WriteLine("Press any key to exit...");
|
return;
|
||||||
Console.ReadKey();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
UpgradeApp.Upgrade(argData);
|
||||||
/// Display help information and usage guidelines
|
|
||||||
/// </summary>
|
|
||||||
private static void ShowHelp()
|
|
||||||
{
|
|
||||||
Console.WriteLine(Resx.Resource.Guidelines);
|
|
||||||
Console.WriteLine("Available commands:");
|
|
||||||
Console.WriteLine(" rebootas - Restart the application");
|
|
||||||
Console.WriteLine(" help - Display this help information");
|
|
||||||
Thread.Sleep(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handle application restart
|
|
||||||
/// </summary>
|
|
||||||
private static void HandleRebootAsync()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Restarting application...");
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
Utils.StartV2RayN();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handle application upgrade with the provided data
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="upgradeData">Data for the upgrade process</param>
|
|
||||||
private static void HandleUpgrade(string upgradeData)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Upgrading application...");
|
|
||||||
UpgradeApp.Upgrade(upgradeData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.12.1</Version>
|
<Version>7.11.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.7" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.7" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.7" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.0" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.7" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
<PackageVersion Include="CliWrap" Version="3.8.2" />
|
||||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
<PackageVersion Include="Downloader" Version="3.3.4" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
|
@ -18,8 +18,8 @@
|
||||||
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI" Version="20.2.45" />
|
||||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.2.45" />
|
||||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.7" />
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.6" />
|
||||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.7" />
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.6" />
|
||||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
||||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
<PackageVersion Include="TaskScheduler" Version="2.12.1" />
|
||||||
|
|
|
@ -20,7 +20,6 @@ public enum EViewAction
|
||||||
BrowseServer,
|
BrowseServer,
|
||||||
ImportRulesFromFile,
|
ImportRulesFromFile,
|
||||||
InitSettingFont,
|
InitSettingFont,
|
||||||
PasswordInput,
|
|
||||||
SubEditWindow,
|
SubEditWindow,
|
||||||
RoutingRuleSettingWindow,
|
RoutingRuleSettingWindow,
|
||||||
RoutingRuleDetailsWindow,
|
RoutingRuleDetailsWindow,
|
||||||
|
|
|
@ -9,6 +9,7 @@ public sealed class AppHandler
|
||||||
private int? _statePort;
|
private int? _statePort;
|
||||||
private int? _statePort2;
|
private int? _statePort2;
|
||||||
private Job? _processJob;
|
private Job? _processJob;
|
||||||
|
private bool? _isAdministrator;
|
||||||
public static AppHandler Instance => _instance.Value;
|
public static AppHandler Instance => _instance.Value;
|
||||||
public Config Config => _config;
|
public Config Config => _config;
|
||||||
|
|
||||||
|
@ -30,7 +31,14 @@ public sealed class AppHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LinuxSudoPwd { get; set; }
|
public bool IsAdministrator
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_isAdministrator ??= Utils.IsAdministrator();
|
||||||
|
return _isAdministrator.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Property
|
#endregion Property
|
||||||
|
|
||||||
|
|
|
@ -799,11 +799,8 @@ public class ConfigHandler
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
var lstServerStat = (config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
|
||||||
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||||
var lstProfile = (from t in lstModel
|
var lstProfile = (from t in lstModel
|
||||||
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
|
||||||
from t22 in t2b.DefaultIfEmpty()
|
|
||||||
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
||||||
from t33 in t3b.DefaultIfEmpty()
|
from t33 in t3b.DefaultIfEmpty()
|
||||||
select new ProfileItemModel
|
select new ProfileItemModel
|
||||||
|
@ -818,11 +815,7 @@ public class ConfigHandler
|
||||||
StreamSecurity = t.StreamSecurity,
|
StreamSecurity = t.StreamSecurity,
|
||||||
Delay = t33?.Delay ?? 0,
|
Delay = t33?.Delay ?? 0,
|
||||||
Speed = t33?.Speed ?? 0,
|
Speed = t33?.Speed ?? 0,
|
||||||
Sort = t33?.Sort ?? 0,
|
Sort = t33?.Sort ?? 0
|
||||||
TodayDown = (t22?.TodayDown ?? 0).ToString("D16"),
|
|
||||||
TodayUp = (t22?.TodayUp ?? 0).ToString("D16"),
|
|
||||||
TotalDown = (t22?.TotalDown ?? 0).ToString("D16"),
|
|
||||||
TotalUp = (t22?.TotalUp ?? 0).ToString("D16"),
|
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
Enum.TryParse(colName, true, out EServerColName name);
|
Enum.TryParse(colName, true, out EServerColName name);
|
||||||
|
@ -840,10 +833,6 @@ public class ConfigHandler
|
||||||
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
||||||
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
||||||
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
||||||
EServerColName.TodayDown => lstProfile.OrderBy(t => t.TodayDown).ToList(),
|
|
||||||
EServerColName.TodayUp => lstProfile.OrderBy(t => t.TodayUp).ToList(),
|
|
||||||
EServerColName.TotalDown => lstProfile.OrderBy(t => t.TotalDown).ToList(),
|
|
||||||
EServerColName.TotalUp => lstProfile.OrderBy(t => t.TotalUp).ToList(),
|
|
||||||
_ => lstProfile
|
_ => lstProfile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -860,10 +849,6 @@ public class ConfigHandler
|
||||||
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
||||||
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
||||||
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
||||||
EServerColName.TodayDown => lstProfile.OrderByDescending(t => t.TodayDown).ToList(),
|
|
||||||
EServerColName.TodayUp => lstProfile.OrderByDescending(t => t.TodayUp).ToList(),
|
|
||||||
EServerColName.TotalDown => lstProfile.OrderByDescending(t => t.TotalDown).ToList(),
|
|
||||||
EServerColName.TotalUp => lstProfile.OrderByDescending(t => t.TotalUp).ToList(),
|
|
||||||
_ => lstProfile
|
_ => lstProfile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
|
||||||
using CliWrap;
|
|
||||||
|
|
||||||
namespace ServiceLib.Handler;
|
|
||||||
|
|
||||||
public class CoreAdminHandler
|
|
||||||
{
|
|
||||||
private static readonly Lazy<CoreAdminHandler> _instance = new(() => new());
|
|
||||||
public static CoreAdminHandler Instance => _instance.Value;
|
|
||||||
private Config _config;
|
|
||||||
private Action<bool, string>? _updateFunc;
|
|
||||||
private int _linuxSudoPid = -1;
|
|
||||||
|
|
||||||
public async Task Init(Config config, Action<bool, string> updateFunc)
|
|
||||||
{
|
|
||||||
if (_config != null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_config = config;
|
|
||||||
_updateFunc = updateFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateFunc(bool notify, string msg)
|
|
||||||
{
|
|
||||||
_updateFunc?.Invoke(notify, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Process?> RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath)
|
|
||||||
{
|
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
|
||||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
|
||||||
|
|
||||||
Process proc = new()
|
|
||||||
{
|
|
||||||
StartInfo = new()
|
|
||||||
{
|
|
||||||
FileName = shFilePath,
|
|
||||||
Arguments = "",
|
|
||||||
WorkingDirectory = Utils.GetBinConfigPath(),
|
|
||||||
UseShellExecute = false,
|
|
||||||
RedirectStandardInput = true,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
CreateNoWindow = true,
|
|
||||||
StandardInputEncoding = Encoding.UTF8,
|
|
||||||
StandardOutputEncoding = Encoding.UTF8,
|
|
||||||
StandardErrorEncoding = Encoding.UTF8,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
proc.Start();
|
|
||||||
proc.BeginOutputReadLine();
|
|
||||||
proc.BeginErrorReadLine();
|
|
||||||
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync();
|
|
||||||
await Task.Delay(10);
|
|
||||||
await proc.StandardInput.WriteLineAsync(AppHandler.Instance.LinuxSudoPwd);
|
|
||||||
|
|
||||||
await Task.Delay(100);
|
|
||||||
if (proc is null or { HasExited: true })
|
|
||||||
{
|
|
||||||
throw new Exception(ResUI.FailedToRunCore);
|
|
||||||
}
|
|
||||||
|
|
||||||
_linuxSudoPid = proc.Id;
|
|
||||||
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task KillProcessAsLinuxSudo()
|
|
||||||
{
|
|
||||||
if (_linuxSudoPid < 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}";
|
|
||||||
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
|
|
||||||
|
|
||||||
await Cli.Wrap(shFilePath)
|
|
||||||
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
|
|
||||||
.ExecuteAsync();
|
|
||||||
|
|
||||||
_linuxSudoPid = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
|
||||||
{
|
|
||||||
var shFilePath = Utils.GetBinConfigPath(fileName);
|
|
||||||
File.Delete(shFilePath);
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("#!/bin/sh");
|
|
||||||
if (Utils.IsAdministrator())
|
|
||||||
{
|
|
||||||
sb.AppendLine($"{cmdLine}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.AppendLine($"sudo -S {cmdLine}");
|
|
||||||
}
|
|
||||||
|
|
||||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
|
||||||
await Utils.SetLinuxChmod(shFilePath);
|
|
||||||
|
|
||||||
return shFilePath;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ public class CoreHandler
|
||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
private Process? _processPre;
|
private Process? _processPre;
|
||||||
private bool _linuxSudo = false;
|
private int _linuxSudoPid = -1;
|
||||||
private Action<bool, string>? _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
private const string _tag = "CoreHandler";
|
private const string _tag = "CoreHandler";
|
||||||
|
|
||||||
|
@ -155,23 +155,23 @@ public class CoreHandler
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_linuxSudo)
|
|
||||||
{
|
|
||||||
await CoreAdminHandler.Instance.KillProcessAsLinuxSudo();
|
|
||||||
_linuxSudo = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_process != null)
|
if (_process != null)
|
||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(_process, Utils.IsWindows());
|
await ProcUtils.ProcessKill(_process, true);
|
||||||
_process = null;
|
_process = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_processPre != null)
|
if (_processPre != null)
|
||||||
{
|
{
|
||||||
await ProcUtils.ProcessKill(_processPre, Utils.IsWindows());
|
await ProcUtils.ProcessKill(_processPre, true);
|
||||||
_processPre = null;
|
_processPre = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_linuxSudoPid > 0)
|
||||||
|
{
|
||||||
|
await KillProcessAsLinuxSudo();
|
||||||
|
}
|
||||||
|
_linuxSudoPid = -1;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -225,6 +225,15 @@ public class CoreHandler
|
||||||
_updateFunc?.Invoke(notify, msg);
|
_updateFunc?.Invoke(notify, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsNeedSudo(ECoreType eCoreType)
|
||||||
|
{
|
||||||
|
return _config.TunModeItem.EnableTun
|
||||||
|
&& eCoreType == ECoreType.sing_box
|
||||||
|
&& (Utils.IsNonWindows())
|
||||||
|
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Private
|
#endregion Private
|
||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
@ -240,17 +249,69 @@ public class CoreHandler
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (mayNeedSudo
|
Process proc = new()
|
||||||
&& _config.TunModeItem.EnableTun
|
|
||||||
&& coreInfo.CoreType == ECoreType.sing_box
|
|
||||||
&& Utils.IsNonWindows())
|
|
||||||
{
|
{
|
||||||
_linuxSudo = true;
|
StartInfo = new()
|
||||||
await CoreAdminHandler.Instance.Init(_config, _updateFunc);
|
{
|
||||||
return await CoreAdminHandler.Instance.RunProcessAsLinuxSudo(fileName, coreInfo, configPath);
|
FileName = fileName,
|
||||||
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||||
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = displayLog,
|
||||||
|
RedirectStandardError = displayLog,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
|
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||||
|
if (isNeedSudo)
|
||||||
|
{
|
||||||
|
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await RunProcessNormal(fileName, coreInfo, configPath, displayLog);
|
if (displayLog)
|
||||||
|
{
|
||||||
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.Data.IsNullOrEmpty())
|
||||||
|
return;
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
|
};
|
||||||
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
|
{
|
||||||
|
if (e.Data.IsNullOrEmpty())
|
||||||
|
return;
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
proc.Start();
|
||||||
|
|
||||||
|
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
|
{
|
||||||
|
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
}
|
||||||
|
if (isNeedSudo)
|
||||||
|
_linuxSudoPid = proc.Id;
|
||||||
|
|
||||||
|
if (displayLog)
|
||||||
|
{
|
||||||
|
proc.BeginOutputReadLine();
|
||||||
|
proc.BeginErrorReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(500);
|
||||||
|
AppHandler.Instance.AddProcess(proc.Handle);
|
||||||
|
if (proc is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
throw new Exception(ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -260,57 +321,89 @@ public class CoreHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Process?> RunProcessNormal(string fileName, CoreInfo? coreInfo, string configPath, bool displayLog)
|
#endregion Process
|
||||||
|
|
||||||
|
#region Linux
|
||||||
|
|
||||||
|
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
||||||
{
|
{
|
||||||
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
|
|
||||||
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
||||||
|
proc.StartInfo.FileName = shFilePath;
|
||||||
|
proc.StartInfo.Arguments = "";
|
||||||
|
proc.StartInfo.WorkingDirectory = "";
|
||||||
|
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
|
{
|
||||||
|
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
||||||
|
proc.StartInfo.RedirectStandardInput = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task KillProcessAsLinuxSudo()
|
||||||
|
{
|
||||||
|
var cmdLine = $"kill {_linuxSudoPid}";
|
||||||
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
|
||||||
Process proc = new()
|
Process proc = new()
|
||||||
{
|
{
|
||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = shFilePath,
|
||||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
|
||||||
WorkingDirectory = Utils.GetBinConfigPath(),
|
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
|
||||||
RedirectStandardError = displayLog,
|
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
|
StandardInputEncoding = Encoding.UTF8,
|
||||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
RedirectStandardInput = true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (displayLog)
|
|
||||||
{
|
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
|
||||||
{
|
|
||||||
if (e.Data.IsNotEmpty())
|
|
||||||
{
|
|
||||||
UpdateFunc(false, e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
proc.Start();
|
proc.Start();
|
||||||
|
|
||||||
if (displayLog)
|
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
{
|
{
|
||||||
proc.BeginOutputReadLine();
|
try
|
||||||
proc.BeginErrorReadLine();
|
{
|
||||||
|
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(100);
|
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||||
AppHandler.Instance.AddProcess(proc.Handle);
|
await proc.WaitForExitAsync(timeout.Token);
|
||||||
if (proc is null or { HasExited: true })
|
await Task.Delay(3000);
|
||||||
{
|
|
||||||
throw new Exception(ResUI.FailedToRunCore);
|
|
||||||
}
|
|
||||||
return proc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Process
|
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||||
|
{
|
||||||
|
//Shell scripts
|
||||||
|
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||||
|
File.Delete(shFilePath);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine("#!/bin/sh");
|
||||||
|
if (AppHandler.Instance.IsAdministrator)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"{cmdLine}");
|
||||||
|
}
|
||||||
|
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
sb.AppendLine($"pkexec {cmdLine}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine($"sudo -S {cmdLine}");
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
||||||
|
await Utils.SetLinuxChmod(shFilePath);
|
||||||
|
Logging.SaveLog(shFilePath);
|
||||||
|
|
||||||
|
return shFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Linux
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ public class VmessFmt : BaseFmt
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
ProfileItem? item;
|
||||||
if (str.IndexOf('@') > 0)
|
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0)
|
||||||
{
|
{
|
||||||
item = ResolveStdVmess(str) ?? ResolveVmess(str, out msg);
|
item = ResolveStdVmess(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,6 +147,7 @@ public class TunModeItem
|
||||||
public int Mtu { get; set; }
|
public int Mtu { get; set; }
|
||||||
public bool EnableExInbound { get; set; }
|
public bool EnableExInbound { get; set; }
|
||||||
public bool EnableIPv6Address { get; set; }
|
public bool EnableIPv6Address { get; set; }
|
||||||
|
public string? LinuxSudoPwd { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
|
2
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
2
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
|
@ -3247,7 +3247,7 @@ namespace ServiceLib.Resx {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart. 的本地化字符串。
|
/// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPasswordTip {
|
public static string TbSettingsLinuxSudoPasswordTip {
|
||||||
get {
|
get {
|
||||||
|
|
|
@ -1339,7 +1339,7 @@
|
||||||
<value>رمز عبور sudo سیستم</value>
|
<value>رمز عبور sudo سیستم</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.</value>
|
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
||||||
|
|
|
@ -1339,7 +1339,7 @@
|
||||||
<value>Rendszer sudo jelszó</value>
|
<value>Rendszer sudo jelszó</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
|
<value>A jelszó titkosítva és csak a helyi fájlokban tárolva.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>Kérlek, először állítsd be a sudo jelszót a Tun módban</value>
|
<value>Kérlek, először állítsd be a sudo jelszót a Tun módban</value>
|
||||||
|
|
|
@ -1339,7 +1339,7 @@
|
||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
|
<value>The password is encrypted and stored only in local files</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
<value>Please set the sudo password in Tun mode settings first</value>
|
||||||
|
|
|
@ -1339,7 +1339,7 @@
|
||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password you entered cannot be verified, so make sure you enter it correctly. If the application does not work properly due to an incorrect input, please restart the application. The password will not be stored and you will need to enter it again after each restart.</value>
|
<value>Пароль зашифрован и хранится только в локальных файлах..</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>Please set the sudo password in Tun mode settings first</value>
|
<value>Please set the sudo password in Tun mode settings first</value>
|
||||||
|
|
|
@ -1071,13 +1071,13 @@
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>拥塞控制算法</value>
|
<value>拥塞控制算法</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfile" xml:space="preserve">
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
<value>前置代理配置文件别名</value>
|
<value>前置代理配置文件别名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>落地代理配置文件別名</value>
|
<value>落地代理配置文件別名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfileTip" xml:space="preserve">
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
<value>请确保配置文件别名存在并唯一</value>
|
<value>请确保配置文件别名存在并唯一</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
|
@ -1336,7 +1336,7 @@
|
||||||
<value>系统的 sudo 密码</value>
|
<value>系统的 sudo 密码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>输入的密码无法校验,所以请确保输入正确。如果因为输入错误导致无法正常运行时,请重启本应用。 密码不会存储,每次重启后都需要再次输入。</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>
|
||||||
|
|
|
@ -1071,13 +1071,13 @@
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>擁塞控制算法</value>
|
<value>擁塞控制算法</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfile" xml:space="preserve">
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
<value>前置代理設定檔別名</value>
|
<value>前置代理設定檔別名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>落地代理設定檔別名</value>
|
<value>落地代理設定檔別名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfileTip" xml:space="preserve">
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
<value>請確保設定檔別名存在並且唯一</value>
|
<value>請確保設定檔別名存在並且唯一</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
|
@ -1336,7 +1336,7 @@
|
||||||
<value>系統的 sudo 密碼</value>
|
<value>系統的 sudo 密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>輸入的密碼無法校驗,所以請確保輸入正確。如果因為輸入錯誤導致無法正常運作時,請重新啟動本應用。 密碼不會存儲,每次重啟後都需要再次輸入。</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>
|
||||||
|
|
|
@ -6,10 +6,11 @@
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
"address": "1.1.1.1",
|
"address": "1.1.1.1",
|
||||||
"skipFallback": true,
|
|
||||||
"domains": [
|
"domains": [
|
||||||
"domain:googleapis.cn",
|
"geosite:geolocation-!cn"
|
||||||
"domain:gstatic.com"
|
],
|
||||||
|
"expectIPs": [
|
||||||
|
"geoip:!cn"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -22,7 +23,6 @@
|
||||||
"geoip:cn"
|
"geoip:cn"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"1.1.1.1",
|
|
||||||
"8.8.8.8",
|
"8.8.8.8",
|
||||||
"https://dns.google/dns-query"
|
"https://dns.google/dns-query"
|
||||||
]
|
]
|
||||||
|
|
|
@ -979,6 +979,26 @@ public class CoreConfigSingboxService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dnsOutbound = "dns_out";
|
var dnsOutbound = "dns_out";
|
||||||
|
if (!_config.Inbound.First().SniffingEnabled)
|
||||||
|
{
|
||||||
|
singboxConfig.route.rules.Add(new()
|
||||||
|
{
|
||||||
|
port = [53],
|
||||||
|
network = ["udp"],
|
||||||
|
outbound = dnsOutbound
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.DirectTag,
|
||||||
|
clash_mode = ERuleMode.Direct.ToString()
|
||||||
|
});
|
||||||
|
singboxConfig.route.rules.Insert(0, new()
|
||||||
|
{
|
||||||
|
outbound = Global.ProxyTag,
|
||||||
|
clash_mode = ERuleMode.Global.ToString()
|
||||||
|
});
|
||||||
|
|
||||||
if (_config.TunModeItem.EnableTun)
|
if (_config.TunModeItem.EnableTun)
|
||||||
{
|
{
|
||||||
|
@ -1005,27 +1025,6 @@ public class CoreConfigSingboxService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_config.Inbound.First().SniffingEnabled)
|
|
||||||
{
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
port = [53],
|
|
||||||
network = ["udp"],
|
|
||||||
outbound = dnsOutbound
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
outbound = Global.DirectTag,
|
|
||||||
clash_mode = ERuleMode.Direct.ToString()
|
|
||||||
});
|
|
||||||
singboxConfig.route.rules.Add(new()
|
|
||||||
{
|
|
||||||
outbound = Global.ProxyTag,
|
|
||||||
clash_mode = ERuleMode.Global.ToString()
|
|
||||||
});
|
|
||||||
|
|
||||||
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
var routing = await ConfigHandler.GetDefaultRouting(_config);
|
||||||
if (routing != null)
|
if (routing != null)
|
||||||
{
|
{
|
||||||
|
@ -1088,11 +1087,14 @@ public class CoreConfigSingboxService
|
||||||
|
|
||||||
if (item.Port.IsNotEmpty())
|
if (item.Port.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var portRanges = item.Port.Split(',').Where(it => it.Contains('-')).Select(it => it.Replace("-", ":")).ToList();
|
if (item.Port.Contains("-"))
|
||||||
var ports = item.Port.Split(',').Where(it => !it.Contains('-')).Select(it => it.ToInt()).ToList();
|
{
|
||||||
|
rule.port_range = new List<string> { item.Port.Replace("-", ":") };
|
||||||
rule.port_range = portRanges.Count > 0 ? portRanges : null;
|
}
|
||||||
rule.port = ports.Count > 0 ? ports : null;
|
else
|
||||||
|
{
|
||||||
|
rule.port = new List<int> { item.Port.ToInt() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.Network.IsNotEmpty())
|
if (item.Network.IsNotEmpty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1183,6 +1183,7 @@ public class CoreConfigV2rayService
|
||||||
if (servers != null)
|
if (servers != null)
|
||||||
{
|
{
|
||||||
var domainList = new List<string>();
|
var domainList = new List<string>();
|
||||||
|
string? wireguardEndpointDomain = null;
|
||||||
if (Utils.IsDomain(node.Address))
|
if (Utils.IsDomain(node.Address))
|
||||||
{
|
{
|
||||||
domainList.Add(node.Address);
|
domainList.Add(node.Address);
|
||||||
|
@ -1209,7 +1210,14 @@ public class CoreConfigV2rayService
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC
|
&& nextNode.ConfigType != EConfigType.TUIC
|
||||||
&& Utils.IsDomain(nextNode.Address))
|
&& Utils.IsDomain(nextNode.Address))
|
||||||
{
|
{
|
||||||
domainList.Add(nextNode.Address);
|
if (nextNode.ConfigType == EConfigType.WireGuard)
|
||||||
|
{
|
||||||
|
wireguardEndpointDomain = nextNode.Address;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
domainList.Add(nextNode.Address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (domainList.Count > 0)
|
if (domainList.Count > 0)
|
||||||
|
@ -1222,6 +1230,16 @@ public class CoreConfigV2rayService
|
||||||
};
|
};
|
||||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
}
|
}
|
||||||
|
if (wireguardEndpointDomain is not null)
|
||||||
|
{
|
||||||
|
var dnsServer = new DnsServer4Ray()
|
||||||
|
{
|
||||||
|
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
|
||||||
|
skipFallback = true,
|
||||||
|
domains = new() { wireguardEndpointDomain }
|
||||||
|
};
|
||||||
|
servers.AsArray().Insert(0, JsonUtils.SerializeToNode(dnsServer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return await Task.FromResult(0);
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,11 +174,6 @@ public class ClashProxiesViewModel : MyReactiveObject
|
||||||
|
|
||||||
public void RefreshProxyGroups()
|
public void RefreshProxyGroups()
|
||||||
{
|
{
|
||||||
if (_proxies == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectedName = SelectedGroup?.Name;
|
var selectedName = SelectedGroup?.Name;
|
||||||
_proxyGroups.Clear();
|
_proxyGroups.Clear();
|
||||||
|
|
||||||
|
@ -302,10 +297,8 @@ public class ClashProxiesViewModel : MyReactiveObject
|
||||||
|
|
||||||
private ProxiesItem? TryGetProxy(string name)
|
private ProxiesItem? TryGetProxy(string name)
|
||||||
{
|
{
|
||||||
if (_proxies == null)
|
if (_proxies is null)
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
_proxies.TryGetValue(name, out var proxy2);
|
_proxies.TryGetValue(name, out var proxy2);
|
||||||
if (proxy2 != null)
|
if (proxy2 != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -548,11 +548,8 @@ public class MainWindowViewModel : MyReactiveObject
|
||||||
|
|
||||||
BlReloadEnabled = false;
|
BlReloadEnabled = false;
|
||||||
|
|
||||||
await Task.Run(async () =>
|
await LoadCore();
|
||||||
{
|
await SysProxyHandler.UpdateSysProxy(_config, false);
|
||||||
await LoadCore();
|
|
||||||
await SysProxyHandler.UpdateSysProxy(_config, false);
|
|
||||||
});
|
|
||||||
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
Locator.Current.GetService<StatusBarViewModel>()?.TestServerAvailability();
|
||||||
|
|
||||||
_updateView?.Invoke(EViewAction.DispatcherReload, null);
|
_updateView?.Invoke(EViewAction.DispatcherReload, null);
|
||||||
|
|
|
@ -88,6 +88,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
||||||
[Reactive] public int TunMtu { get; set; }
|
[Reactive] public int TunMtu { get; set; }
|
||||||
[Reactive] public bool TunEnableExInbound { get; set; }
|
[Reactive] public bool TunEnableExInbound { get; set; }
|
||||||
[Reactive] public bool TunEnableIPv6Address { get; set; }
|
[Reactive] public bool TunEnableIPv6Address { get; set; }
|
||||||
|
[Reactive] public string TunLinuxSudoPassword { get; set; }
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
|
@ -204,6 +205,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
||||||
TunMtu = _config.TunModeItem.Mtu;
|
TunMtu = _config.TunModeItem.Mtu;
|
||||||
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
|
TunEnableExInbound = _config.TunModeItem.EnableExInbound;
|
||||||
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
|
TunEnableIPv6Address = _config.TunModeItem.EnableIPv6Address;
|
||||||
|
TunLinuxSudoPassword = _config.TunModeItem.LinuxSudoPwd;
|
||||||
|
|
||||||
#endregion Tun mode
|
#endregion Tun mode
|
||||||
|
|
||||||
|
@ -356,6 +358,10 @@ public class OptionSettingViewModel : MyReactiveObject
|
||||||
_config.TunModeItem.Mtu = TunMtu;
|
_config.TunModeItem.Mtu = TunMtu;
|
||||||
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
|
_config.TunModeItem.EnableExInbound = TunEnableExInbound;
|
||||||
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
|
_config.TunModeItem.EnableIPv6Address = TunEnableIPv6Address;
|
||||||
|
if (TunLinuxSudoPassword != _config.TunModeItem.LinuxSudoPwd)
|
||||||
|
{
|
||||||
|
_config.TunModeItem.LinuxSudoPwd = DesUtils.Encrypt(TunLinuxSudoPassword);
|
||||||
|
}
|
||||||
|
|
||||||
//coreType
|
//coreType
|
||||||
await SaveCoreType();
|
await SaveCoreType();
|
||||||
|
|
|
@ -318,10 +318,7 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
|
|
||||||
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
||||||
|
|
||||||
var msg = await Task.Run(async () =>
|
var msg = await (new UpdateService()).RunAvailabilityCheck();
|
||||||
{
|
|
||||||
return await (new UpdateService()).RunAvailabilityCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
NoticeHandler.Instance.SendMessageEx(msg);
|
NoticeHandler.Instance.SendMessageEx(msg);
|
||||||
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
|
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
|
||||||
|
@ -436,13 +433,11 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else if (Utils.IsOSX())
|
||||||
{
|
{
|
||||||
if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
|
_config.TunModeItem.EnableTun = false;
|
||||||
{
|
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||||
_config.TunModeItem.EnableTun = false;
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ConfigHandler.SaveConfig(_config);
|
await ConfigHandler.SaveConfig(_config);
|
||||||
|
@ -454,15 +449,15 @@ public class StatusBarViewModel : MyReactiveObject
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
return Utils.IsAdministrator();
|
return AppHandler.Instance.IsAdministrator;
|
||||||
}
|
}
|
||||||
else if (Utils.IsLinux())
|
else if (Utils.IsLinux())
|
||||||
{
|
{
|
||||||
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
|
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
||||||
}
|
}
|
||||||
else if (Utils.IsOSX())
|
else if (Utils.IsOSX())
|
||||||
{
|
{
|
||||||
return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
|
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ public partial class App : Application
|
||||||
{
|
{
|
||||||
if (e.ExceptionObject != null)
|
if (e.ExceptionObject != null)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject);
|
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,16 +52,9 @@ public partial class ClashConnectionsView : ReactiveUserControl<ClashConnections
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstConnections.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstConnections.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ClashConnectionsView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Utils.IsAdministrator())
|
if (AppHandler.Instance.IsAdministrator)
|
||||||
{
|
{
|
||||||
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
||||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
||||||
|
|
|
@ -784,6 +784,28 @@
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
x:Name="labLinuxSudoPassword"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtLinuxSudoPassword"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="labLinuxSudoPasswordTip"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
||||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||||
|
@ -169,6 +170,10 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
||||||
{
|
{
|
||||||
txbSettingsExceptionTip2.IsVisible = false;
|
txbSettingsExceptionTip2.IsVisible = false;
|
||||||
|
|
||||||
|
txtLinuxSudoPassword.IsVisible = false;
|
||||||
|
labLinuxSudoPassword.IsVisible = false;
|
||||||
|
labLinuxSudoPasswordTip.IsVisible = false;
|
||||||
|
|
||||||
labHide2TrayWhenClose.IsVisible = false;
|
labHide2TrayWhenClose.IsVisible = false;
|
||||||
togHide2TrayWhenClose.IsVisible = false;
|
togHide2TrayWhenClose.IsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,16 +345,9 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstProfiles.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ProfilesView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DialogHostAvalonia;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Splat;
|
using Splat;
|
||||||
using v2rayN.Desktop.Common;
|
using v2rayN.Desktop.Common;
|
||||||
|
@ -82,10 +81,6 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||||
return false;
|
return false;
|
||||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EViewAction.PasswordInput:
|
|
||||||
return await PasswordInputAsync();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return await Task.FromResult(true);
|
return await Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
@ -101,20 +96,6 @@ public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> PasswordInputAsync()
|
|
||||||
{
|
|
||||||
var dialog = new SudoPasswordInputView();
|
|
||||||
var obj = await DialogHost.Show(dialog);
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
togEnableTun.IsChecked = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppHandler.Instance.LinuxSudoPwd = obj.ToString() ?? string.Empty;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||||
{
|
{
|
||||||
ViewModel?.TestServerAvailability();
|
ViewModel?.TestServerAvailability();
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
<UserControl
|
|
||||||
x:Class="v2rayN.Desktop.Views.SudoPasswordInputView"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
|
||||||
d:DesignHeight="200"
|
|
||||||
d:DesignWidth="400"
|
|
||||||
mc:Ignorable="d">
|
|
||||||
<DockPanel Margin="{StaticResource Margin8}">
|
|
||||||
|
|
||||||
<Border
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
DockPanel.Dock="Bottom"
|
|
||||||
Theme="{DynamicResource CardBorder}">
|
|
||||||
|
|
||||||
<StackPanel
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Button
|
|
||||||
x:Name="btnSave"
|
|
||||||
Width="100"
|
|
||||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
|
||||||
Cursor="Hand"
|
|
||||||
IsDefault="True" />
|
|
||||||
<Button
|
|
||||||
x:Name="btnCancel"
|
|
||||||
Width="100"
|
|
||||||
Margin="{StaticResource MarginLr8}"
|
|
||||||
Content="{x:Static resx:ResUI.TbCancel}"
|
|
||||||
Cursor="Hand"
|
|
||||||
IsCancel="True" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Theme="{DynamicResource CardBorder}">
|
|
||||||
|
|
||||||
<Grid ColumnDefinitions="Auto,400" RowDefinitions="Auto,Auto,Auto">
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPassword}" />
|
|
||||||
|
|
||||||
<TextBox
|
|
||||||
x:Name="txtPassword"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
Classes="revealPasswordButton"
|
|
||||||
Focusable="True" />
|
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="{StaticResource Margin4}"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{x:Static resx:ResUI.TbSettingsLinuxSudoPasswordTip}"
|
|
||||||
TextWrapping="Wrap" />
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</DockPanel>
|
|
||||||
</UserControl>
|
|
|
@ -1,33 +0,0 @@
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using DialogHostAvalonia;
|
|
||||||
|
|
||||||
namespace v2rayN.Desktop.Views;
|
|
||||||
|
|
||||||
public partial class SudoPasswordInputView : UserControl
|
|
||||||
{
|
|
||||||
public SudoPasswordInputView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
this.Loaded += (s, e) => txtPassword.Focus();
|
|
||||||
|
|
||||||
btnSave.Click += (_, _) =>
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(txtPassword.Text))
|
|
||||||
{
|
|
||||||
txtPassword.Focus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
DialogHost.Close(null, txtPassword.Text);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
btnCancel.Click += (_, _) =>
|
|
||||||
{
|
|
||||||
DialogHost.Close(null);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
||||||
|
|
|
@ -56,7 +56,7 @@ public partial class App : Application
|
||||||
{
|
{
|
||||||
if (e.ExceptionObject != null)
|
if (e.ExceptionObject != null)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject);
|
Logging.SaveLog("CurrentDomain_UnhandledException", (Exception)e.ExceptionObject!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,16 +55,9 @@ public partial class ClashConnectionsView
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstConnections.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstConnections.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ClashConnectionsView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<reactiveui:ReactiveWindow
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.MainWindow"
|
x:Class="v2rayN.Views.MainWindow"
|
||||||
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:view="clr-namespace:v2rayN.Views"
|
|
||||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||||
|
xmlns:view="clr-namespace:v2rayN.Views"
|
||||||
Title="v2rayN"
|
Title="v2rayN"
|
||||||
Width="900"
|
Width="900"
|
||||||
Height="700"
|
Height="700"
|
||||||
|
@ -40,10 +40,10 @@
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ClipToBounds="True"
|
ClipToBounds="True"
|
||||||
Style="{StaticResource MaterialDesignToolBar}"
|
Style="{StaticResource MaterialDesignToolBar}">
|
||||||
KeyboardNavigation.TabNavigation="Continue">
|
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
<MenuItem Padding="8,0"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -111,7 +111,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}">
|
<MenuItem Padding="8,0"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -146,7 +147,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem Padding="8,0" AutomationProperties.Name="{x:Static resx:ResUI.menuSetting}">
|
<MenuItem Padding="8,0"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSetting}">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -212,10 +214,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem
|
<MenuItem x:Name="menuReload" Padding="8,0"
|
||||||
x:Name="menuReload"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuReload}">
|
||||||
Padding="8,0"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuReload}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -229,10 +229,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem
|
<MenuItem Name="menuCheckUpdate" Padding="8,0"
|
||||||
Name="menuCheckUpdate"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuCheckUpdate}">
|
||||||
Padding="8,0"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuCheckUpdate}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -246,10 +244,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem
|
<MenuItem x:Name="menuHelp" Padding="8,0"
|
||||||
x:Name="menuHelp"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuHelp}">
|
||||||
Padding="8,0"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuHelp}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -263,10 +259,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem
|
<MenuItem x:Name="menuPromotion" Padding="8,0"
|
||||||
x:Name="menuPromotion"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuPromotion}">
|
||||||
Padding="8,0"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuPromotion}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -280,10 +274,8 @@
|
||||||
</Menu>
|
</Menu>
|
||||||
<Separator />
|
<Separator />
|
||||||
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
|
||||||
<MenuItem
|
<MenuItem x:Name="menuClose" Padding="8,0"
|
||||||
x:Name="menuClose"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuClose}">
|
||||||
Padding="8,0"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuClose}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
|
|
@ -132,7 +132,7 @@ public partial class MainWindow
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||||
|
|
||||||
if (!_config.GuiItem.EnableHWA)
|
if (!_config.GuiItem.EnableHWA)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
|
||||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||||
<Style x:Key="AccessibleMyChipListBoxItem" TargetType="ListBoxItem" BasedOn="{StaticResource MyChipListBoxItem}">
|
|
||||||
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
|
||||||
</Style>
|
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
@ -29,9 +26,8 @@
|
||||||
x:Name="lstGroup"
|
x:Name="lstGroup"
|
||||||
MaxHeight="200"
|
MaxHeight="200"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
ItemContainerStyle="{StaticResource AccessibleMyChipListBoxItem}"
|
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
||||||
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}"
|
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}">
|
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding Remarks}" />
|
<TextBlock Text="{Binding Remarks}" />
|
||||||
|
@ -44,9 +40,9 @@
|
||||||
Width="30"
|
Width="30"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="{StaticResource MarginLeftRight4}"
|
Margin="{StaticResource MarginLeftRight4}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSubEdit}"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
ToolTip="{x:Static resx:ResUI.menuSubEdit}">
|
ToolTip="{x:Static resx:ResUI.menuSubEdit}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSubEdit}">
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
@ -54,9 +50,9 @@
|
||||||
Width="30"
|
Width="30"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="{StaticResource MarginLeftRight4}"
|
Margin="{StaticResource MarginLeftRight4}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSubAdd}"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
ToolTip="{x:Static resx:ResUI.menuSubAdd}">
|
ToolTip="{x:Static resx:ResUI.menuSubAdd}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSubAdd}">
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
@ -65,9 +61,9 @@
|
||||||
Width="30"
|
Width="30"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="{StaticResource MarginLeftRight8}"
|
Margin="{StaticResource MarginLeftRight8}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
|
|
||||||
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
|
||||||
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||||
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
|
||||||
</Button>
|
</Button>
|
||||||
<TextBox
|
<TextBox
|
||||||
|
@ -77,8 +73,8 @@
|
||||||
VerticalContentAlignment="Center"
|
VerticalContentAlignment="Center"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
|
||||||
materialDesign:TextFieldAssist.HasClearButton="True"
|
materialDesign:TextFieldAssist.HasClearButton="True"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}"
|
Style="{StaticResource DefTextBox}"
|
||||||
Style="{StaticResource DefTextBox}" />
|
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstProfiles"
|
x:Name="lstProfiles"
|
||||||
|
|
|
@ -323,16 +323,9 @@ public partial class ProfilesView
|
||||||
|
|
||||||
private void AutofitColumnWidth()
|
private void AutofitColumnWidth()
|
||||||
{
|
{
|
||||||
try
|
foreach (var it in lstProfiles.Columns)
|
||||||
{
|
{
|
||||||
foreach (var it in lstProfiles.Columns)
|
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||||
{
|
|
||||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog("ProfilesView", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -61,8 +61,7 @@
|
||||||
x:Name="togEnableTun"
|
x:Name="togEnableTun"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center" AutomationProperties.Name="{x:Static resx:ResUI.TbEnableTunAs}" />
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.TbEnableTunAs}" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
@ -75,9 +74,9 @@
|
||||||
Width="160"
|
Width="160"
|
||||||
Margin="{StaticResource MarginLeftRight8}"
|
Margin="{StaticResource MarginLeftRight8}"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSystemproxy}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemproxy}"
|
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}">
|
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemproxy}">
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
||||||
|
@ -89,16 +88,10 @@
|
||||||
Width="160"
|
Width="160"
|
||||||
Margin="{StaticResource MarginLeftRight8}"
|
Margin="{StaticResource MarginLeftRight8}"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}"
|
|
||||||
DisplayMemberPath="Remarks"
|
DisplayMemberPath="Remarks"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFloatingHintComboBox}">
|
Style="{StaticResource MaterialDesignFloatingHintComboBox}"
|
||||||
<ComboBox.ItemContainerStyle>
|
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}"/>
|
||||||
<Style TargetType="ComboBoxItem">
|
|
||||||
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
|
||||||
</Style>
|
|
||||||
</ComboBox.ItemContainerStyle>
|
|
||||||
</ComboBox>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Margin="{StaticResource MarginLeftRight8}" VerticalAlignment="Center">
|
<StackPanel Margin="{StaticResource MarginLeftRight8}" VerticalAlignment="Center">
|
||||||
|
@ -116,10 +109,8 @@
|
||||||
ToolTipText="v2rayN">
|
ToolTipText="v2rayN">
|
||||||
<tb:TaskbarIcon.ContextMenu>
|
<tb:TaskbarIcon.ContextMenu>
|
||||||
<ContextMenu Style="{StaticResource DefContextMenu}">
|
<ContextMenu Style="{StaticResource DefContextMenu}">
|
||||||
<MenuItem
|
<MenuItem x:Name="menuSystemProxyClear" Height="{StaticResource MenuItemHeight}"
|
||||||
x:Name="menuSystemProxyClear"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyClear}">
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyClear}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -131,10 +122,8 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem x:Name="menuSystemProxySet" Height="{StaticResource MenuItemHeight}"
|
||||||
x:Name="menuSystemProxySet"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxySet}">
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxySet}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -146,10 +135,8 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem x:Name="menuSystemProxyNothing" Height="{StaticResource MenuItemHeight}"
|
||||||
x:Name="menuSystemProxyNothing"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyNothing}">
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyNothing}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -161,10 +148,8 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem x:Name="menuSystemProxyPac" Height="{StaticResource MenuItemHeight}"
|
||||||
x:Name="menuSystemProxyPac"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyPac}">
|
||||||
Height="{StaticResource MenuItemHeight}"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuSystemProxyPac}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon
|
<materialDesign:PackIcon
|
||||||
|
@ -177,26 +162,18 @@
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator x:Name="sepRoutings" />
|
<Separator x:Name="sepRoutings" />
|
||||||
<MenuItem
|
<MenuItem x:Name="menuRoutings" Height="Auto"
|
||||||
x:Name="menuRoutings"
|
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}">
|
||||||
Height="Auto"
|
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}">
|
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="cmbRoutings"
|
x:Name="cmbRoutings"
|
||||||
MaxWidth="300"
|
MaxWidth="300"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuRouting}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}"
|
|
||||||
DisplayMemberPath="Remarks"
|
DisplayMemberPath="Remarks"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}">
|
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||||
<ComboBox.ItemContainerStyle>
|
AutomationProperties.Name="{x:Static resx:ResUI.menuRouting}"/>
|
||||||
<Style TargetType="ComboBoxItem">
|
|
||||||
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
|
|
||||||
</Style>
|
|
||||||
</ComboBox.ItemContainerStyle>
|
|
||||||
</ComboBox>
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -207,16 +184,10 @@
|
||||||
x:Name="cmbServers"
|
x:Name="cmbServers"
|
||||||
MaxWidth="300"
|
MaxWidth="300"
|
||||||
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}"
|
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuServers}"
|
||||||
AutomationProperties.Name="{x:Static resx:ResUI.menuServers}"
|
|
||||||
DisplayMemberPath="Text"
|
DisplayMemberPath="Text"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
Style="{StaticResource MaterialDesignFilledComboBox}">
|
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||||
<ComboBox.ItemContainerStyle>
|
AutomationProperties.Name="{x:Static resx:ResUI.menuServers}"/>
|
||||||
<Style TargetType="ComboBoxItem">
|
|
||||||
<Setter Property="AutomationProperties.Name" Value="{Binding Text}" />
|
|
||||||
</Style>
|
|
||||||
</ComboBox.ItemContainerStyle>
|
|
||||||
</ComboBox>
|
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<reactiveui:ReactiveWindow
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubSettingWindow"
|
x:Class="v2rayN.Views.SubSettingWindow"
|
||||||
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}"
|
||||||
|
|
|
@ -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: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: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:v2rayN.ViewModels"
|
xmlns:vms="clr-namespace:v2rayN.ViewModels"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
|
|
Loading…
Reference in a new issue