Compare commits

...

38 Commits

Author SHA1 Message Date
2dust
331e8ce960 up 7.12.3 2025-05-11 19:19:26 +08:00
2dust
a2cfe6fa51 Added the current connection information test url option
https://github.com/2dust/v2rayN/discussions/7268
2025-05-11 16:59:00 +08:00
2dust
8381fefb78 up 7.12.2 2025-05-11 10:39:02 +08:00
2dust
d3b95d781a Removed the function of displaying the current connection IP
https://github.com/2dust/v2rayN/discussions/7268
2025-05-11 10:38:48 +08:00
2dust
3a4a96f87a Fix
https://github.com/2dust/v2rayN/issues/7258
2025-05-09 14:33:41 +08:00
2dust
3d462c4be3 Fix
https://github.com/2dust/v2rayN/issues/7247
2025-05-08 15:56:52 +08:00
2dust
82b366cd9b Fix
https://github.com/2dust/v2rayN/issues/7244
2025-05-07 14:28:55 +08:00
DHR60
897a4e5635 Move exe direct rule before clash_mode (#7236) 2025-05-05 13:59:14 +08:00
2dust
8ea76fd318 up 7.12.1 2025-05-04 17:44:36 +08:00
2dust
693a96fff2 Update Directory.Packages.props 2025-05-04 17:44:04 +08:00
DHR60
8b4e2f8f23 Fix DNS (#7233)
* Fix DNS

* Removes expectIPs from remote DNS
2025-05-04 17:28:57 +08:00
2dust
13b164acac Enhanced sorting function, can sort by statistics 2025-05-03 11:29:36 +08:00
2dust
e590547b30 Revert "Bug fix"
This reverts commit 5a0fdd971a.
2025-05-02 10:44:20 +08:00
2dust
5a0fdd971a Bug fix
https://github.com/2dust/v2rayN/issues/7211
2025-04-30 14:12:02 +08:00
2dust
514dce960a up 7.12.0 2025-04-28 15:57:09 +08:00
Reza Bakhshi Laktasaraei
6ee6fb1706 Improve Accessibility in StatusBarView and ProfilesView, Update Package Versions (#7199)
* Fix Tab navigation in ToolBar by setting KeyboardNavigation to Continue

* Improve accessibility for ComboBoxes in StatusBarView.xaml

Added ItemContainerStyle to cmbRoutings2 and cmbRoutings to bind AutomationProperties.Name to Remarks, ensuring screen readers announce the correct values instead of the default object type.

* Improve accessibility for cmbServers in StatusBarView.xaml

Added ItemContainerStyle to cmbServers to bind AutomationProperties.Name to Text, ensuring screen readers announce the correct values instead of the default object type.

* Update package versions and fix accessibility in ProfilesView.xaml

- Updated package versions in Directory.Packages.props:
  - Semi.Avalonia and Semi.Avalonia.DataGrid from 11.2.1.6 to 11.2.1.7.
  - ZXing.Net.Bindings.SkiaSharp from 0.16.14 to 0.16.21.
- Fixed MC3024 error in ProfilesView.xaml by creating AccessibleMyChipListBoxItem style:
  - Added AccessibleMyChipListBoxItem style based on MyChipListBoxItem to set AutomationProperties.Name.
  - Replaced ItemContainerStyle with AccessibleMyChipListBoxItem to preserve original appearance.
  - Updated AutomationProperties.Name to use resx:ResUI.menuSubscription for better localization.
  - Removed duplicate AutomationProperties.Name from TextBlock as it's now handled by the style.

* Update Directory.Packages.props

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
2025-04-28 15:25:57 +08:00
2dust
6985328653 Optimize and improve code 2025-04-28 15:16:58 +08:00
DHR60
41c406b84d Revert "Fix xray wireguard chained proxies not working (2dust#7113)" (#7194) 2025-04-27 09:37:46 +08:00
2dust
30f7f2c563 Update Directory.Packages.props 2025-04-26 10:32:20 +08:00
Reza Bakhshi Laktasaraei
be3dbfb8e3 Fix Tab navigation in ToolBar by setting KeyboardNavigation to Continue (#7185) 2025-04-26 10:31:00 +08:00
Pk-web6936
9b92259e80 Update Persian translation (#7191)
0032a3d27a
2025-04-26 10:30:05 +08:00
2dust
1c04144573 Code clean 2025-04-26 09:53:19 +08:00
2dust
adf3b955d6 Refactor Linux to run Tun as sudo 2025-04-26 09:50:31 +08:00
2dust
0032a3d27a Fix kill process for linux 2025-04-25 16:36:28 +08:00
2dust
c6d347d49a Refactor the Linux version to not store sudo password 2025-04-25 15:19:49 +08:00
2dust
ea42246d1b Improved AmazTool 2025-04-25 14:38:33 +08:00
2dust
3f19958c75 Bug fix
https://github.com/2dust/v2rayN/issues/7179
2025-04-24 11:50:24 +08:00
2dust
35788158bc up 7.11.3 2025-04-21 10:17:37 +08:00
2dust
4fd494ded4 Update Directory.Packages.props 2025-04-21 10:15:49 +08:00
2dust
23eeb8ff55 Try to fix
https://github.com/2dust/v2rayN/issues/7128
2025-04-18 12:31:46 +08:00
2dust
456ffb200a up 7.11.2 2025-04-15 10:54:55 +08:00
2dust
18e0bb194e Enhance Accessibility in MsgView 2025-04-15 09:57:04 +08:00
2dust
392f6111dd Update Directory.Packages.props 2025-04-14 11:17:57 +08:00
DHR60
ce6572af3d Fix xray wireguard chained proxies not working (#7113)
* Fix chained proxies not working

* Add domain field for WireGuard exit node
2025-04-12 19:03:34 +08:00
DHR60
cf59137481 fix dns leak (#7110) 2025-04-12 10:00:18 +08:00
DHR60
519e588124 fix #7105 (#7109) 2025-04-12 09:52:20 +08:00
Reza Bakhshi Laktasaraei
666c874998 Add accessibility labels to improve screen reader support (#7105)
* Add accessibility with AutomationProperties.Name to menus

* Add accessibility labels to StatusBarView using ResUI resources

* Add accessibility labels to ProfilesView using ResUI resources
2025-04-11 09:28:34 +08:00
DHR60
5f9f677467 Adjust menu items (#7100)
* Adjust menu items

* fix #7089
2025-04-11 09:27:34 +08:00
56 changed files with 808 additions and 360 deletions

View File

@@ -5,21 +5,83 @@ internal static class Program
[STAThread] [STAThread]
private static void Main(string[] args) private static void Main(string[] args)
{ {
if (args.Length == 0) try
{ {
Console.WriteLine(Resx.Resource.Guidelines); // If no arguments are provided, display usage guidelines and exit
Thread.Sleep(5000); if (args.Length == 0)
return; {
} ShowHelp();
return;
}
var argData = Uri.UnescapeDataString(string.Join(" ", args)); // Log all arguments for debugging purposes
if (argData.Equals("rebootas")) 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)
{ {
Thread.Sleep(1000); // Global exception handling
Utils.StartV2RayN(); Console.WriteLine($"An error occurred: {ex.Message}");
return; Console.WriteLine("Press any key to exit...");
Console.ReadKey();
} }
}
UpgradeApp.Upgrade(argData); /// <summary>
/// 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);
} }
} }

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.11.1</Version> <Version>7.12.3</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View File

@@ -5,10 +5,10 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.6" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.0" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.6" /> <PackageVersion Include="Avalonia.Desktop" Version="11.3.0" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.6" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.3.0" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.6" /> <PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.0" />
<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.6" /> <PackageVersion Include="Semi.Avalonia" Version="11.2.1.7" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.6" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.7" />
<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" />

View File

@@ -20,6 +20,7 @@ public enum EViewAction
BrowseServer, BrowseServer,
ImportRulesFromFile, ImportRulesFromFile,
InitSettingFont, InitSettingFont,
PasswordInput,
SubEditWindow, SubEditWindow,
RoutingRuleSettingWindow, RoutingRuleSettingWindow,
RoutingRuleDetailsWindow, RoutingRuleDetailsWindow,

View File

@@ -8,9 +8,7 @@ public class Global
public const string GithubUrl = "https://github.com"; public const string GithubUrl = "https://github.com";
public const string GithubApiUrl = "https://api.github.com/repos"; public const string GithubApiUrl = "https://api.github.com/repos";
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat"; public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs"; public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
public const string IPAPIUrl = "https://api.ip.sb/geoip";
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="; public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
public const string ConfigFileName = "guiNConfig.json"; public const string ConfigFileName = "guiNConfig.json";
@@ -519,5 +517,15 @@ public class Global
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" @"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
]; ];
public static readonly List<string> IPAPIUrls =
[
@"https://speed.cloudflare.com/meta",
@"https://api.ip.sb/geoip",
@"https://api-ipv4.ip.sb/geoip",
@"https://api-ipv6.ip.sb/geoip",
@"https://api.ipapi.is",
@""
];
#endregion const #endregion const
} }

View File

@@ -9,7 +9,6 @@ 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;
@@ -31,14 +30,7 @@ public sealed class AppHandler
} }
} }
public bool IsAdministrator public string LinuxSudoPwd { get; set; }
{
get
{
_isAdministrator ??= Utils.IsAdministrator();
return _isAdministrator.Value;
}
}
#endregion Property #endregion Property

View File

@@ -122,7 +122,7 @@ public class ConfigHandler
} }
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty()) if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
{ {
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl; config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrls.First();
} }
if (config.SpeedTestItem.MixedConcurrencyCount < 1) if (config.SpeedTestItem.MixedConcurrencyCount < 1)
{ {
@@ -799,8 +799,11 @@ 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
@@ -815,7 +818,11 @@ 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);
@@ -833,6 +840,10 @@ 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
}; };
} }
@@ -849,6 +860,10 @@ 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
}; };
} }

View File

@@ -0,0 +1,42 @@
namespace ServiceLib.Handler;
public class ConnectionHandler
{
private static readonly Lazy<ConnectionHandler> _instance = new(() => new());
public static ConnectionHandler Instance => _instance.Value;
public async Task<string> RunAvailabilityCheck()
{
var downloadHandle = new DownloadService();
var time = await downloadHandle.RunAvailabilityCheck(null);
var ip = time > 0 ? await GetIPInfo(downloadHandle) ?? Global.None : Global.None;
return string.Format(ResUI.TestMeOutput, time, ip);
}
private async Task<string?> GetIPInfo(DownloadService downloadHandle)
{
var url = AppHandler.Instance.Config.SpeedTestItem.IPAPIUrl;
if (url.IsNullOrEmpty())
{
return null;
}
var result = await downloadHandle.TryDownloadString(url, true, "");
if (result == null)
{
return null;
}
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
if (ipInfo == null)
{
return null;
}
var ip = ipInfo.ip ?? ipInfo.clientIp ?? ipInfo.ip_addr ?? ipInfo.query;
var country = ipInfo.country_code ?? ipInfo.country ?? ipInfo.countryCode ?? ipInfo.location?.country_code;
return $"({country ?? "unknown"}) {ip}";
}
}

View File

@@ -0,0 +1,126 @@
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;
}
}

View File

@@ -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 int _linuxSudoPid = -1; private bool _linuxSudo = false;
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, true); await ProcUtils.ProcessKill(_process, Utils.IsWindows());
_process = null; _process = null;
} }
if (_processPre != null) if (_processPre != null)
{ {
await ProcUtils.ProcessKill(_processPre, true); await ProcUtils.ProcessKill(_processPre, Utils.IsWindows());
_processPre = null; _processPre = null;
} }
if (_linuxSudoPid > 0)
{
await KillProcessAsLinuxSudo();
}
_linuxSudoPid = -1;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -225,15 +225,6 @@ 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
@@ -249,69 +240,17 @@ public class CoreHandler
try try
{ {
Process proc = new() if (mayNeedSudo
&& _config.TunModeItem.EnableTun
&& coreInfo.CoreType == ECoreType.sing_box
&& Utils.IsNonWindows())
{ {
StartInfo = new() _linuxSudo = true;
{ await CoreAdminHandler.Instance.Init(_config, _updateFunc);
FileName = fileName, return await CoreAdminHandler.Instance.RunProcessAsLinuxSudo(fileName, coreInfo, configPath);
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);
} }
if (displayLog) return await RunProcessNormal(fileName, coreInfo, configPath, 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)
{ {
@@ -321,89 +260,57 @@ public class CoreHandler
} }
} }
#endregion Process private async Task<Process?> RunProcessNormal(string fileName, CoreInfo? coreInfo, string configPath, bool displayLog)
#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 = shFilePath, FileName = fileName,
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,
StandardInputEncoding = Encoding.UTF8, StandardOutputEncoding = displayLog ? Encoding.UTF8 : null,
RedirectStandardInput = true StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
} }
}; };
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 (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty()) if (displayLog)
{ {
try proc.BeginOutputReadLine();
{ 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
}
} }
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10)); await Task.Delay(100);
await proc.WaitForExitAsync(timeout.Token); AppHandler.Instance.AddProcess(proc.Handle);
await Task.Delay(3000); if (proc is null or { HasExited: true })
{
throw new Exception(ResUI.FailedToRunCore);
}
return proc;
} }
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName) #endregion Process
{
//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
} }

View File

@@ -6,9 +6,9 @@ public class VmessFmt : BaseFmt
{ {
msg = ResUI.ConfigurationFormatIncorrect; msg = ResUI.ConfigurationFormatIncorrect;
ProfileItem? item; ProfileItem? item;
if (str.IndexOf('?') > 0 && str.IndexOf('&') > 0) if (str.IndexOf('@') > 0)
{ {
item = ResolveStdVmess(str); item = ResolveStdVmess(str) ?? ResolveVmess(str, out msg);
} }
else else
{ {

View File

@@ -147,7 +147,6 @@ 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]
@@ -157,6 +156,7 @@ public class SpeedTestItem
public string SpeedTestUrl { get; set; } public string SpeedTestUrl { get; set; }
public string SpeedPingTestUrl { get; set; } public string SpeedPingTestUrl { get; set; }
public int MixedConcurrencyCount { get; set; } public int MixedConcurrencyCount { get; set; }
public string IPAPIUrl { get; set; }
} }
[Serializable] [Serializable]

View File

@@ -3,10 +3,17 @@ namespace ServiceLib.Models;
internal class IPAPIInfo internal class IPAPIInfo
{ {
public string? ip { get; set; } public string? ip { get; set; }
public string? city { get; set; } public string? clientIp { get; set; }
public string? region { get; set; } public string? ip_addr { get; set; }
public string? region_code { get; set; } public string? query { get; set; }
public string? country { get; set; } public string? country { get; set; }
public string? country_name { get; set; } public string? country_name { get; set; }
public string? country_code { get; set; } public string? country_code { get; set; }
public string? countryCode { get; set; }
public LocationInfo? location { get; set; }
}
public class LocationInfo
{
public string? country_code { get; set; }
} }

View File

@@ -210,6 +210,7 @@ public class DnsServer4Ray
{ {
public string? address { get; set; } public string? address { get; set; }
public List<string>? domains { get; set; } public List<string>? domains { get; set; }
public bool? skipFallback { get; set; }
} }
public class Routing4Ray public class Routing4Ray

View File

@@ -3201,6 +3201,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Current connection info test URL 的本地化字符串。
/// </summary>
public static string TbSettingsIPAPIUrl {
get {
return ResourceManager.GetString("TbSettingsIPAPIUrl", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Keep older entries when de-duplicating 的本地化字符串。 /// 查找类似 Keep older entries when de-duplicating 的本地化字符串。
/// </summary> /// </summary>
@@ -3247,7 +3256,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。 /// 查找类似 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. 的本地化字符串。
/// </summary> /// </summary>
public static string TbSettingsLinuxSudoPasswordTip { public static string TbSettingsLinuxSudoPasswordTip {
get { get {

View File

@@ -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>
@@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>صادر کردن سرور</value> <value>صادر کردن سرور</value>
</data> </data>
</root> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root>

View File

@@ -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>A jelszó titkosítva és csak a helyi fájlokban tárolva.</value> <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>
</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>
@@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>Export server</value> <value>Export server</value>
</data> </data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root> </root>

View File

@@ -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 is encrypted and stored only in local files</value> <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>
</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>
@@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>Export Configuration</value> <value>Export Configuration</value>
</data> </data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root> </root>

View File

@@ -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>Пароль зашифрован и хранится только в локальных файлах..</value> <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>
</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>
@@ -1416,4 +1416,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>Export server</value> <value>Export server</value>
</data> </data>
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value>
</data>
</root> </root>

View File

@@ -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>
@@ -1413,4 +1413,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>导出配置文件</value> <value>导出配置文件</value>
</data> </data>
</root> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>当前连接信息测试地址</value>
</data>
</root>

View File

@@ -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>
@@ -1413,4 +1413,7 @@
<data name="menuExportConfig" xml:space="preserve"> <data name="menuExportConfig" xml:space="preserve">
<value>匯出設定檔</value> <value>匯出設定檔</value>
</data> </data>
</root> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>目前連接資訊測試地址</value>
</data>
</root>

View File

@@ -6,15 +6,15 @@
"servers": [ "servers": [
{ {
"address": "1.1.1.1", "address": "1.1.1.1",
"skipFallback": true,
"domains": [ "domains": [
"geosite:geolocation-!cn" "domain:googleapis.cn",
], "domain:gstatic.com"
"expectIPs": [
"geoip:!cn"
] ]
}, },
{ {
"address": "223.5.5.5", "address": "223.5.5.5",
"skipFallback": true,
"domains": [ "domains": [
"geosite:cn" "geosite:cn"
], ],
@@ -22,6 +22,7 @@
"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"
] ]

View File

@@ -979,26 +979,6 @@ 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)
{ {
@@ -1025,6 +1005,27 @@ 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)
{ {
@@ -1087,14 +1088,11 @@ public class CoreConfigSingboxService
if (item.Port.IsNotEmpty()) if (item.Port.IsNotEmpty())
{ {
if (item.Port.Contains("-")) var portRanges = item.Port.Split(',').Where(it => it.Contains('-')).Select(it => it.Replace("-", ":")).ToList();
{ 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;
else rule.port = ports.Count > 0 ? ports : null;
{
rule.port = new List<int> { item.Port.ToInt() };
}
} }
if (item.Network.IsNotEmpty()) if (item.Network.IsNotEmpty())
{ {

View File

@@ -1176,16 +1176,49 @@ public class CoreConfigV2rayService
private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem) private async Task<int> GenDnsDomains(ProfileItem? node, JsonNode dns, DNSItem? dNSItem)
{ {
if (node == null) if (node == null)
{ return 0; } {
return 0;
}
var servers = dns["servers"]; var servers = dns["servers"];
if (servers != null) if (servers != null)
{ {
var domainList = new List<string>();
if (Utils.IsDomain(node.Address)) if (Utils.IsDomain(node.Address))
{
domainList.Add(node.Address);
}
var subItem = await AppHandler.Instance.GetSubItem(node.Subid);
if (subItem is not null)
{
// Previous proxy
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2
&& prevNode.ConfigType != EConfigType.TUIC
&& Utils.IsDomain(prevNode.Address))
{
domainList.Add(prevNode.Address);
}
// Next proxy
var nextNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.NextProfile);
if (nextNode is not null
&& nextNode.ConfigType != EConfigType.Custom
&& nextNode.ConfigType != EConfigType.Hysteria2
&& nextNode.ConfigType != EConfigType.TUIC
&& Utils.IsDomain(nextNode.Address))
{
domainList.Add(nextNode.Address);
}
}
if (domainList.Count > 0)
{ {
var dnsServer = new DnsServer4Ray() var dnsServer = new DnsServer4Ray()
{ {
address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress, address = string.IsNullOrEmpty(dNSItem?.DomainDNSAddress) ? Global.DomainDNSAddress.FirstOrDefault() : dNSItem?.DomainDNSAddress,
domains = [node.Address] skipFallback = true,
domains = domainList
}; };
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer)); servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
} }

View File

@@ -357,8 +357,8 @@ public class SpeedtestService
private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize) private List<List<ServerTestItem>> GetTestBatchItem(List<ServerTestItem> lstSelected, int pageSize)
{ {
List<List<ServerTestItem>> lstTest = new(); List<List<ServerTestItem>> lstTest = new();
var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)).ToList(); var lst1 = lstSelected.Where(t => t.ConfigType is not (EConfigType.Hysteria2 or EConfigType.TUIC)).ToList();
var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard).ToList(); var lst2 = lstSelected.Where(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC).ToList();
for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++) for (var num = 0; num < (int)Math.Ceiling(lst1.Count * 1.0 / pageSize); num++)
{ {

View File

@@ -243,21 +243,6 @@ public class UpdateService
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo")); _updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
} }
public async Task<string> RunAvailabilityCheck()
{
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, Global.IPAPIUrl);
var ipInfo = JsonUtils.Deserialize<IPAPIInfo>(result);
ip = $"({ipInfo?.country_code}) {ipInfo?.ip}";
}
return string.Format(ResUI.TestMeOutput, time, ip);
}
#region CheckUpdate private #region CheckUpdate private
private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease) private async Task<RetResult> CheckUpdateAsync(DownloadService downloadHandle, ECoreType type, bool preRelease)

View File

@@ -174,6 +174,11 @@ 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();
@@ -229,7 +234,7 @@ public class ClashProxiesViewModel : MyReactiveObject
else else
{ {
SelectedGroup = _proxyGroups.First(); SelectedGroup = _proxyGroups.First();
} }
} }
else else
{ {
@@ -297,8 +302,10 @@ public class ClashProxiesViewModel : MyReactiveObject
private ProxiesItem? TryGetProxy(string name) private ProxiesItem? TryGetProxy(string name)
{ {
if (_proxies is null) if (_proxies == null)
{
return null; return null;
}
_proxies.TryGetValue(name, out var proxy2); _proxies.TryGetValue(name, out var proxy2);
if (proxy2 != null) if (proxy2 != null)
{ {

View File

@@ -548,8 +548,11 @@ public class MainWindowViewModel : MyReactiveObject
BlReloadEnabled = false; BlReloadEnabled = false;
await LoadCore(); await Task.Run(async () =>
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);

View File

@@ -70,6 +70,7 @@ public class OptionSettingViewModel : MyReactiveObject
[Reactive] public string GeoFileSourceUrl { get; set; } [Reactive] public string GeoFileSourceUrl { get; set; }
[Reactive] public string SrsFileSourceUrl { get; set; } [Reactive] public string SrsFileSourceUrl { get; set; }
[Reactive] public string RoutingRulesSourceUrl { get; set; } [Reactive] public string RoutingRulesSourceUrl { get; set; }
[Reactive] public string IPAPIUrl { get; set; }
#endregion UI #endregion UI
@@ -88,7 +89,6 @@ 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
@@ -187,6 +187,7 @@ public class OptionSettingViewModel : MyReactiveObject
GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl; GeoFileSourceUrl = _config.ConstItem.GeoSourceUrl;
SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl; SrsFileSourceUrl = _config.ConstItem.SrsSourceUrl;
RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl; RoutingRulesSourceUrl = _config.ConstItem.RouteRulesTemplateSourceUrl;
IPAPIUrl = _config.SpeedTestItem.IPAPIUrl;
#endregion UI #endregion UI
@@ -205,7 +206,6 @@ 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
@@ -346,6 +346,7 @@ public class OptionSettingViewModel : MyReactiveObject
_config.ConstItem.GeoSourceUrl = GeoFileSourceUrl; _config.ConstItem.GeoSourceUrl = GeoFileSourceUrl;
_config.ConstItem.SrsSourceUrl = SrsFileSourceUrl; _config.ConstItem.SrsSourceUrl = SrsFileSourceUrl;
_config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl; _config.ConstItem.RouteRulesTemplateSourceUrl = RoutingRulesSourceUrl;
_config.SpeedTestItem.IPAPIUrl = IPAPIUrl;
//systemProxy //systemProxy
_config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions; _config.SystemProxyItem.SystemProxyExceptions = systemProxyExceptions;
@@ -358,10 +359,6 @@ 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();

View File

@@ -318,7 +318,10 @@ public class StatusBarViewModel : MyReactiveObject
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting); _updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
var msg = await (new UpdateService()).RunAvailabilityCheck(); var msg = await Task.Run(async () =>
{
return await ConnectionHandler.Instance.RunAvailabilityCheck();
});
NoticeHandler.Instance.SendMessageEx(msg); NoticeHandler.Instance.SendMessageEx(msg);
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
@@ -433,11 +436,13 @@ public class StatusBarViewModel : MyReactiveObject
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin(); Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return; return;
} }
else if (Utils.IsOSX()) else
{ {
_config.TunModeItem.EnableTun = false; if (await _updateView?.Invoke(EViewAction.PasswordInput, null) == false)
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty); {
return; _config.TunModeItem.EnableTun = false;
return;
}
} }
} }
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
@@ -449,15 +454,15 @@ public class StatusBarViewModel : MyReactiveObject
{ {
if (Utils.IsWindows()) if (Utils.IsWindows())
{ {
return AppHandler.Instance.IsAdministrator; return Utils.IsAdministrator();
} }
else if (Utils.IsLinux()) else if (Utils.IsLinux())
{ {
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty(); return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
} }
else if (Utils.IsOSX()) else if (Utils.IsOSX())
{ {
return _config.TunModeItem.LinuxSudoPwd.IsNotEmpty(); return AppHandler.Instance.LinuxSudoPwd.IsNotEmpty();
} }
return false; return false;
} }

View File

@@ -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);
} }
} }

View File

@@ -52,9 +52,16 @@ public partial class ClashConnectionsView : ReactiveUserControl<ClashConnections
private void AutofitColumnWidth() private void AutofitColumnWidth()
{ {
foreach (var it in lstConnections.Columns) try
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); foreach (var it in lstConnections.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
catch (Exception ex)
{
Logging.SaveLog("ClashConnectionsView", ex);
} }
} }

View File

@@ -39,13 +39,13 @@
<MenuItem x:Name="menuAddVmessServer" Header="{x:Static resx:ResUI.menuAddVmessServer}" /> <MenuItem x:Name="menuAddVmessServer" Header="{x:Static resx:ResUI.menuAddVmessServer}" />
<MenuItem x:Name="menuAddVlessServer" Header="{x:Static resx:ResUI.menuAddVlessServer}" /> <MenuItem x:Name="menuAddVlessServer" Header="{x:Static resx:ResUI.menuAddVlessServer}" />
<MenuItem x:Name="menuAddShadowsocksServer" Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" /> <MenuItem x:Name="menuAddShadowsocksServer" Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" />
<MenuItem x:Name="menuAddTrojanServer" Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
<MenuItem x:Name="menuAddWireguardServer" Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
<MenuItem x:Name="menuAddSocksServer" Header="{x:Static resx:ResUI.menuAddSocksServer}" /> <MenuItem x:Name="menuAddSocksServer" Header="{x:Static resx:ResUI.menuAddSocksServer}" />
<MenuItem x:Name="menuAddHttpServer" Header="{x:Static resx:ResUI.menuAddHttpServer}" /> <MenuItem x:Name="menuAddHttpServer" Header="{x:Static resx:ResUI.menuAddHttpServer}" />
<MenuItem x:Name="menuAddTrojanServer" Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
<Separator /> <Separator />
<MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" /> <MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" /> <MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
<MenuItem x:Name="menuAddWireguardServer" Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
</MenuItem> </MenuItem>
<MenuItem Padding="8,0"> <MenuItem Padding="8,0">

View File

@@ -143,7 +143,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
} }
else else
{ {
if (AppHandler.Instance.IsAdministrator) if (Utils.IsAdministrator())
{ {
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}"; this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp); NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);

View File

@@ -343,7 +343,7 @@
<Grid <Grid
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
ColumnDefinitions="Auto,Auto,*" ColumnDefinitions="Auto,Auto,*"
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
<TextBlock <TextBlock
x:Name="tbAutoRun" x:Name="tbAutoRun"
@@ -655,6 +655,20 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}" Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
Grid.Row="25"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
<ComboBox
x:Name="cmbIPAPIUrl"
Grid.Row="25"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin4}" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>
@@ -784,28 +798,6 @@
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>

View File

@@ -92,6 +92,10 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
{ {
cmbRoutingRulesSourceUrl.Items.Add(it); cmbRoutingRulesSourceUrl.Items.Add(it);
}); });
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation))) foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{ {
cmbMainGirdOrientation.Items.Add(it.ToString()); cmbMainGirdOrientation.Items.Add(it.ToString());
@@ -143,6 +147,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);
@@ -153,7 +158,6 @@ 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);
@@ -170,10 +174,6 @@ 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;
} }

View File

@@ -345,9 +345,16 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
private void AutofitColumnWidth() private void AutofitColumnWidth()
{ {
foreach (var it in lstProfiles.Columns) try
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); foreach (var it in lstProfiles.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
catch (Exception ex)
{
Logging.SaveLog("ProfilesView", ex);
} }
} }

View File

@@ -4,6 +4,7 @@ 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;
@@ -81,6 +82,10 @@ 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);
} }
@@ -96,6 +101,20 @@ 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();

View File

@@ -0,0 +1,70 @@
<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>

View File

@@ -0,0 +1,33 @@
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);
};
}
}

View File

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

View File

@@ -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);
} }
} }

View File

@@ -55,9 +55,16 @@ public partial class ClashConnectionsView
private void AutofitColumnWidth() private void AutofitColumnWidth()
{ {
foreach (var it in lstConnections.Columns) try
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); foreach (var it in lstConnections.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
catch (Exception ex)
{
Logging.SaveLog("ClashConnectionsView", ex);
} }
} }

View File

@@ -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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
xmlns:view="clr-namespace:v2rayN.Views" xmlns:view="clr-namespace:v2rayN.Views"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="v2rayN" Title="v2rayN"
Width="900" Width="900"
Height="700" Height="700"
@@ -40,9 +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"> <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
@@ -81,6 +82,14 @@
x:Name="menuAddShadowsocksServer" x:Name="menuAddShadowsocksServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" /> Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" />
<MenuItem
x:Name="menuAddTrojanServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
<MenuItem
x:Name="menuAddWireguardServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
<MenuItem <MenuItem
x:Name="menuAddSocksServer" x:Name="menuAddSocksServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
@@ -89,10 +98,6 @@
x:Name="menuAddHttpServer" x:Name="menuAddHttpServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddHttpServer}" /> Header="{x:Static resx:ResUI.menuAddHttpServer}" />
<MenuItem
x:Name="menuAddTrojanServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
<Separator Margin="-40,5" /> <Separator Margin="-40,5" />
<MenuItem <MenuItem
x:Name="menuAddHysteria2Server" x:Name="menuAddHysteria2Server"
@@ -102,15 +107,11 @@
x:Name="menuAddTuicServer" x:Name="menuAddTuicServer"
Height="{StaticResource MenuItemHeight}" Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddTuicServer}" /> Header="{x:Static resx:ResUI.menuAddTuicServer}" />
<MenuItem
x:Name="menuAddWireguardServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
</MenuItem> </MenuItem>
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <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
@@ -145,7 +146,7 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Padding="8,0"> <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
@@ -211,7 +212,10 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuReload" Padding="8,0"> <MenuItem
x:Name="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
@@ -225,7 +229,10 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem Name="menuCheckUpdate" Padding="8,0"> <MenuItem
Name="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
@@ -239,7 +246,10 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuHelp" Padding="8,0"> <MenuItem
x:Name="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
@@ -253,7 +263,10 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuPromotion" Padding="8,0"> <MenuItem
x:Name="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
@@ -267,7 +280,10 @@
</Menu> </Menu>
<Separator /> <Separator />
<Menu Margin="0,1" Style="{StaticResource ToolbarMenu}"> <Menu Margin="0,1" Style="{StaticResource ToolbarMenu}">
<MenuItem x:Name="menuClose" Padding="8,0"> <MenuItem
x:Name="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

View File

@@ -132,7 +132,7 @@ public partial class MainWindow
} }
}); });
this.Title = $"{Utils.GetVersion()} - {(AppHandler.Instance.IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
if (!_config.GuiItem.EnableHWA) if (!_config.GuiItem.EnableHWA)
{ {

View File

@@ -26,6 +26,7 @@
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
AutomationProperties.Name="{x:Static resx:ResUI.MsgFilterTitle}"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<Button <Button
@@ -33,6 +34,7 @@
Width="24" Width="24"
Height="24" Height="24"
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
AutomationProperties.Name="{x:Static resx:ResUI.menuMsgViewCopyAll}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuMsgViewCopyAll}"> ToolTip="{x:Static resx:ResUI.menuMsgViewCopyAll}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ContentCopy" /> <materialDesign:PackIcon VerticalAlignment="Center" Kind="ContentCopy" />
@@ -42,6 +44,7 @@
Width="24" Width="24"
Height="24" Height="24"
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
AutomationProperties.Name="{x:Static resx:ResUI.menuMsgViewClear}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}" Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuMsgViewClear}"> ToolTip="{x:Static resx:ResUI.menuMsgViewClear}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Delete" /> <materialDesign:PackIcon VerticalAlignment="Center" Kind="Delete" />
@@ -55,6 +58,7 @@
x:Name="togAutoRefresh" x:Name="togAutoRefresh"
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
AutomationProperties.Name="{x:Static resx:ResUI.TbAutoRefresh}"
IsChecked="True" /> IsChecked="True" />
<TextBlock <TextBlock
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
@@ -65,6 +69,7 @@
x:Name="togScrollToEnd" x:Name="togScrollToEnd"
Margin="{StaticResource MarginLeftRight8}" Margin="{StaticResource MarginLeftRight8}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
AutomationProperties.Name="{x:Static resx:ResUI.TbAutoScrollToEnd}"
IsChecked="True" /> IsChecked="True" />
</WrapPanel> </WrapPanel>
<TextBox <TextBox
@@ -103,4 +108,4 @@
</TextBox.ContextMenu> </TextBox.ContextMenu>
</TextBox> </TextBox>
</DockPanel> </DockPanel>
</reactiveui:ReactiveUserControl> </reactiveui:ReactiveUserControl>

View File

@@ -552,6 +552,7 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -942,6 +943,22 @@
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}" Text="{x:Static resx:ResUI.TbSettingsChinaUserTip}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
Grid.Row="25"
Grid.Column="0"
Margin="{StaticResource Margin8}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbSettingsIPAPIUrl}" />
<ComboBox
x:Name="cmbIPAPIUrl"
Grid.Row="25"
Grid.Column="1"
Width="300"
Margin="{StaticResource Margin8}"
IsEditable="True"
Style="{StaticResource DefComboBox}" />
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</TabItem> </TabItem>

View File

@@ -101,6 +101,10 @@ public partial class OptionSettingWindow
{ {
cmbRoutingRulesSourceUrl.Items.Add(it); cmbRoutingRulesSourceUrl.Items.Add(it);
}); });
Global.IPAPIUrls.ForEach(it =>
{
cmbIPAPIUrl.Items.Add(it);
});
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation))) foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
{ {
cmbMainGirdOrientation.Items.Add(it.ToString()); cmbMainGirdOrientation.Items.Add(it.ToString());
@@ -162,6 +166,7 @@ public partial class OptionSettingWindow
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.IPAPIUrl, v => v.cmbIPAPIUrl.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.Text).DisposeWith(disposables);

View File

@@ -18,6 +18,9 @@
<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>
@@ -26,8 +29,9 @@
x:Name="lstGroup" x:Name="lstGroup"
MaxHeight="200" MaxHeight="200"
FontSize="{DynamicResource StdFontSize}" FontSize="{DynamicResource StdFontSize}"
ItemContainerStyle="{StaticResource MyChipListBoxItem}" ItemContainerStyle="{StaticResource AccessibleMyChipListBoxItem}"
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}" />
@@ -40,6 +44,7 @@
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}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" /> <materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
@@ -49,6 +54,7 @@
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}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" /> <materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
@@ -59,6 +65,7 @@
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}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" /> <materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
@@ -70,6 +77,7 @@
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}" />
</WrapPanel> </WrapPanel>
<DataGrid <DataGrid

View File

@@ -323,9 +323,16 @@ public partial class ProfilesView
private void AutofitColumnWidth() private void AutofitColumnWidth()
{ {
foreach (var it in lstProfiles.Columns) try
{ {
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto); foreach (var it in lstProfiles.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
catch (Exception ex)
{
Logging.SaveLog("ProfilesView", ex);
} }
} }

View File

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

View File

@@ -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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}" Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"

View File

@@ -61,7 +61,8 @@
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}" />
</StackPanel> </StackPanel>
<StackPanel <StackPanel
@@ -74,6 +75,7 @@
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}">
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" /> <ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
@@ -87,9 +89,16 @@
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>
<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">
@@ -107,7 +116,10 @@
ToolTipText="v2rayN"> ToolTipText="v2rayN">
<tb:TaskbarIcon.ContextMenu> <tb:TaskbarIcon.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}"> <ContextMenu Style="{StaticResource DefContextMenu}">
<MenuItem x:Name="menuSystemProxyClear" Height="{StaticResource MenuItemHeight}"> <MenuItem
x:Name="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
@@ -119,7 +131,10 @@
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<MenuItem x:Name="menuSystemProxySet" Height="{StaticResource MenuItemHeight}"> <MenuItem
x:Name="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
@@ -131,7 +146,10 @@
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<MenuItem x:Name="menuSystemProxyNothing" Height="{StaticResource MenuItemHeight}"> <MenuItem
x:Name="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
@@ -143,7 +161,10 @@
</StackPanel> </StackPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<MenuItem x:Name="menuSystemProxyPac" Height="{StaticResource MenuItemHeight}"> <MenuItem
x:Name="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
@@ -156,29 +177,46 @@
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<Separator x:Name="sepRoutings" /> <Separator x:Name="sepRoutings" />
<MenuItem x:Name="menuRoutings" Height="Auto"> <MenuItem
x:Name="menuRoutings"
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>
<Style TargetType="ComboBoxItem">
<Setter Property="AutomationProperties.Name" Value="{Binding Remarks}" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>
<MenuItem Height="Auto"> <MenuItem Height="Auto" AutomationProperties.Name="{x:Static resx:ResUI.menuServers}">
<MenuItem.Header> <MenuItem.Header>
<DockPanel> <DockPanel>
<ComboBox <ComboBox
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>
<Style TargetType="ComboBoxItem">
<Setter Property="AutomationProperties.Name" Value="{Binding Text}" />
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DockPanel> </DockPanel>
</MenuItem.Header> </MenuItem.Header>
</MenuItem> </MenuItem>

View File

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

View File

@@ -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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:reactiveui="http://reactiveui.net"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="{x:Static resx:ResUI.menuSubSetting}" Title="{x:Static resx:ResUI.menuSubSetting}"

View File

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