Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ab1b9068f | ||
|
|
b9613875ce | ||
|
|
5d2aea6b4f | ||
|
|
5824e18ed6 | ||
|
|
4f8648cbc9 | ||
|
|
01b021b2c3 | ||
|
|
331e8ce960 | ||
|
|
a2cfe6fa51 | ||
|
|
8381fefb78 | ||
|
|
d3b95d781a | ||
|
|
3a4a96f87a | ||
|
|
3d462c4be3 | ||
|
|
82b366cd9b | ||
|
|
897a4e5635 | ||
|
|
8ea76fd318 | ||
|
|
693a96fff2 | ||
|
|
8b4e2f8f23 | ||
|
|
13b164acac | ||
|
|
e590547b30 | ||
|
|
5a0fdd971a | ||
|
|
514dce960a | ||
|
|
6ee6fb1706 | ||
|
|
6985328653 | ||
|
|
41c406b84d | ||
|
|
30f7f2c563 | ||
|
|
be3dbfb8e3 | ||
|
|
9b92259e80 | ||
|
|
1c04144573 | ||
|
|
adf3b955d6 | ||
|
|
0032a3d27a | ||
|
|
c6d347d49a | ||
|
|
ea42246d1b | ||
|
|
3f19958c75 | ||
|
|
35788158bc | ||
|
|
4fd494ded4 | ||
|
|
23eeb8ff55 | ||
|
|
456ffb200a | ||
|
|
18e0bb194e | ||
|
|
392f6111dd | ||
|
|
ce6572af3d | ||
|
|
cf59137481 | ||
|
|
519e588124 | ||
|
|
666c874998 | ||
|
|
5f9f677467 | ||
|
|
b06b5779dd | ||
|
|
e3a3b9c201 | ||
|
|
321ec30f39 | ||
|
|
5adae2dd2a | ||
|
|
be5e15dfb6 | ||
|
|
15d3418c79 | ||
|
|
0efb0228c6 | ||
|
|
75b399b48b |
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.11.0</Version>
|
<Version>7.12.4</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.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" />
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ public class AesUtils
|
|||||||
private const int KeySize = 256; // AES-256
|
private const int KeySize = 256; // AES-256
|
||||||
private const int IvSize = 16; // AES block size
|
private const int IvSize = 16; // AES block size
|
||||||
private const int Iterations = 10000;
|
private const int Iterations = 10000;
|
||||||
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
|
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' '));
|
||||||
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Text.Encodings.Web;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
@@ -86,7 +87,8 @@ public class JsonUtils
|
|||||||
var options = new JsonSerializerOptions
|
var options = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = indented,
|
WriteIndented = indented,
|
||||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
};
|
};
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class YamlUtils
|
|||||||
#region YAML
|
#region YAML
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 反序列化成对象
|
/// Deserialize
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
@@ -34,7 +34,7 @@ public class YamlUtils
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 序列化
|
/// Serialize
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public enum EViewAction
|
|||||||
BrowseServer,
|
BrowseServer,
|
||||||
ImportRulesFromFile,
|
ImportRulesFromFile,
|
||||||
InitSettingFont,
|
InitSettingFont,
|
||||||
|
PasswordInput,
|
||||||
SubEditWindow,
|
SubEditWindow,
|
||||||
RoutingRuleSettingWindow,
|
RoutingRuleSettingWindow,
|
||||||
RoutingRuleDetailsWindow,
|
RoutingRuleDetailsWindow,
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -125,7 +123,7 @@ public class Global
|
|||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
||||||
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
|
@"https://github.com/Chocolate4U/Iran-v2ray-rules/releases/latest/download/{0}.dat"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxRulesetSources =
|
public static readonly List<string> SingboxRulesetSources =
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace ServiceLib.Handler;
|
namespace ServiceLib.Handler;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本软件配置文件处理类
|
|
||||||
/// </summary>
|
|
||||||
public class ConfigHandler
|
public class ConfigHandler
|
||||||
{
|
{
|
||||||
private static readonly string _configRes = Global.ConfigFileName;
|
private static readonly string _configRes = Global.ConfigFileName;
|
||||||
@@ -14,10 +11,12 @@ public class ConfigHandler
|
|||||||
#region ConfigHandler
|
#region ConfigHandler
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 载入配置文件
|
/// Load the application configuration file
|
||||||
|
/// If the file exists, deserialize it from JSON
|
||||||
|
/// If not found, create a new Config object with default settings
|
||||||
|
/// Initialize default values for missing configuration sections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <returns>Config object containing application settings or null if there's an error</returns>
|
||||||
/// <returns></returns>
|
|
||||||
public static Config? LoadConfig()
|
public static Config? LoadConfig()
|
||||||
{
|
{
|
||||||
Config? config = null;
|
Config? config = null;
|
||||||
@@ -123,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)
|
||||||
{
|
{
|
||||||
@@ -169,10 +168,11 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保参数
|
/// Save the configuration to a file
|
||||||
|
/// First writes to a temporary file, then replaces the original file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Configuration object to be saved</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> SaveConfig(Config config)
|
public static async Task<int> SaveConfig(Config config)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -204,6 +204,13 @@ public class ConfigHandler
|
|||||||
|
|
||||||
#region Server
|
#region Server
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a server profile to the configuration
|
||||||
|
/// Dispatches the request to the appropriate method based on the config type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="profileItem">Server profile to add</param>
|
||||||
|
/// <returns>Result of the operation (0 if successful, -1 if failed)</returns>
|
||||||
public static async Task<int> AddServer(Config config, ProfileItem profileItem)
|
public static async Task<int> AddServer(Config config, ProfileItem profileItem)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetProfileItem(profileItem.IndexId);
|
var item = await AppHandler.Instance.GetProfileItem(profileItem.IndexId);
|
||||||
@@ -258,11 +265,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a VMess server
|
||||||
|
/// Validates and processes VMess-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">VMess profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddVMessServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddVMessServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.VMess;
|
profileItem.ConfigType = EConfigType.VMess;
|
||||||
@@ -291,11 +300,11 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除服务器
|
/// Remove multiple servers from the configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="indexes"></param>
|
/// <param name="indexes">List of server profiles to remove</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> RemoveServers(Config config, List<ProfileItem> indexes)
|
public static async Task<int> RemoveServers(Config config, List<ProfileItem> indexes)
|
||||||
{
|
{
|
||||||
var subid = "TempRemoveSubId";
|
var subid = "TempRemoveSubId";
|
||||||
@@ -311,11 +320,12 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 克隆服务器
|
/// Clone server profiles
|
||||||
|
/// Creates copies of the specified server profiles with "-clone" appended to the remarks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="index"></param>
|
/// <param name="indexes">List of server profiles to clone</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> CopyServer(Config config, List<ProfileItem> indexes)
|
public static async Task<int> CopyServer(Config config, List<ProfileItem> indexes)
|
||||||
{
|
{
|
||||||
foreach (var it in indexes)
|
foreach (var it in indexes)
|
||||||
@@ -347,11 +357,12 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置活动服务器
|
/// Set the default server by its index ID
|
||||||
|
/// Updates the configuration to use the specified server as default
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="item"></param>
|
/// <param name="indexId">Index ID of the server to set as default</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> SetDefaultServerIndex(Config config, string? indexId)
|
public static async Task<int> SetDefaultServerIndex(Config config, string? indexId)
|
||||||
{
|
{
|
||||||
if (indexId.IsNullOrEmpty())
|
if (indexId.IsNullOrEmpty())
|
||||||
@@ -366,6 +377,13 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set a default server from the provided list of profiles
|
||||||
|
/// Ensures there's always a valid default server selected
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="lstProfile">List of profile models to choose from</param>
|
||||||
|
/// <returns>Result of SetDefaultServerIndex operation</returns>
|
||||||
public static async Task<int> SetDefaultServer(Config config, List<ProfileItemModel> lstProfile)
|
public static async Task<int> SetDefaultServer(Config config, List<ProfileItemModel> lstProfile)
|
||||||
{
|
{
|
||||||
if (lstProfile.Exists(t => t.IndexId == config.IndexId))
|
if (lstProfile.Exists(t => t.IndexId == config.IndexId))
|
||||||
@@ -386,6 +404,12 @@ public class ConfigHandler
|
|||||||
return await SetDefaultServerIndex(config, item?.IndexId);
|
return await SetDefaultServerIndex(config, item?.IndexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the current default server profile
|
||||||
|
/// If the current default is invalid, selects a new default
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <returns>The default profile item or null if none exists</returns>
|
||||||
public static async Task<ProfileItem?> GetDefaultServer(Config config)
|
public static async Task<ProfileItem?> GetDefaultServer(Config config)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetProfileItem(config.IndexId);
|
var item = await AppHandler.Instance.GetProfileItem(config.IndexId);
|
||||||
@@ -400,13 +424,15 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移动服务器
|
/// Move a server in the list to a different position
|
||||||
|
/// Supports moving to top, up, down, bottom or specific position
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="lstProfile"></param>
|
/// <param name="lstProfile">List of server profiles</param>
|
||||||
/// <param name="index"></param>
|
/// <param name="index">Index of the server to move</param>
|
||||||
/// <param name="eMove"></param>
|
/// <param name="eMove">Direction to move the server</param>
|
||||||
/// <returns></returns>
|
/// <param name="pos">Target position when using EMove.Position</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> MoveServer(Config config, List<ProfileItem> lstProfile, int index, EMove eMove, int pos = -1)
|
public static async Task<int> MoveServer(Config config, List<ProfileItem> lstProfile, int index, EMove eMove, int pos = -1)
|
||||||
{
|
{
|
||||||
int count = lstProfile.Count;
|
int count = lstProfile.Count;
|
||||||
@@ -474,11 +500,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加自定义服务器
|
/// Add a custom server configuration from a file
|
||||||
|
/// Copies the configuration file to the app's config directory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">Profile item with the file path in Address</param>
|
||||||
/// <returns></returns>
|
/// <param name="blDelete">Whether to delete the source file after copying</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddCustomServer(Config config, ProfileItem profileItem, bool blDelete)
|
public static async Task<int> AddCustomServer(Config config, ProfileItem profileItem, bool blDelete)
|
||||||
{
|
{
|
||||||
var fileName = profileItem.Address;
|
var fileName = profileItem.Address;
|
||||||
@@ -517,11 +545,12 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Edit an existing custom server configuration
|
||||||
|
/// Updates the server's properties without changing the file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">Profile item with updated properties</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> EditCustomServer(Config config, ProfileItem profileItem)
|
public static async Task<int> EditCustomServer(Config config, ProfileItem profileItem)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetProfileItem(profileItem.IndexId);
|
var item = await AppHandler.Instance.GetProfileItem(profileItem.IndexId);
|
||||||
@@ -551,11 +580,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a Shadowsocks server
|
||||||
|
/// Validates and processes Shadowsocks-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">Shadowsocks profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddShadowsocksServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddShadowsocksServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.Shadowsocks;
|
profileItem.ConfigType = EConfigType.Shadowsocks;
|
||||||
@@ -579,11 +610,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a SOCKS server
|
||||||
|
/// Processes SOCKS-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">SOCKS profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddSocksServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddSocksServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.SOCKS;
|
profileItem.ConfigType = EConfigType.SOCKS;
|
||||||
@@ -596,11 +629,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit an HTTP server
|
||||||
|
/// Processes HTTP-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">HTTP profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddHttpServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddHttpServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.HTTP;
|
profileItem.ConfigType = EConfigType.HTTP;
|
||||||
@@ -613,11 +648,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a Trojan server
|
||||||
|
/// Validates and processes Trojan-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">Trojan profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddTrojanServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddTrojanServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.Trojan;
|
profileItem.ConfigType = EConfigType.Trojan;
|
||||||
@@ -639,11 +676,14 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a Hysteria2 server
|
||||||
|
/// Validates and processes Hysteria2-specific settings
|
||||||
|
/// Sets the core type to sing_box as required by Hysteria2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">Hysteria2 profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddHysteria2Server(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddHysteria2Server(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.Hysteria2;
|
profileItem.ConfigType = EConfigType.Hysteria2;
|
||||||
@@ -669,11 +709,14 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a TUIC server
|
||||||
|
/// Validates and processes TUIC-specific settings
|
||||||
|
/// Sets the core type to sing_box as required by TUIC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">TUIC profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddTuicServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddTuicServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.TUIC;
|
profileItem.ConfigType = EConfigType.TUIC;
|
||||||
@@ -708,15 +751,16 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a WireGuard server
|
||||||
|
/// Validates and processes WireGuard-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">WireGuard profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddWireguardServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddWireguardServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.WireGuard;
|
profileItem.ConfigType = EConfigType.WireGuard;
|
||||||
profileItem.CoreType = ECoreType.sing_box;
|
|
||||||
|
|
||||||
profileItem.Address = profileItem.Address.TrimEx();
|
profileItem.Address = profileItem.Address.TrimEx();
|
||||||
profileItem.Id = profileItem.Id.TrimEx();
|
profileItem.Id = profileItem.Id.TrimEx();
|
||||||
@@ -739,6 +783,15 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sort the server list by the specified column
|
||||||
|
/// Updates the sort order in the profile extension data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="subId">Subscription ID to filter servers</param>
|
||||||
|
/// <param name="colName">Column name to sort by</param>
|
||||||
|
/// <param name="asc">Sort in ascending order if true, descending if false</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> SortServers(Config config, string subId, string colName, bool asc)
|
public static async Task<int> SortServers(Config config, string subId, string colName, bool asc)
|
||||||
{
|
{
|
||||||
var lstModel = await AppHandler.Instance.ProfileItems(subId, "");
|
var lstModel = await AppHandler.Instance.ProfileItems(subId, "");
|
||||||
@@ -746,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
|
||||||
@@ -762,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);
|
||||||
@@ -780,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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -796,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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -832,11 +900,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add or edit server
|
/// Add or edit a VLESS server
|
||||||
|
/// Validates and processes VLESS-specific settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="profileItem"></param>
|
/// <param name="profileItem">VLESS profile to add</param>
|
||||||
/// <returns></returns>
|
/// <param name="toFile">Whether to save to file</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddVlessServer(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddVlessServer(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigType = EConfigType.VLESS;
|
profileItem.ConfigType = EConfigType.VLESS;
|
||||||
@@ -868,6 +938,13 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove duplicate servers from a subscription
|
||||||
|
/// Compares servers based on their properties rather than just names
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="subId">Subscription ID to deduplicate</param>
|
||||||
|
/// <returns>Tuple with total count and remaining count after deduplication</returns>
|
||||||
public static async Task<Tuple<int, int>> DedupServerList(Config config, string subId)
|
public static async Task<Tuple<int, int>> DedupServerList(Config config, string subId)
|
||||||
{
|
{
|
||||||
var lstProfile = await AppHandler.Instance.ProfileItems(subId);
|
var lstProfile = await AppHandler.Instance.ProfileItems(subId);
|
||||||
@@ -899,6 +976,14 @@ public class ConfigHandler
|
|||||||
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Common server addition logic used by all server types
|
||||||
|
/// Sets common properties and handles sorting and persistence
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="profileItem">Profile item to add</param>
|
||||||
|
/// <param name="toFile">Whether to save to database</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> AddServerCommon(Config config, ProfileItem profileItem, bool toFile = true)
|
public static async Task<int> AddServerCommon(Config config, ProfileItem profileItem, bool toFile = true)
|
||||||
{
|
{
|
||||||
profileItem.ConfigVersion = 2;
|
profileItem.ConfigVersion = 2;
|
||||||
@@ -950,6 +1035,14 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compare two profile items to determine if they represent the same server
|
||||||
|
/// Used for deduplication and server matching
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">First profile item</param>
|
||||||
|
/// <param name="n">Second profile item</param>
|
||||||
|
/// <param name="remarks">Whether to compare remarks</param>
|
||||||
|
/// <returns>True if the profiles match, false otherwise</returns>
|
||||||
private static bool CompareProfileItem(ProfileItem? o, ProfileItem? n, bool remarks)
|
private static bool CompareProfileItem(ProfileItem? o, ProfileItem? n, bool remarks)
|
||||||
{
|
{
|
||||||
if (o == null || n == null)
|
if (o == null || n == null)
|
||||||
@@ -981,6 +1074,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a single server profile by its index ID
|
||||||
|
/// Deletes the configuration file if it's a custom config
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="indexId">Index ID of the profile to remove</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
private static async Task<int> RemoveProfileItem(Config config, string indexId)
|
private static async Task<int> RemoveProfileItem(Config config, string indexId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1005,6 +1105,15 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a custom server that combines multiple servers for load balancing
|
||||||
|
/// Generates a configuration file that references multiple servers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="selecteds">Selected servers to combine</param>
|
||||||
|
/// <param name="coreType">Core type to use (Xray or sing_box)</param>
|
||||||
|
/// <param name="multipleLoad">Load balancing algorithm</param>
|
||||||
|
/// <returns>Result object with success state and data</returns>
|
||||||
public static async Task<RetResult> AddCustomServer4Multiple(Config config, List<ProfileItem> selecteds, ECoreType coreType, EMultipleLoad multipleLoad)
|
public static async Task<RetResult> AddCustomServer4Multiple(Config config, List<ProfileItem> selecteds, ECoreType coreType, EMultipleLoad multipleLoad)
|
||||||
{
|
{
|
||||||
var indexId = Utils.GetMd5(Global.CoreMultipleLoadConfigFileName);
|
var indexId = Utils.GetMd5(Global.CoreMultipleLoadConfigFileName);
|
||||||
@@ -1023,14 +1132,21 @@ public class ConfigHandler
|
|||||||
|
|
||||||
var profileItem = await AppHandler.Instance.GetProfileItem(indexId) ?? new();
|
var profileItem = await AppHandler.Instance.GetProfileItem(indexId) ?? new();
|
||||||
profileItem.IndexId = indexId;
|
profileItem.IndexId = indexId;
|
||||||
profileItem.Remarks = multipleLoad switch
|
if (coreType == ECoreType.Xray)
|
||||||
{
|
{
|
||||||
EMultipleLoad.Random => ResUI.menuSetDefaultMultipleServerXrayRandom,
|
profileItem.Remarks = multipleLoad switch
|
||||||
EMultipleLoad.RoundRobin => ResUI.menuSetDefaultMultipleServerXrayRoundRobin,
|
{
|
||||||
EMultipleLoad.LeastPing => ResUI.menuSetDefaultMultipleServerXrayLeastPing,
|
EMultipleLoad.Random => ResUI.menuSetDefaultMultipleServerXrayRandom,
|
||||||
EMultipleLoad.LeastLoad => ResUI.menuSetDefaultMultipleServerXrayLeastLoad,
|
EMultipleLoad.RoundRobin => ResUI.menuSetDefaultMultipleServerXrayRoundRobin,
|
||||||
_ => ResUI.menuSetDefaultMultipleServerXrayRoundRobin,
|
EMultipleLoad.LeastPing => ResUI.menuSetDefaultMultipleServerXrayLeastPing,
|
||||||
};
|
EMultipleLoad.LeastLoad => ResUI.menuSetDefaultMultipleServerXrayLeastLoad,
|
||||||
|
_ => ResUI.menuSetDefaultMultipleServerXrayRoundRobin,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (coreType == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
profileItem.Remarks = ResUI.menuSetDefaultMultipleServerSingBoxLeastPing;
|
||||||
|
}
|
||||||
profileItem.Address = Global.CoreMultipleLoadConfigFileName;
|
profileItem.Address = Global.CoreMultipleLoadConfigFileName;
|
||||||
profileItem.ConfigType = EConfigType.Custom;
|
profileItem.ConfigType = EConfigType.Custom;
|
||||||
profileItem.CoreType = coreType;
|
profileItem.CoreType = coreType;
|
||||||
@@ -1041,6 +1157,14 @@ public class ConfigHandler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a SOCKS server profile for pre-SOCKS functionality
|
||||||
|
/// Used when TUN mode is enabled or when a custom config has a pre-SOCKS port
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="node">Server node that might need pre-SOCKS</param>
|
||||||
|
/// <param name="coreType">Core type being used</param>
|
||||||
|
/// <returns>A SOCKS profile item or null if not needed</returns>
|
||||||
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
||||||
{
|
{
|
||||||
ProfileItem? itemSocks = null;
|
ProfileItem? itemSocks = null;
|
||||||
@@ -1070,6 +1194,13 @@ public class ConfigHandler
|
|||||||
return itemSocks;
|
return itemSocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove servers with invalid test results (timeout)
|
||||||
|
/// Useful for cleaning up subscription lists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="subid">Subscription ID to filter servers</param>
|
||||||
|
/// <returns>Number of removed servers or -1 if failed</returns>
|
||||||
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
|
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
|
||||||
{
|
{
|
||||||
var lstModel = await AppHandler.Instance.ProfileItems(subid, "");
|
var lstModel = await AppHandler.Instance.ProfileItems(subid, "");
|
||||||
@@ -1093,12 +1224,14 @@ public class ConfigHandler
|
|||||||
#region Batch add servers
|
#region Batch add servers
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量添加服务器
|
/// Add multiple servers from string data (common protocols)
|
||||||
|
/// Parses the string data into server profiles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="strData"></param>
|
/// <param name="strData">String data containing server information</param>
|
||||||
/// <param name="subid"></param>
|
/// <param name="subid">Subscription ID to associate with the servers</param>
|
||||||
/// <returns>成功导入的数量</returns>
|
/// <param name="isSub">Whether this is from a subscription</param>
|
||||||
|
/// <returns>Number of successfully imported servers or -1 if failed</returns>
|
||||||
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (strData.IsNullOrEmpty())
|
if (strData.IsNullOrEmpty())
|
||||||
@@ -1178,6 +1311,15 @@ public class ConfigHandler
|
|||||||
return countServers;
|
return countServers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add servers from custom configuration formats (sing-box, v2ray, etc.)
|
||||||
|
/// Handles various configuration formats and imports them as custom configs
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="strData">String data containing server information</param>
|
||||||
|
/// <param name="subid">Subscription ID to associate with the servers</param>
|
||||||
|
/// <param name="isSub">Whether this is from a subscription</param>
|
||||||
|
/// <returns>Number of successfully imported servers or -1 if failed</returns>
|
||||||
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (strData.IsNullOrEmpty())
|
if (strData.IsNullOrEmpty())
|
||||||
@@ -1276,6 +1418,15 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add Shadowsocks servers from SIP008 format
|
||||||
|
/// SIP008 is a JSON-based format for Shadowsocks servers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="strData">String data in SIP008 format</param>
|
||||||
|
/// <param name="subid">Subscription ID to associate with the servers</param>
|
||||||
|
/// <param name="isSub">Whether this is from a subscription</param>
|
||||||
|
/// <returns>Number of successfully imported servers or -1 if failed</returns>
|
||||||
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (strData.IsNullOrEmpty())
|
if (strData.IsNullOrEmpty())
|
||||||
@@ -1308,6 +1459,15 @@ public class ConfigHandler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main entry point for adding batch servers from various formats
|
||||||
|
/// Tries different parsing methods to import as many servers as possible
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="strData">String data containing server information</param>
|
||||||
|
/// <param name="subid">Subscription ID to associate with the servers</param>
|
||||||
|
/// <param name="isSub">Whether this is from a subscription</param>
|
||||||
|
/// <returns>Number of successfully imported servers or -1 if failed</returns>
|
||||||
public static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub)
|
public static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (strData.IsNullOrEmpty())
|
if (strData.IsNullOrEmpty())
|
||||||
@@ -1380,11 +1540,12 @@ public class ConfigHandler
|
|||||||
#region Sub & Group
|
#region Sub & Group
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// add sub
|
/// Add a subscription item from URL
|
||||||
|
/// Creates a new subscription with default settings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="url"></param>
|
/// <param name="url">Subscription URL</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddSubItem(Config config, string url)
|
public static async Task<int> AddSubItem(Config config, string url)
|
||||||
{
|
{
|
||||||
//already exists
|
//already exists
|
||||||
@@ -1416,6 +1577,12 @@ public class ConfigHandler
|
|||||||
return await AddSubItem(config, subItem);
|
return await AddSubItem(config, subItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add or update a subscription item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="subItem">Subscription item to add or update</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddSubItem(Config config, SubItem subItem)
|
public static async Task<int> AddSubItem(Config config, SubItem subItem)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetSubItem(subItem.Id);
|
var item = await AppHandler.Instance.GetSubItem(subItem.Id);
|
||||||
@@ -1467,11 +1634,12 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除服务器
|
/// Remove servers associated with a subscription ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">Current configuration</param>
|
||||||
/// <param name="subid"></param>
|
/// <param name="subid">Subscription ID</param>
|
||||||
/// <returns></returns>
|
/// <param name="isSub">Whether to only remove servers marked as subscription items</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> RemoveServersViaSubid(Config config, string subid, bool isSub)
|
public static async Task<int> RemoveServersViaSubid(Config config, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (subid.IsNullOrEmpty())
|
if (subid.IsNullOrEmpty())
|
||||||
@@ -1495,6 +1663,12 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a subscription item and all its associated servers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="id">Subscription ID to delete</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> DeleteSubItem(Config config, string id)
|
public static async Task<int> DeleteSubItem(Config config, string id)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetSubItem(id);
|
var item = await AppHandler.Instance.GetSubItem(id);
|
||||||
@@ -1508,6 +1682,13 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move servers to a different group (subscription)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="lstProfile">List of profiles to move</param>
|
||||||
|
/// <param name="subid">Target subscription ID</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> MoveToGroup(Config config, List<ProfileItem> lstProfile, string subid)
|
public static async Task<int> MoveToGroup(Config config, List<ProfileItem> lstProfile, string subid)
|
||||||
{
|
{
|
||||||
foreach (var item in lstProfile)
|
foreach (var item in lstProfile)
|
||||||
@@ -1523,6 +1704,12 @@ public class ConfigHandler
|
|||||||
|
|
||||||
#region Routing
|
#region Routing
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save a routing item to the database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="item">Routing item to save</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> SaveRoutingItem(Config config, RoutingItem item)
|
public static async Task<int> SaveRoutingItem(Config config, RoutingItem item)
|
||||||
{
|
{
|
||||||
if (item.Id.IsNullOrEmpty())
|
if (item.Id.IsNullOrEmpty())
|
||||||
@@ -1541,11 +1728,11 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AddBatchRoutingRules
|
/// Add multiple routing rules to a routing item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config"></param>
|
/// <param name="routingItem">Routing item to add rules to</param>
|
||||||
/// <param name="strData"></param>
|
/// <param name="strData">JSON string containing rules data</param>
|
||||||
/// <returns></returns>
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> AddBatchRoutingRules(RoutingItem routingItem, string strData)
|
public static async Task<int> AddBatchRoutingRules(RoutingItem routingItem, string strData)
|
||||||
{
|
{
|
||||||
if (strData.IsNullOrEmpty())
|
if (strData.IsNullOrEmpty())
|
||||||
@@ -1582,12 +1769,14 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MoveRoutingRule
|
/// Move a routing rule within a rules list
|
||||||
|
/// Supports moving to top, up, down, bottom or specific position
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="routingItem"></param>
|
/// <param name="rules">List of routing rules</param>
|
||||||
/// <param name="index"></param>
|
/// <param name="index">Index of the rule to move</param>
|
||||||
/// <param name="eMove"></param>
|
/// <param name="eMove">Direction to move the rule</param>
|
||||||
/// <returns></returns>
|
/// <param name="pos">Target position when using EMove.Position</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> MoveRoutingRule(List<RulesItem> rules, int index, EMove eMove, int pos = -1)
|
public static async Task<int> MoveRoutingRule(List<RulesItem> rules, int index, EMove eMove, int pos = -1)
|
||||||
{
|
{
|
||||||
int count = rules.Count;
|
int count = rules.Count;
|
||||||
@@ -1658,6 +1847,12 @@ public class ConfigHandler
|
|||||||
return await Task.FromResult(0);
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the default routing configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="routingItem">Routing item to set as default</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
||||||
{
|
{
|
||||||
if (await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(t => t.Id == routingItem.Id).CountAsync() > 0)
|
if (await SQLiteHelper.Instance.TableAsync<RoutingItem>().Where(t => t.Id == routingItem.Id).CountAsync() > 0)
|
||||||
@@ -1670,6 +1865,12 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the current default routing configuration
|
||||||
|
/// If no default is set, selects the first available routing item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <returns>The default routing item</returns>
|
||||||
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
public static async Task<RoutingItem> GetDefaultRouting(Config config)
|
||||||
{
|
{
|
||||||
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
|
var item = await AppHandler.Instance.GetRoutingItem(config.RoutingBasicItem.RoutingIndexId);
|
||||||
@@ -1683,6 +1884,12 @@ public class ConfigHandler
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize routing rules from built-in or external templates
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="blImportAdvancedRules">Whether to import advanced rules</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> InitRouting(Config config, bool blImportAdvancedRules = false)
|
public static async Task<int> InitRouting(Config config, bool blImportAdvancedRules = false)
|
||||||
{
|
{
|
||||||
if (config.ConstItem.RouteRulesTemplateSourceUrl.IsNullOrEmpty())
|
if (config.ConstItem.RouteRulesTemplateSourceUrl.IsNullOrEmpty())
|
||||||
@@ -1697,6 +1904,13 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize routing rules from external templates
|
||||||
|
/// Downloads and processes routing templates from a URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="blImportAdvancedRules">Whether to import advanced rules</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> InitExternalRouting(Config config, bool blImportAdvancedRules = false)
|
public static async Task<int> InitExternalRouting(Config config, bool blImportAdvancedRules = false)
|
||||||
{
|
{
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
@@ -1745,6 +1959,13 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize built-in routing rules
|
||||||
|
/// Creates default routing configurations (whitelist, blacklist, global)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="blImportAdvancedRules">Whether to import advanced rules</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> InitBuiltinRouting(Config config, bool blImportAdvancedRules = false)
|
public static async Task<int> InitBuiltinRouting(Config config, bool blImportAdvancedRules = false)
|
||||||
{
|
{
|
||||||
var ver = "V3-";
|
var ver = "V3-";
|
||||||
@@ -1798,6 +2019,10 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove a routing item from the database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routingItem">Routing item to remove</param>
|
||||||
public static async Task RemoveRoutingItem(RoutingItem routingItem)
|
public static async Task RemoveRoutingItem(RoutingItem routingItem)
|
||||||
{
|
{
|
||||||
await SQLiteHelper.Instance.DeleteAsync(routingItem);
|
await SQLiteHelper.Instance.DeleteAsync(routingItem);
|
||||||
@@ -1807,6 +2032,12 @@ public class ConfigHandler
|
|||||||
|
|
||||||
#region DNS
|
#region DNS
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize built-in DNS configurations
|
||||||
|
/// Creates default DNS items for V2Ray and sing-box
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <returns>0 if successful</returns>
|
||||||
public static async Task<int> InitBuiltinDNS(Config config)
|
public static async Task<int> InitBuiltinDNS(Config config)
|
||||||
{
|
{
|
||||||
var items = await AppHandler.Instance.DNSItems();
|
var items = await AppHandler.Instance.DNSItems();
|
||||||
@@ -1830,6 +2061,12 @@ public class ConfigHandler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save a DNS item to the database
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="item">DNS item to save</param>
|
||||||
|
/// <returns>0 if successful, -1 if failed</returns>
|
||||||
public static async Task<int> SaveDNSItems(Config config, DNSItem item)
|
public static async Task<int> SaveDNSItems(Config config, DNSItem item)
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
@@ -1852,6 +2089,13 @@ public class ConfigHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an external DNS configuration from URL
|
||||||
|
/// Downloads and processes DNS templates
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Core type (Xray or sing-box)</param>
|
||||||
|
/// <param name="url">URL of the DNS template</param>
|
||||||
|
/// <returns>DNS item with configuration from the URL</returns>
|
||||||
public static async Task<DNSItem> GetExternalDNSItem(ECoreType type, string url)
|
public static async Task<DNSItem> GetExternalDNSItem(ECoreType type, string url)
|
||||||
{
|
{
|
||||||
var currentItem = await AppHandler.Instance.GetDNSItem(type);
|
var currentItem = await AppHandler.Instance.GetDNSItem(type);
|
||||||
@@ -1883,6 +2127,13 @@ public class ConfigHandler
|
|||||||
|
|
||||||
#region Regional Presets
|
#region Regional Presets
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply regional presets for geo-specific configurations
|
||||||
|
/// Sets up geo files, routing rules, and DNS for specific regions
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">Current configuration</param>
|
||||||
|
/// <param name="type">Type of preset (Default, Russia, Iran)</param>
|
||||||
|
/// <returns>True if successful</returns>
|
||||||
public static async Task<bool> ApplyRegionalPreset(Config config, EPresetType type)
|
public static async Task<bool> ApplyRegionalPreset(Config config, EPresetType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|||||||
42
v2rayN/ServiceLib/Handler/ConnectionHandler.cs
Normal file
42
v2rayN/ServiceLib/Handler/ConnectionHandler.cs
Normal 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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
126
v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
Normal file
126
v2rayN/ServiceLib/Handler/CoreAdminHandler.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ public class CoreHandler
|
|||||||
|
|
||||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
var configPath = Utils.GetBinConfigPath(fileName);
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ public class BaseFmt
|
|||||||
{
|
{
|
||||||
if (Utils.IsIpv6(address))
|
if (Utils.IsIpv6(address))
|
||||||
{
|
{
|
||||||
// 检查地址是否已经被方括号包围,如果没有,则添加方括号
|
// Check if the address is already surrounded by square brackets, if not, add square brackets
|
||||||
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
return address.StartsWith('[') && address.EndsWith(']') ? address : $"[{address}]";
|
||||||
}
|
}
|
||||||
return address; // 如果不是IPv6地址,直接返回原地址
|
else
|
||||||
|
{
|
||||||
|
return address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本软件配置文件实体类
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,26 @@ public class Outboundsettings4Ray
|
|||||||
public int? userLevel { get; set; }
|
public int? userLevel { get; set; }
|
||||||
|
|
||||||
public FragmentItem4Ray? fragment { get; set; }
|
public FragmentItem4Ray? fragment { get; set; }
|
||||||
|
|
||||||
|
public string? secretKey { get; set; }
|
||||||
|
|
||||||
|
public List<string>? address { get; set; }
|
||||||
|
|
||||||
|
public List<WireguardPeer4Ray>? peers { get; set; }
|
||||||
|
|
||||||
|
public bool? noKernelTun { get; set; }
|
||||||
|
|
||||||
|
public int? mtu { get; set; }
|
||||||
|
|
||||||
|
public List<int>? reserved { get; set; }
|
||||||
|
|
||||||
|
public int? workers { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WireguardPeer4Ray
|
||||||
|
{
|
||||||
|
public string endpoint { get; set; }
|
||||||
|
public string publicKey { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VnextItem4Ray
|
public class VnextItem4Ray
|
||||||
@@ -190,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
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
namespace ServiceLib.Models;
|
namespace ServiceLib.Models;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tcp伪装http的Request,只要Host
|
|
||||||
/// </summary>
|
|
||||||
public class V2rayTcpRequest
|
public class V2rayTcpRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
105
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
105
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -88,7 +88,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please check the server settings first. 的本地化字符串。
|
/// 查找类似 Please check the Configuration settings first. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string CheckServerSettings {
|
public static string CheckServerSettings {
|
||||||
get {
|
get {
|
||||||
@@ -178,7 +178,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Failed to import custom configuration server 的本地化字符串。
|
/// 查找类似 Failed to import custom configuration Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FailedImportedCustomServer {
|
public static string FailedImportedCustomServer {
|
||||||
get {
|
get {
|
||||||
@@ -214,7 +214,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please enter the correct server port format. 的本地化字符串。
|
/// 查找类似 Please enter the correct port format. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FillCorrectServerPort {
|
public static string FillCorrectServerPort {
|
||||||
get {
|
get {
|
||||||
@@ -241,7 +241,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please enter the server address. 的本地化字符串。
|
/// 查找类似 Please enter the address. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FillServerAddress {
|
public static string FillServerAddress {
|
||||||
get {
|
get {
|
||||||
@@ -250,7 +250,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please browse to import server configuration 的本地化字符串。
|
/// 查找类似 Please browse to import Configuration configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FillServerAddressCustom {
|
public static string FillServerAddressCustom {
|
||||||
get {
|
get {
|
||||||
@@ -466,7 +466,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Next proxy remarks 的本地化字符串。
|
/// 查找类似 Next proxy Configuration remarks 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvNextProfile {
|
public static string LvNextProfile {
|
||||||
get {
|
get {
|
||||||
@@ -484,7 +484,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Previous proxy remarks 的本地化字符串。
|
/// 查找类似 Previous proxy Configuration remarks 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvPrevProfile {
|
public static string LvPrevProfile {
|
||||||
get {
|
get {
|
||||||
@@ -493,7 +493,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please make sure the remarks exist and are unique 的本地化字符串。
|
/// 查找类似 Please make sure the Configuration remarks exist and are unique 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvPrevProfileTip {
|
public static string LvPrevProfileTip {
|
||||||
get {
|
get {
|
||||||
@@ -673,7 +673,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add a custom configuration server 的本地化字符串。
|
/// 查找类似 Add a custom configuration Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddCustomServer {
|
public static string menuAddCustomServer {
|
||||||
get {
|
get {
|
||||||
@@ -682,7 +682,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [HTTP] server 的本地化字符串。
|
/// 查找类似 Add [HTTP] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddHttpServer {
|
public static string menuAddHttpServer {
|
||||||
get {
|
get {
|
||||||
@@ -691,7 +691,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Hysteria2] server 的本地化字符串。
|
/// 查找类似 Add [Hysteria2] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddHysteria2Server {
|
public static string menuAddHysteria2Server {
|
||||||
get {
|
get {
|
||||||
@@ -727,7 +727,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Shadowsocks] server 的本地化字符串。
|
/// 查找类似 Add [Shadowsocks] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddShadowsocksServer {
|
public static string menuAddShadowsocksServer {
|
||||||
get {
|
get {
|
||||||
@@ -736,7 +736,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [SOCKS] server 的本地化字符串。
|
/// 查找类似 Add [SOCKS] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddSocksServer {
|
public static string menuAddSocksServer {
|
||||||
get {
|
get {
|
||||||
@@ -745,7 +745,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [Trojan] server 的本地化字符串。
|
/// 查找类似 Add [Trojan] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddTrojanServer {
|
public static string menuAddTrojanServer {
|
||||||
get {
|
get {
|
||||||
@@ -754,7 +754,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [TUIC] server 的本地化字符串。
|
/// 查找类似 Add [TUIC] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddTuicServer {
|
public static string menuAddTuicServer {
|
||||||
get {
|
get {
|
||||||
@@ -763,7 +763,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [VLESS] server 的本地化字符串。
|
/// 查找类似 Add [VLESS] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddVlessServer {
|
public static string menuAddVlessServer {
|
||||||
get {
|
get {
|
||||||
@@ -772,7 +772,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [VMess] server 的本地化字符串。
|
/// 查找类似 Add [VMess] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddVmessServer {
|
public static string menuAddVmessServer {
|
||||||
get {
|
get {
|
||||||
@@ -781,7 +781,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add [WireGuard] server 的本地化字符串。
|
/// 查找类似 Add [WireGuard] Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuAddWireguardServer {
|
public static string menuAddWireguardServer {
|
||||||
get {
|
get {
|
||||||
@@ -853,7 +853,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Clone selected server 的本地化字符串。
|
/// 查找类似 Clone selected Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuCopyServer {
|
public static string menuCopyServer {
|
||||||
get {
|
get {
|
||||||
@@ -871,7 +871,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Edit Server (Ctrl+D) 的本地化字符串。
|
/// 查找类似 Edit Configuration (Ctrl+D) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuEditServer {
|
public static string menuEditServer {
|
||||||
get {
|
get {
|
||||||
@@ -898,7 +898,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Export selected server for complete configuration 的本地化字符串。
|
/// 查找类似 Export selected Configuration for complete configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuExport2ClientConfig {
|
public static string menuExport2ClientConfig {
|
||||||
get {
|
get {
|
||||||
@@ -907,7 +907,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Export selected server for complete configuration to clipboard 的本地化字符串。
|
/// 查找类似 Export selected Configuration for complete configuration to clipboard 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuExport2ClientConfigClipboard {
|
public static string menuExport2ClientConfigClipboard {
|
||||||
get {
|
get {
|
||||||
@@ -934,7 +934,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Export server 的本地化字符串。
|
/// 查找类似 Export Configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuExportConfig {
|
public static string menuExportConfig {
|
||||||
get {
|
get {
|
||||||
@@ -1222,7 +1222,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Test servers real delay (Ctrl+R) 的本地化字符串。
|
/// 查找类似 Test Configurations real delay (Ctrl+R) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuRealPingServer {
|
public static string menuRealPingServer {
|
||||||
get {
|
get {
|
||||||
@@ -1312,7 +1312,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove duplicate servers 的本地化字符串。
|
/// 查找类似 Remove duplicate Configurations 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuRemoveDuplicateServer {
|
public static string menuRemoveDuplicateServer {
|
||||||
get {
|
get {
|
||||||
@@ -1330,7 +1330,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。
|
/// 查找类似 Remove selected Configurations (Delete) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuRemoveServer {
|
public static string menuRemoveServer {
|
||||||
get {
|
get {
|
||||||
@@ -1474,7 +1474,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Servers 的本地化字符串。
|
/// 查找类似 Configurations 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuServers {
|
public static string menuServers {
|
||||||
get {
|
get {
|
||||||
@@ -1483,7 +1483,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server to custom configuration 的本地化字符串。
|
/// 查找类似 Multi-Configuration to custom configuration 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServer {
|
public static string menuSetDefaultMultipleServer {
|
||||||
get {
|
get {
|
||||||
@@ -1492,7 +1492,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server LeastPing by sing-box 的本地化字符串。
|
/// 查找类似 Multi-Configuration LeastPing by sing-box 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServerSingBoxLeastPing {
|
public static string menuSetDefaultMultipleServerSingBoxLeastPing {
|
||||||
get {
|
get {
|
||||||
@@ -1501,7 +1501,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server LeastLoad by Xray 的本地化字符串。
|
/// 查找类似 Multi-Configuration LeastLoad by Xray 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServerXrayLeastLoad {
|
public static string menuSetDefaultMultipleServerXrayLeastLoad {
|
||||||
get {
|
get {
|
||||||
@@ -1510,7 +1510,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server LeastPing by Xray 的本地化字符串。
|
/// 查找类似 Multi-Configuration LeastPing by Xray 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServerXrayLeastPing {
|
public static string menuSetDefaultMultipleServerXrayLeastPing {
|
||||||
get {
|
get {
|
||||||
@@ -1519,7 +1519,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server Random by Xray 的本地化字符串。
|
/// 查找类似 Multi-Configuration Random by Xray 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServerXrayRandom {
|
public static string menuSetDefaultMultipleServerXrayRandom {
|
||||||
get {
|
get {
|
||||||
@@ -1528,7 +1528,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Multi-server RoundRobin by Xray 的本地化字符串。
|
/// 查找类似 Multi-Configuration RoundRobin by Xray 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultMultipleServerXrayRoundRobin {
|
public static string menuSetDefaultMultipleServerXrayRoundRobin {
|
||||||
get {
|
get {
|
||||||
@@ -1537,7 +1537,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set as active server (Enter) 的本地化字符串。
|
/// 查找类似 Set as active Configuration (Enter) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSetDefaultServer {
|
public static string menuSetDefaultServer {
|
||||||
get {
|
get {
|
||||||
@@ -1555,7 +1555,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Share Server (Ctrl+F) 的本地化字符串。
|
/// 查找类似 Share Configuration (Ctrl+F) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuShareServer {
|
public static string menuShareServer {
|
||||||
get {
|
get {
|
||||||
@@ -1582,7 +1582,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Test servers download speed (Ctrl+T) 的本地化字符串。
|
/// 查找类似 Test Configurations download speed (Ctrl+T) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuSpeedServer {
|
public static string menuSpeedServer {
|
||||||
get {
|
get {
|
||||||
@@ -1726,7 +1726,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Test servers with tcping (Ctrl+O) 的本地化字符串。
|
/// 查找类似 Test Configurations with tcping (Ctrl+O) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuTcpingServer {
|
public static string menuTcpingServer {
|
||||||
get {
|
get {
|
||||||
@@ -1834,7 +1834,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Server filter, press Enter to execute 的本地化字符串。
|
/// 查找类似 Configuration filter, press Enter to execute 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string MsgServerTitle {
|
public static string MsgServerTitle {
|
||||||
get {
|
get {
|
||||||
@@ -2023,7 +2023,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Please select the server first 的本地化字符串。
|
/// 查找类似 Please select the Configuration first 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string PleaseSelectServer {
|
public static string PleaseSelectServer {
|
||||||
get {
|
get {
|
||||||
@@ -2050,7 +2050,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Servers deduplication completed. Old: {0}, New: {1}. 的本地化字符串。
|
/// 查找类似 Configurations deduplication completed. Old: {0}, New: {1}. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string RemoveDuplicateServerResult {
|
public static string RemoveDuplicateServerResult {
|
||||||
get {
|
get {
|
||||||
@@ -2077,7 +2077,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Are you sure you want to remove the server? 的本地化字符串。
|
/// 查找类似 Are you sure you want to remove the Configuration? 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string RemoveServer {
|
public static string RemoveServer {
|
||||||
get {
|
get {
|
||||||
@@ -2203,7 +2203,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Custom configuration server imported successfully 的本地化字符串。
|
/// 查找类似 Custom configuration Configuration imported successfully 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string SuccessfullyImportedCustomServer {
|
public static string SuccessfullyImportedCustomServer {
|
||||||
get {
|
get {
|
||||||
@@ -2212,7 +2212,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} servers have been imported from clipboard 的本地化字符串。
|
/// 查找类似 {0} Configurations have been imported from clipboard 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string SuccessfullyImportedServerViaClipboard {
|
public static string SuccessfullyImportedServerViaClipboard {
|
||||||
get {
|
get {
|
||||||
@@ -2581,7 +2581,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Server port range 的本地化字符串。
|
/// 查找类似 Configuration port range 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbPorts7 {
|
public static string TbPorts7 {
|
||||||
get {
|
get {
|
||||||
@@ -3040,7 +3040,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Double-clicking server makes it active 的本地化字符串。
|
/// 查找类似 Double-clicking Configuration makes it active 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsDoubleClick2Activate {
|
public static string TbSettingsDoubleClick2Activate {
|
||||||
get {
|
get {
|
||||||
@@ -3076,7 +3076,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable sorting servers by drag-n-drop (requires restart) 的本地化字符串。
|
/// 查找类似 Enable sorting Configurations by drag-n-drop (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsEnableDragDropSort {
|
public static string TbSettingsEnableDragDropSort {
|
||||||
get {
|
get {
|
||||||
@@ -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 {
|
||||||
@@ -3526,7 +3535,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Tray right-click menu servers display limit 的本地化字符串。
|
/// 查找类似 Tray right-click menu Configurations display limit 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsTrayMenuServersLimit {
|
public static string TbSettingsTrayMenuServersLimit {
|
||||||
get {
|
get {
|
||||||
|
|||||||
@@ -1339,7 +1339,7 @@
|
|||||||
<value>رمز عبور sudo سیستم</value>
|
<value>رمز عبور sudo سیستم</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>رمز عبور رمزگذاری شده و فقط در فایل های محلی ذخیره می شود.</value>
|
<value>رمز عبوری که وارد کرده اید تایید نمی شود، بنابراین مطمئن شوید که آن را به درستی وارد کرده اید. اگر برنامه به دلیل ورودی نادرست به درستی کار نمی کند، لطفاً برنامه را مجدداً راه اندازی کنید. رمز عبور ذخیره نمی شود و پس از هر بار راه اندازی مجدد باید آن را دوباره وارد کنید.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||||
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
<value>لطفاً ابتدا رمز عبور sudo را در تنظیمات حالت Tun تنظیم کنید</value>
|
||||||
@@ -1416,4 +1416,7 @@
|
|||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>صادر کردن سرور</value>
|
<value>صادر کردن سرور</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>URL آزمایش اطلاعات اتصال فعلی</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<value>Export share link to clipboard successfully</value>
|
<value>Export share link to clipboard successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>Please check the server settings first.</value>
|
<value>Please check the Configuration settings first.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||||
<value>Invalid configuration format.</value>
|
<value>Invalid configuration format.</value>
|
||||||
@@ -148,13 +148,13 @@
|
|||||||
<value>Failed to get the default configuration</value>
|
<value>Failed to get the default configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>Failed to import custom configuration server</value>
|
<value>Failed to import custom configuration Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||||
<value>Failed to read configuration file</value>
|
<value>Failed to read configuration file</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>Please enter the correct server port format.</value>
|
<value>Please enter the correct port format.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>Please enter the local listening port.</value>
|
<value>Please enter the local listening port.</value>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<value>Please enter the password.</value>
|
<value>Please enter the password.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddress" xml:space="preserve">
|
<data name="FillServerAddress" xml:space="preserve">
|
||||||
<value>Please enter the server address.</value>
|
<value>Please enter the address.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>Please enter the user ID.</value>
|
<value>Please enter the user ID.</value>
|
||||||
@@ -271,13 +271,13 @@
|
|||||||
<value>Please select a protocol</value>
|
<value>Please select a protocol</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectServer" xml:space="preserve">
|
<data name="PleaseSelectServer" xml:space="preserve">
|
||||||
<value>Please select the server first</value>
|
<value>Please select the Configuration first</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>Servers deduplication completed. Old: {0}, New: {1}.</value>
|
<value>Configurations deduplication completed. Old: {0}, New: {1}.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>Are you sure you want to remove the server?</value>
|
<value>Are you sure you want to remove the Configuration?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>The client configuration file is saved at: {0}</value>
|
<value>The client configuration file is saved at: {0}</value>
|
||||||
@@ -289,10 +289,10 @@
|
|||||||
<value>Configuration successful. {0}</value>
|
<value>Configuration successful. {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>Custom configuration server imported successfully</value>
|
<value>Custom configuration Configuration imported successfully</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>{0} servers have been imported from clipboard</value>
|
<value>{0} Configurations have been imported from clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>Successfully scanned and imported the shared link</value>
|
<value>Successfully scanned and imported the shared link</value>
|
||||||
@@ -394,7 +394,7 @@
|
|||||||
<value>All</value>
|
<value>All</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>Please browse to import server configuration</value>
|
<value>Please browse to import Configuration configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>Testing...</value>
|
<value>Testing...</value>
|
||||||
@@ -406,7 +406,7 @@
|
|||||||
<value>Local</value>
|
<value>Local</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>Server filter, press Enter to execute</value>
|
<value>Configuration filter, press Enter to execute</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>Check Update</value>
|
<value>Check Update</value>
|
||||||
@@ -436,7 +436,7 @@
|
|||||||
<value>Routing Setting</value>
|
<value>Routing Setting</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServers" xml:space="preserve">
|
<data name="menuServers" xml:space="preserve">
|
||||||
<value>Servers</value>
|
<value>Configurations</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetting" xml:space="preserve">
|
<data name="menuSetting" xml:space="preserve">
|
||||||
<value>Settings</value>
|
<value>Settings</value>
|
||||||
@@ -487,55 +487,55 @@
|
|||||||
<value>Scan QR code on the screen (Ctrl+S)</value>
|
<value>Scan QR code on the screen (Ctrl+S)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCopyServer" xml:space="preserve">
|
<data name="menuCopyServer" xml:space="preserve">
|
||||||
<value>Clone selected server</value>
|
<value>Clone selected Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
||||||
<value>Remove duplicate servers</value>
|
<value>Remove duplicate Configurations</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveServer" xml:space="preserve">
|
<data name="menuRemoveServer" xml:space="preserve">
|
||||||
<value>Remove selected servers (Delete)</value>
|
<value>Remove selected Configurations (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultServer" xml:space="preserve">
|
<data name="menuSetDefaultServer" xml:space="preserve">
|
||||||
<value>Set as active server (Enter)</value>
|
<value>Set as active Configuration (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>Clear all service statistics</value>
|
<value>Clear all service statistics</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>Test servers real delay (Ctrl+R)</value>
|
<value>Test Configurations real delay (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSortServerResult" xml:space="preserve">
|
<data name="menuSortServerResult" xml:space="preserve">
|
||||||
<value>Sort by test result</value>
|
<value>Sort by test result</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSpeedServer" xml:space="preserve">
|
<data name="menuSpeedServer" xml:space="preserve">
|
||||||
<value>Test servers download speed (Ctrl+T)</value>
|
<value>Test Configurations download speed (Ctrl+T)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>Test servers with tcping (Ctrl+O)</value>
|
<value>Test Configurations with tcping (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>Export selected server for complete configuration</value>
|
<value>Export selected Configuration for complete configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>Export Share Link to Clipboard (Ctrl+C)</value>
|
<value>Export Share Link to Clipboard (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>Add a custom configuration server</value>
|
<value>Add a custom configuration Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||||
<value>Add [Shadowsocks] server</value>
|
<value>Add [Shadowsocks] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>Add [SOCKS] server</value>
|
<value>Add [SOCKS] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>Add [Trojan] server</value>
|
<value>Add [Trojan] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVlessServer" xml:space="preserve">
|
<data name="menuAddVlessServer" xml:space="preserve">
|
||||||
<value>Add [VLESS] server</value>
|
<value>Add [VLESS] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVmessServer" xml:space="preserve">
|
<data name="menuAddVmessServer" xml:space="preserve">
|
||||||
<value>Add [VMess] server</value>
|
<value>Add [VMess] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSelectAll" xml:space="preserve">
|
<data name="menuSelectAll" xml:space="preserve">
|
||||||
<value>Select all (Ctrl+A)</value>
|
<value>Select all (Ctrl+A)</value>
|
||||||
@@ -760,7 +760,7 @@
|
|||||||
<value>Enable Security Protocol TLS v1.3 (subscription/update)</value>
|
<value>Enable Security Protocol TLS v1.3 (subscription/update)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||||
<value>Tray right-click menu servers display limit</value>
|
<value>Tray right-click menu Configurations display limit</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||||
<value>Enable UDP</value>
|
<value>Enable UDP</value>
|
||||||
@@ -793,7 +793,7 @@
|
|||||||
<value>PAC mode</value>
|
<value>PAC mode</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShareServer" xml:space="preserve">
|
<data name="menuShareServer" xml:space="preserve">
|
||||||
<value>Share Server (Ctrl+F)</value>
|
<value>Share Configuration (Ctrl+F)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRouting" xml:space="preserve">
|
<data name="menuRouting" xml:space="preserve">
|
||||||
<value>Routing</value>
|
<value>Routing</value>
|
||||||
@@ -940,7 +940,7 @@
|
|||||||
<value>Move to group</value>
|
<value>Move to group</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>Enable sorting servers by drag-n-drop (requires restart)</value>
|
<value>Enable sorting Configurations by drag-n-drop (requires restart)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>Auto refresh</value>
|
<value>Auto refresh</value>
|
||||||
@@ -949,10 +949,10 @@
|
|||||||
<value>Skip test</value>
|
<value>Skip test</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuEditServer" xml:space="preserve">
|
<data name="menuEditServer" xml:space="preserve">
|
||||||
<value>Edit Server (Ctrl+D)</value>
|
<value>Edit Configuration (Ctrl+D)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||||
<value>Double-clicking server makes it active</value>
|
<value>Double-clicking Configuration makes it active</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||||
<value>Test completed</value>
|
<value>Test completed</value>
|
||||||
@@ -1060,7 +1060,7 @@
|
|||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
<value>Add [Hysteria2] server</value>
|
<value>Add [Hysteria2] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
<value>Hysteria Max bandwidth (Up/Down)</value>
|
<value>Hysteria Max bandwidth (Up/Down)</value>
|
||||||
@@ -1069,19 +1069,19 @@
|
|||||||
<value>Use System Hosts</value>
|
<value>Use System Hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>Add [TUIC] server</value>
|
<value>Add [TUIC] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbHeaderType8" xml:space="preserve">
|
<data name="TbHeaderType8" xml:space="preserve">
|
||||||
<value>Congestion control</value>
|
<value>Congestion control</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfile" xml:space="preserve">
|
<data name="LvPrevProfile" xml:space="preserve">
|
||||||
<value>Previous proxy remarks</value>
|
<value>Previous proxy Configuration remarks</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvNextProfile" xml:space="preserve">
|
<data name="LvNextProfile" xml:space="preserve">
|
||||||
<value>Next proxy remarks</value>
|
<value>Next proxy Configuration remarks</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LvPrevProfileTip" xml:space="preserve">
|
<data name="LvPrevProfileTip" xml:space="preserve">
|
||||||
<value>Please make sure the remarks exist and are unique</value>
|
<value>Please make sure the Configuration remarks exist and are unique</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
<data name="TbSettingsEnableExInbound" xml:space="preserve">
|
||||||
<value>Enable additional Inbound</value>
|
<value>Enable additional Inbound</value>
|
||||||
@@ -1090,7 +1090,7 @@
|
|||||||
<value>Enable IPv6 Address</value>
|
<value>Enable IPv6 Address</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>Add [WireGuard] server</value>
|
<value>Add [WireGuard] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>Private Key</value>
|
<value>Private Key</value>
|
||||||
@@ -1123,7 +1123,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>Add [HTTP] server</value>
|
<value>Add [HTTP] Configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
<value>Use Xray and enable non-Tun mode, which conflicts with the group previous proxy</value>
|
||||||
@@ -1237,7 +1237,7 @@
|
|||||||
<value>Export Base64-encoded Share Links to Clipboard</value>
|
<value>Export Base64-encoded Share Links to Clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>Export selected server for complete configuration to clipboard</value>
|
<value>Export selected Configuration for complete configuration to clipboard</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>Show or hide the main window</value>
|
<value>Show or hide the main window</value>
|
||||||
@@ -1339,7 +1339,7 @@
|
|||||||
<value>System sudo password</value>
|
<value>System sudo password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||||
<value>The password 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>
|
||||||
@@ -1390,30 +1390,33 @@
|
|||||||
<value>Removed {0} invalid test results.</value>
|
<value>Removed {0} invalid test results.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7" xml:space="preserve">
|
<data name="TbPorts7" xml:space="preserve">
|
||||||
<value>Server port range</value>
|
<value>Configuration port range</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPorts7Tips" xml:space="preserve">
|
<data name="TbPorts7Tips" xml:space="preserve">
|
||||||
<value>Will cover the port, separate with commas (,)</value>
|
<value>Will cover the port, separate with commas (,)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>Multi-server to custom configuration</value>
|
<value>Multi-Configuration to custom configuration</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>Multi-server Random by Xray</value>
|
<value>Multi-Configuration Random by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>Multi-server RoundRobin by Xray</value>
|
<value>Multi-Configuration RoundRobin by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>Multi-server LeastPing by Xray</value>
|
<value>Multi-Configuration LeastPing by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>Multi-server LeastLoad by Xray</value>
|
<value>Multi-Configuration LeastLoad by Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>Multi-server LeastPing by sing-box</value>
|
<value>Multi-Configuration LeastPing by sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>Export server</value>
|
<value>Export Configuration</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>Current connection info test URL</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -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>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<value>导出分享链接至剪贴板成功</value>
|
<value>导出分享链接至剪贴板成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>请先检查服务器设置</value>
|
<value>请先检查配置文件设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||||
<value>配置格式不正确</value>
|
<value>配置格式不正确</value>
|
||||||
@@ -148,13 +148,13 @@
|
|||||||
<value>获取默认配置失败</value>
|
<value>获取默认配置失败</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>导入自定义配置服务器失败</value>
|
<value>导入自定义配置文件失败</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||||
<value>读取配置文件失败</value>
|
<value>读取配置文件失败</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>请填写正确格式的服务器端口</value>
|
<value>请填写正确格式的端口</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>请填写本地监听端口</value>
|
<value>请填写本地监听端口</value>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<value>请填写密码</value>
|
<value>请填写密码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddress" xml:space="preserve">
|
<data name="FillServerAddress" xml:space="preserve">
|
||||||
<value>请填写服务器地址</value>
|
<value>请填写地址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>请填写用户 ID</value>
|
<value>请填写用户 ID</value>
|
||||||
@@ -271,13 +271,13 @@
|
|||||||
<value>请选择协议</value>
|
<value>请选择协议</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectServer" xml:space="preserve">
|
<data name="PleaseSelectServer" xml:space="preserve">
|
||||||
<value>请先选择服务器</value>
|
<value>请先选择配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>服务器去重完成。原数量: {0},现数量: {1}。</value>
|
<value>配置文件去重完成。原数量: {0},现数量: {1}。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>是否确定移除服务器?</value>
|
<value>是否确定移除配置文件?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>客户端配置文件保存在:{0}</value>
|
<value>客户端配置文件保存在:{0}</value>
|
||||||
@@ -289,10 +289,10 @@
|
|||||||
<value>配置成功。 {0}</value>
|
<value>配置成功。 {0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>成功导入自定义配置服务器</value>
|
<value>成功导入自定义配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>成功从剪贴板导入 {0} 个服务器</value>
|
<value>成功从剪贴板导入 {0} 个配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>扫描导入分享链接成功</value>
|
<value>扫描导入分享链接成功</value>
|
||||||
@@ -388,13 +388,13 @@
|
|||||||
<value>注册全局热键 {0} 成功</value>
|
<value>注册全局热键 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
<data name="UngroupedServers" xml:space="preserve">
|
||||||
<value>未分组服务器</value>
|
<value>未分组配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>请浏览导入服务器配置</value>
|
<value>请浏览导入配置文件配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>测试中...</value>
|
<value>测试中...</value>
|
||||||
@@ -406,7 +406,7 @@
|
|||||||
<value>本地</value>
|
<value>本地</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>服务器过滤器,按回车执行</value>
|
<value>配置文件过滤器,按回车执行</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>检查更新</value>
|
<value>检查更新</value>
|
||||||
@@ -436,7 +436,7 @@
|
|||||||
<value>路由设置</value>
|
<value>路由设置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServers" xml:space="preserve">
|
<data name="menuServers" xml:space="preserve">
|
||||||
<value>服务器</value>
|
<value>配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetting" xml:space="preserve">
|
<data name="menuSetting" xml:space="preserve">
|
||||||
<value>设置</value>
|
<value>设置</value>
|
||||||
@@ -487,55 +487,55 @@
|
|||||||
<value>扫描屏幕上的二维码 (Ctrl+S)</value>
|
<value>扫描屏幕上的二维码 (Ctrl+S)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCopyServer" xml:space="preserve">
|
<data name="menuCopyServer" xml:space="preserve">
|
||||||
<value>克隆所选服务器</value>
|
<value>克隆所选配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
||||||
<value>移除重复的服务器</value>
|
<value>移除重复的配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveServer" xml:space="preserve">
|
<data name="menuRemoveServer" xml:space="preserve">
|
||||||
<value>移除所选服务器 (多选) (Delete)</value>
|
<value>移除所选配置文件 (多选) (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultServer" xml:space="preserve">
|
<data name="menuSetDefaultServer" xml:space="preserve">
|
||||||
<value>设为活动服务器 (Enter)</value>
|
<value>设为活动配置文件 (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>清除所有服务统计数据</value>
|
<value>清除所有服务统计数据</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>测试服务器真连接延迟 (多选) (Ctrl+R)</value>
|
<value>测试配置文件真连接延迟 (多选) (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSortServerResult" xml:space="preserve">
|
<data name="menuSortServerResult" xml:space="preserve">
|
||||||
<value>按测试结果排序</value>
|
<value>按测试结果排序</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSpeedServer" xml:space="preserve">
|
<data name="menuSpeedServer" xml:space="preserve">
|
||||||
<value>测试服务器速度 (多选) (Ctrl+T)</value>
|
<value>测试配置文件速度 (多选) (Ctrl+T)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>测试服务器延迟 Tcping (多选) (Ctrl+O)</value>
|
<value>测试配置文件延迟 Tcping (多选) (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>导出所选服务器完整配置</value>
|
<value>导出所选配置文件完整配置</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>导出分享链接至剪贴板 (多选) (Ctrl+C)</value>
|
<value>导出分享链接至剪贴板 (多选) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>添加自定义配置服务器</value>
|
<value>添加自定义配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||||
<value>添加 [Shadowsocks] 服务器</value>
|
<value>添加 [Shadowsocks] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>添加 [SOCKS] 服务器</value>
|
<value>添加 [SOCKS] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>添加 [Trojan] 服务器</value>
|
<value>添加 [Trojan] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVlessServer" xml:space="preserve">
|
<data name="menuAddVlessServer" xml:space="preserve">
|
||||||
<value>添加 [VLESS] 服务器</value>
|
<value>添加 [VLESS] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVmessServer" xml:space="preserve">
|
<data name="menuAddVmessServer" xml:space="preserve">
|
||||||
<value>添加 [VMess] 服务器</value>
|
<value>添加 [VMess] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSelectAll" xml:space="preserve">
|
<data name="menuSelectAll" xml:space="preserve">
|
||||||
<value>全选 (Ctrl+A)</value>
|
<value>全选 (Ctrl+A)</value>
|
||||||
@@ -700,7 +700,7 @@
|
|||||||
<value>Outbound Freedom domainStrategy</value>
|
<value>Outbound Freedom domainStrategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||||
<value>自动调整服务器列宽在更新订阅后</value>
|
<value>自动调整配置文件列宽在更新订阅后</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
||||||
<value>检查 Pre-Release 更新 (请谨慎启用)</value>
|
<value>检查 Pre-Release 更新 (请谨慎启用)</value>
|
||||||
@@ -760,7 +760,7 @@
|
|||||||
<value>启用安全协议 TLS v1.3 (订阅/检查更新)</value>
|
<value>启用安全协议 TLS v1.3 (订阅/检查更新)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||||
<value>托盘右键菜单服务器展示数量限制</value>
|
<value>托盘右键菜单配置文件展示数量限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||||
<value>开启 UDP</value>
|
<value>开启 UDP</value>
|
||||||
@@ -793,7 +793,7 @@
|
|||||||
<value>Pac 模式</value>
|
<value>Pac 模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShareServer" xml:space="preserve">
|
<data name="menuShareServer" xml:space="preserve">
|
||||||
<value>分享服务器 (Ctrl+F)</value>
|
<value>分享配置文件 (Ctrl+F)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRouting" xml:space="preserve">
|
<data name="menuRouting" xml:space="preserve">
|
||||||
<value>路由</value>
|
<value>路由</value>
|
||||||
@@ -940,7 +940,7 @@
|
|||||||
<value>移至订阅分组</value>
|
<value>移至订阅分组</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>启用服务器拖放排序(需重启)</value>
|
<value>启用配置文件拖放排序(需重启)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>自动刷新</value>
|
<value>自动刷新</value>
|
||||||
@@ -949,10 +949,10 @@
|
|||||||
<value>跳过测试</value>
|
<value>跳过测试</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuEditServer" xml:space="preserve">
|
<data name="menuEditServer" xml:space="preserve">
|
||||||
<value>编辑服务器 (Ctrl+D)</value>
|
<value>编辑配置文件 (Ctrl+D)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||||
<value>主界面双击设为活动服务器</value>
|
<value>主界面双击设为活动配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||||
<value>测试完成</value>
|
<value>测试完成</value>
|
||||||
@@ -1057,7 +1057,7 @@
|
|||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
<value>添加 [Hysteria2] 服务器</value>
|
<value>添加 [Hysteria2] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
<value>Hysteria 最大带宽 (Up/Dw)</value>
|
<value>Hysteria 最大带宽 (Up/Dw)</value>
|
||||||
@@ -1066,19 +1066,19 @@
|
|||||||
<value>使用系统 hosts</value>
|
<value>使用系统 hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>添加 [TUIC] 服务器</value>
|
<value>添加 [TUIC] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<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">
|
||||||
<value>启用额外监听端口</value>
|
<value>启用额外监听端口</value>
|
||||||
@@ -1087,7 +1087,7 @@
|
|||||||
<value>启用 IPv6</value>
|
<value>启用 IPv6</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>添加 [WireGuard] 服务器</value>
|
<value>添加 [WireGuard] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>PrivateKey</value>
|
<value>PrivateKey</value>
|
||||||
@@ -1120,7 +1120,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>添加 [HTTP] 服务器</value>
|
<value>添加 [HTTP] 配置文件</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
|
<value>使用 Xray 且非 Tun 模式启用,和分组前置代理冲突</value>
|
||||||
@@ -1234,7 +1234,7 @@
|
|||||||
<value>导出分享链接至剪贴板 (多选) Base64 编码</value>
|
<value>导出分享链接至剪贴板 (多选) Base64 编码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>导出所选服务器完整配置至剪贴板</value>
|
<value>导出所选配置文件完整配置至剪贴板</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>显示或隐藏主界面</value>
|
<value>显示或隐藏主界面</value>
|
||||||
@@ -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>
|
||||||
@@ -1393,24 +1393,27 @@
|
|||||||
<value>会覆盖端口,多组时用逗号 (,) 隔开</value>
|
<value>会覆盖端口,多组时用逗号 (,) 隔开</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>多服务器产生自定义配置 (多选)</value>
|
<value>多配置文件产生自定义配置 (多选)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>多服务器随机 Xray</value>
|
<value>多配置文件随机 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>多服务器负载均衡 Xray</value>
|
<value>多配置文件负载均衡 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>多服务器最低延迟 Xray</value>
|
<value>多配置文件最低延迟 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>多服务器最稳定 Xray</value>
|
<value>多配置文件最稳定 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>多服务器最低延迟 sing-box</value>
|
<value>多配置文件最低延迟 sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>导出服务器</value>
|
<value>导出配置文件</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>当前连接信息测试地址</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
<value>匯出分享链接至剪貼簿成功</value>
|
<value>匯出分享链接至剪貼簿成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CheckServerSettings" xml:space="preserve">
|
<data name="CheckServerSettings" xml:space="preserve">
|
||||||
<value>請先檢查伺服器設定</value>
|
<value>請先檢查設定檔設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
<data name="ConfigurationFormatIncorrect" xml:space="preserve">
|
||||||
<value>設定格式不正確</value>
|
<value>設定格式不正確</value>
|
||||||
@@ -148,13 +148,13 @@
|
|||||||
<value>獲取預設設定失敗</value>
|
<value>獲取預設設定失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedImportedCustomServer" xml:space="preserve">
|
<data name="FailedImportedCustomServer" xml:space="preserve">
|
||||||
<value>匯入自訂設定伺服器失敗</value>
|
<value>匯入自訂設定設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FailedReadConfiguration" xml:space="preserve">
|
<data name="FailedReadConfiguration" xml:space="preserve">
|
||||||
<value>讀取設定檔失敗</value>
|
<value>讀取設定檔失敗</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillCorrectServerPort" xml:space="preserve">
|
<data name="FillCorrectServerPort" xml:space="preserve">
|
||||||
<value>請填寫正確格式的伺服器埠</value>
|
<value>請填寫正確格式的埠</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillLocalListeningPort" xml:space="preserve">
|
<data name="FillLocalListeningPort" xml:space="preserve">
|
||||||
<value>請填寫本機偵聽埠</value>
|
<value>請填寫本機偵聽埠</value>
|
||||||
@@ -163,7 +163,7 @@
|
|||||||
<value>請填寫密碼</value>
|
<value>請填寫密碼</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddress" xml:space="preserve">
|
<data name="FillServerAddress" xml:space="preserve">
|
||||||
<value>請填寫伺服器位址</value>
|
<value>請填寫位址</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillUUID" xml:space="preserve">
|
<data name="FillUUID" xml:space="preserve">
|
||||||
<value>請填寫使用者 ID</value>
|
<value>請填寫使用者 ID</value>
|
||||||
@@ -271,13 +271,13 @@
|
|||||||
<value>請選擇協定</value>
|
<value>請選擇協定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PleaseSelectServer" xml:space="preserve">
|
<data name="PleaseSelectServer" xml:space="preserve">
|
||||||
<value>請先選擇伺服器</value>
|
<value>請先選擇設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
<data name="RemoveDuplicateServerResult" xml:space="preserve">
|
||||||
<value>伺服器去重完成。原數量: {0},現數量: {1}。</value>
|
<value>設定檔去重完成。原數量: {0},現數量: {1}。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveServer" xml:space="preserve">
|
<data name="RemoveServer" xml:space="preserve">
|
||||||
<value>是否確定移除伺服器?</value>
|
<value>是否確定移除設定檔?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
<data name="SaveClientConfigurationIn" xml:space="preserve">
|
||||||
<value>用戶端設定檔儲存在:{0}</value>
|
<value>用戶端設定檔儲存在:{0}</value>
|
||||||
@@ -289,10 +289,10 @@
|
|||||||
<value>設定成功。{0}</value>
|
<value>設定成功。{0}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
<data name="SuccessfullyImportedCustomServer" xml:space="preserve">
|
||||||
<value>成功匯入自訂設定伺服器</value>
|
<value>成功匯入自訂設定設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaClipboard" xml:space="preserve">
|
||||||
<value>成功從剪貼簿匯入 {0} 個伺服器</value>
|
<value>成功從剪貼簿匯入 {0} 個設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
<data name="SuccessfullyImportedServerViaScan" xml:space="preserve">
|
||||||
<value>掃描匯入分享链接成功</value>
|
<value>掃描匯入分享链接成功</value>
|
||||||
@@ -388,13 +388,13 @@
|
|||||||
<value>註冊全域快速鍵 {0} 成功</value>
|
<value>註冊全域快速鍵 {0} 成功</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UngroupedServers" xml:space="preserve">
|
<data name="UngroupedServers" xml:space="preserve">
|
||||||
<value>未分組伺服器</value>
|
<value>未分組設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllGroupServers" xml:space="preserve">
|
<data name="AllGroupServers" xml:space="preserve">
|
||||||
<value>所有</value>
|
<value>所有</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="FillServerAddressCustom" xml:space="preserve">
|
<data name="FillServerAddressCustom" xml:space="preserve">
|
||||||
<value>請瀏覽匯入伺服器設定</value>
|
<value>請瀏覽匯入設定檔設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Speedtesting" xml:space="preserve">
|
<data name="Speedtesting" xml:space="preserve">
|
||||||
<value>測試中...</value>
|
<value>測試中...</value>
|
||||||
@@ -406,7 +406,7 @@
|
|||||||
<value>本機</value>
|
<value>本機</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MsgServerTitle" xml:space="preserve">
|
<data name="MsgServerTitle" xml:space="preserve">
|
||||||
<value>伺服器過濾,按 Enter 執行</value>
|
<value>設定檔過濾,按 Enter 執行</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCheckUpdate" xml:space="preserve">
|
<data name="menuCheckUpdate" xml:space="preserve">
|
||||||
<value>檢查更新</value>
|
<value>檢查更新</value>
|
||||||
@@ -436,7 +436,7 @@
|
|||||||
<value>路由設定</value>
|
<value>路由設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuServers" xml:space="preserve">
|
<data name="menuServers" xml:space="preserve">
|
||||||
<value>伺服器</value>
|
<value>設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetting" xml:space="preserve">
|
<data name="menuSetting" xml:space="preserve">
|
||||||
<value>設定</value>
|
<value>設定</value>
|
||||||
@@ -487,55 +487,55 @@
|
|||||||
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
<value>掃描螢幕上的二維碼 (Ctrl+S)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCopyServer" xml:space="preserve">
|
<data name="menuCopyServer" xml:space="preserve">
|
||||||
<value>複製所選伺服器</value>
|
<value>複製所選設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
<data name="menuRemoveDuplicateServer" xml:space="preserve">
|
||||||
<value>移除重複的伺服器</value>
|
<value>移除重複的設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRemoveServer" xml:space="preserve">
|
<data name="menuRemoveServer" xml:space="preserve">
|
||||||
<value>移除所選伺服器 (多選) (Delete)</value>
|
<value>移除所選設定檔 (多選) (Delete)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultServer" xml:space="preserve">
|
<data name="menuSetDefaultServer" xml:space="preserve">
|
||||||
<value>設為活動伺服器 (Enter)</value>
|
<value>設為活動設定檔 (Enter)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuClearServerStatistics" xml:space="preserve">
|
<data name="menuClearServerStatistics" xml:space="preserve">
|
||||||
<value>清除所有服務統計資料</value>
|
<value>清除所有服務統計資料</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRealPingServer" xml:space="preserve">
|
<data name="menuRealPingServer" xml:space="preserve">
|
||||||
<value>測試伺服器真連線延遲 (多選) (Ctrl+R)</value>
|
<value>測試設定檔真連線延遲 (多選) (Ctrl+R)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSortServerResult" xml:space="preserve">
|
<data name="menuSortServerResult" xml:space="preserve">
|
||||||
<value>按測試結果排序</value>
|
<value>按測試結果排序</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSpeedServer" xml:space="preserve">
|
<data name="menuSpeedServer" xml:space="preserve">
|
||||||
<value>測試伺服器速度 (多選) (Ctrl+T)</value>
|
<value>測試設定檔速度 (多選) (Ctrl+T)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuTcpingServer" xml:space="preserve">
|
<data name="menuTcpingServer" xml:space="preserve">
|
||||||
<value>測試伺服器延遲 Tcping (多選) (Ctrl+O)</value>
|
<value>測試設定檔延遲 Tcping (多選) (Ctrl+O)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfig" xml:space="preserve">
|
<data name="menuExport2ClientConfig" xml:space="preserve">
|
||||||
<value>匯出所選伺服器完整設定</value>
|
<value>匯出所選設定檔完整設定</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ShareUrl" xml:space="preserve">
|
<data name="menuExport2ShareUrl" xml:space="preserve">
|
||||||
<value>匯出分享链接至剪貼簿 (多選) (Ctrl+C)</value>
|
<value>匯出分享链接至剪貼簿 (多選) (Ctrl+C)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddCustomServer" xml:space="preserve">
|
<data name="menuAddCustomServer" xml:space="preserve">
|
||||||
<value>新增自訂設定伺服器</value>
|
<value>新增自訂設定設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
<data name="menuAddShadowsocksServer" xml:space="preserve">
|
||||||
<value>新增 [Shadowsocks] 伺服器</value>
|
<value>新增 [Shadowsocks] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddSocksServer" xml:space="preserve">
|
<data name="menuAddSocksServer" xml:space="preserve">
|
||||||
<value>新增 [SOCKS] 伺服器</value>
|
<value>新增 [SOCKS] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTrojanServer" xml:space="preserve">
|
<data name="menuAddTrojanServer" xml:space="preserve">
|
||||||
<value>新增 [Trojan] 伺服器</value>
|
<value>新增 [Trojan] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVlessServer" xml:space="preserve">
|
<data name="menuAddVlessServer" xml:space="preserve">
|
||||||
<value>新增 [VLESS] 伺服器</value>
|
<value>新增 [VLESS] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddVmessServer" xml:space="preserve">
|
<data name="menuAddVmessServer" xml:space="preserve">
|
||||||
<value>新增 [VMess] 伺服器</value>
|
<value>新增 [VMess] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSelectAll" xml:space="preserve">
|
<data name="menuSelectAll" xml:space="preserve">
|
||||||
<value>全選 (Ctrl+A)</value>
|
<value>全選 (Ctrl+A)</value>
|
||||||
@@ -700,7 +700,7 @@
|
|||||||
<value>Outbound Freedom domainStrategy</value>
|
<value>Outbound Freedom domainStrategy</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
<data name="TbSettingsEnableAutoAdjustMainLvColWidth" xml:space="preserve">
|
||||||
<value>在更新訂閱後自動調整伺服器列寬</value>
|
<value>在更新訂閱後自動調整設定檔列寬</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
<data name="TbSettingsEnableCheckPreReleaseUpdate" xml:space="preserve">
|
||||||
<value>檢查 Pre-Release 更新 (請謹慎啟用)</value>
|
<value>檢查 Pre-Release 更新 (請謹慎啟用)</value>
|
||||||
@@ -760,7 +760,7 @@
|
|||||||
<value>啟用安全協定 TLS v1.3 (訂閱/檢查更新)</value>
|
<value>啟用安全協定 TLS v1.3 (訂閱/檢查更新)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
<data name="TbSettingsTrayMenuServersLimit" xml:space="preserve">
|
||||||
<value>工具列右鍵選單伺服器展示數量限制</value>
|
<value>工具列右鍵選單設定檔展示數量限制</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
<data name="TbSettingsUdpEnabled" xml:space="preserve">
|
||||||
<value>開啟 UDP</value>
|
<value>開啟 UDP</value>
|
||||||
@@ -793,7 +793,7 @@
|
|||||||
<value>PAC 模式</value>
|
<value>PAC 模式</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShareServer" xml:space="preserve">
|
<data name="menuShareServer" xml:space="preserve">
|
||||||
<value>分享伺服器 (Ctrl+F)</value>
|
<value>分享設定檔 (Ctrl+F)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuRouting" xml:space="preserve">
|
<data name="menuRouting" xml:space="preserve">
|
||||||
<value>路由</value>
|
<value>路由</value>
|
||||||
@@ -940,7 +940,7 @@
|
|||||||
<value>移至訂閱分組</value>
|
<value>移至訂閱分組</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
<data name="TbSettingsEnableDragDropSort" xml:space="preserve">
|
||||||
<value>啟動伺服器拖放排序 (需重啟)</value>
|
<value>啟動設定檔拖放排序 (需重啟)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbAutoRefresh" xml:space="preserve">
|
<data name="TbAutoRefresh" xml:space="preserve">
|
||||||
<value>自動重新整理</value>
|
<value>自動重新整理</value>
|
||||||
@@ -949,10 +949,10 @@
|
|||||||
<value>跳過測試</value>
|
<value>跳過測試</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuEditServer" xml:space="preserve">
|
<data name="menuEditServer" xml:space="preserve">
|
||||||
<value>編輯伺服器 (Ctrl+D)</value>
|
<value>編輯設定檔 (Ctrl+D)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
<data name="TbSettingsDoubleClick2Activate" xml:space="preserve">
|
||||||
<value>主介面輕按兩下設為活動伺服器</value>
|
<value>主介面輕按兩下設為活動設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SpeedtestingCompleted" xml:space="preserve">
|
<data name="SpeedtestingCompleted" xml:space="preserve">
|
||||||
<value>測試完成</value>
|
<value>測試完成</value>
|
||||||
@@ -1057,7 +1057,7 @@
|
|||||||
<value>Domain</value>
|
<value>Domain</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHysteria2Server" xml:space="preserve">
|
<data name="menuAddHysteria2Server" xml:space="preserve">
|
||||||
<value>添加 [Hysteria2] 伺服器</value>
|
<value>添加 [Hysteria2] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
<data name="TbSettingsHysteriaBandwidth" xml:space="preserve">
|
||||||
<value>Hysteria 最大頻寬 (Up/Dw)</value>
|
<value>Hysteria 最大頻寬 (Up/Dw)</value>
|
||||||
@@ -1066,19 +1066,19 @@
|
|||||||
<value>使用系統 hosts</value>
|
<value>使用系統 hosts</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddTuicServer" xml:space="preserve">
|
<data name="menuAddTuicServer" xml:space="preserve">
|
||||||
<value>新增 [TUIC] 伺服器</value>
|
<value>新增 [TUIC] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<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">
|
||||||
<value>啟用額外偵聽連接埠</value>
|
<value>啟用額外偵聽連接埠</value>
|
||||||
@@ -1087,7 +1087,7 @@
|
|||||||
<value>啟用 IPv6</value>
|
<value>啟用 IPv6</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddWireguardServer" xml:space="preserve">
|
<data name="menuAddWireguardServer" xml:space="preserve">
|
||||||
<value>添加 [WireGuard] 伺服器</value>
|
<value>添加 [WireGuard] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbPrivateKey" xml:space="preserve">
|
<data name="TbPrivateKey" xml:space="preserve">
|
||||||
<value>PrivateKey</value>
|
<value>PrivateKey</value>
|
||||||
@@ -1120,7 +1120,7 @@
|
|||||||
<value>*grpc Authority</value>
|
<value>*grpc Authority</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuAddHttpServer" xml:space="preserve">
|
<data name="menuAddHttpServer" xml:space="preserve">
|
||||||
<value>新增 [HTTP] 伺服器</value>
|
<value>新增 [HTTP] 設定檔</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
<data name="TbSettingsEnableFragmentTips" xml:space="preserve">
|
||||||
<value>使用 Xray 且非 Tun 模式啟用,和分組前置代理衝突</value>
|
<value>使用 Xray 且非 Tun 模式啟用,和分組前置代理衝突</value>
|
||||||
@@ -1234,7 +1234,7 @@
|
|||||||
<value>匯出分享链接至剪貼簿 (多選) Base64 编码</value>
|
<value>匯出分享链接至剪貼簿 (多選) Base64 编码</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
<data name="menuExport2ClientConfigClipboard" xml:space="preserve">
|
||||||
<value>匯出所選伺服器完整設定至剪貼簿</value>
|
<value>匯出所選設定檔完整設定至剪貼簿</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
<data name="menuShowOrHideMainWindow" xml:space="preserve">
|
||||||
<value>顯示或隱藏主介面</value>
|
<value>顯示或隱藏主介面</value>
|
||||||
@@ -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>
|
||||||
@@ -1393,24 +1393,27 @@
|
|||||||
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
|
<value>會覆蓋端口,多組時用逗號 (,) 隔開</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServer" xml:space="preserve">
|
||||||
<value>多伺服器產生自訂配置 (多選)</value>
|
<value>多設定檔產生自訂配置 (多選)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRandom" xml:space="preserve">
|
||||||
<value>多伺服器隨機 Xray</value>
|
<value>多設定檔隨機 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayRoundRobin" xml:space="preserve">
|
||||||
<value>多伺服器負載平衡 Xray</value>
|
<value>多設定檔負載平衡 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastPing" xml:space="preserve">
|
||||||
<value>多伺服器最低延遲 Xray</value>
|
<value>多設定檔最低延遲 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerXrayLeastLoad" xml:space="preserve">
|
||||||
<value>多伺服器最穩定 Xray</value>
|
<value>多設定檔最穩定 Xray</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
<data name="menuSetDefaultMultipleServerSingBoxLeastPing" xml:space="preserve">
|
||||||
<value>多伺服器最低延遲 sing-box</value>
|
<value>多設定檔最低延遲 sing-box</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuExportConfig" xml:space="preserve">
|
<data name="menuExportConfig" xml:space="preserve">
|
||||||
<value>匯出伺服器</value>
|
<value>匯出設定檔</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbSettingsIPAPIUrl" xml:space="preserve">
|
||||||
|
<value>目前連接資訊測試地址</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -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"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -13,13 +13,6 @@ public class CoreConfigClashService
|
|||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生成配置文件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
/// <param name="fileName"></param>
|
|
||||||
/// <param name="msg"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
public async Task<RetResult> GenerateClientCustomConfig(ProfileItem node, string? fileName)
|
||||||
{
|
{
|
||||||
var ret = new RetResult();
|
var ret = new RetResult();
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -1047,28 +1048,30 @@ public class CoreConfigSingboxService
|
|||||||
|
|
||||||
private void GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
|
private void GenRoutingDirectExe(out List<string> lstDnsExe, out List<string> lstDirectExe)
|
||||||
{
|
{
|
||||||
lstDnsExe = new();
|
var dnsExeSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
lstDirectExe = new();
|
var directExeSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
|
||||||
foreach (var it in coreInfo)
|
var coreInfoResult = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
|
|
||||||
|
foreach (var coreConfig in coreInfoResult)
|
||||||
{
|
{
|
||||||
if (it.CoreType == ECoreType.v2rayN)
|
if (coreConfig.CoreType == ECoreType.v2rayN)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
foreach (var it2 in it.CoreExes)
|
|
||||||
{
|
|
||||||
if (!lstDnsExe.Contains(it2) && it.CoreType != ECoreType.sing_box)
|
|
||||||
{
|
|
||||||
lstDnsExe.Add($"{it2}.exe");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lstDirectExe.Contains(it2))
|
foreach (var baseExeName in coreConfig.CoreExes)
|
||||||
|
{
|
||||||
|
if (coreConfig.CoreType != ECoreType.sing_box)
|
||||||
{
|
{
|
||||||
lstDirectExe.Add($"{it2}.exe");
|
dnsExeSet.Add(Utils.GetExeName(baseExeName));
|
||||||
}
|
}
|
||||||
|
directExeSet.Add(Utils.GetExeName(baseExeName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lstDnsExe = new List<string>(dnsExeSet);
|
||||||
|
lstDirectExe = new List<string>(directExeSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules)
|
||||||
@@ -1087,14 +1090,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())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (it.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard)
|
if (it.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -328,7 +328,7 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.socks.ToString(),
|
protocol = EInboundProtocol.mixed.ToString(),
|
||||||
};
|
};
|
||||||
inbound.tag = inbound.protocol + inbound.port.ToString();
|
inbound.tag = inbound.protocol + inbound.port.ToString();
|
||||||
v2rayConfig.inbounds.Add(inbound);
|
v2rayConfig.inbounds.Add(inbound);
|
||||||
@@ -403,7 +403,7 @@ public class CoreConfigV2rayService
|
|||||||
tag = $"{EInboundProtocol.socks}{port}",
|
tag = $"{EInboundProtocol.socks}{port}",
|
||||||
listen = Global.Loopback,
|
listen = Global.Loopback,
|
||||||
port = port,
|
port = port,
|
||||||
protocol = EInboundProtocol.socks.ToString(),
|
protocol = EInboundProtocol.mixed.ToString(),
|
||||||
});
|
});
|
||||||
|
|
||||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
@@ -507,7 +507,7 @@ public class CoreConfigV2rayService
|
|||||||
}
|
}
|
||||||
inbound.tag = protocol.ToString();
|
inbound.tag = protocol.ToString();
|
||||||
inbound.port = inItem.LocalPort + (int)protocol;
|
inbound.port = inItem.LocalPort + (int)protocol;
|
||||||
inbound.protocol = EInboundProtocol.socks.ToString();
|
inbound.protocol = EInboundProtocol.mixed.ToString();
|
||||||
inbound.settings.udp = inItem.UdpEnabled;
|
inbound.settings.udp = inItem.UdpEnabled;
|
||||||
inbound.sniffing.enabled = inItem.SniffingEnabled;
|
inbound.sniffing.enabled = inItem.SniffingEnabled;
|
||||||
inbound.sniffing.destOverride = inItem.DestOverride;
|
inbound.sniffing.destOverride = inItem.DestOverride;
|
||||||
@@ -661,7 +661,7 @@ public class CoreConfigV2rayService
|
|||||||
{
|
{
|
||||||
usersItem = vnextItem.users.First();
|
usersItem = vnextItem.users.First();
|
||||||
}
|
}
|
||||||
//远程服务器用户ID
|
|
||||||
usersItem.id = node.Id;
|
usersItem.id = node.Id;
|
||||||
usersItem.alterId = node.AlterId;
|
usersItem.alterId = node.AlterId;
|
||||||
usersItem.email = Global.UserEMail;
|
usersItem.email = Global.UserEMail;
|
||||||
@@ -805,6 +805,26 @@ public class CoreConfigV2rayService
|
|||||||
outbound.settings.vnext = null;
|
outbound.settings.vnext = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EConfigType.WireGuard:
|
||||||
|
{
|
||||||
|
var peer = new WireguardPeer4Ray
|
||||||
|
{
|
||||||
|
publicKey = node.PublicKey,
|
||||||
|
endpoint = node.Address + ":" + node.Port.ToString()
|
||||||
|
};
|
||||||
|
var setting = new Outboundsettings4Ray
|
||||||
|
{
|
||||||
|
address = Utils.String2List(node.RequestHost),
|
||||||
|
secretKey = node.Id,
|
||||||
|
reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList(),
|
||||||
|
mtu = node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId.ToInt(),
|
||||||
|
peers = new List<WireguardPeer4Ray> { peer }
|
||||||
|
};
|
||||||
|
outbound.settings = setting;
|
||||||
|
outbound.settings.vnext = null;
|
||||||
|
outbound.settings.servers = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outbound.protocol = Global.ProtocolTypes[node.ConfigType];
|
outbound.protocol = Global.ProtocolTypes[node.ConfigType];
|
||||||
@@ -1123,7 +1143,7 @@ public class CoreConfigV2rayService
|
|||||||
obj["servers"] = JsonUtils.SerializeToNode(servers);
|
obj["servers"] = JsonUtils.SerializeToNode(servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 追加至 dns 设置
|
// Append to dns settings
|
||||||
if (item.UseSystemHosts)
|
if (item.UseSystemHosts)
|
||||||
{
|
{
|
||||||
var systemHosts = Utils.GetSystemHosts();
|
var systemHosts = Utils.GetSystemHosts();
|
||||||
@@ -1156,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));
|
||||||
}
|
}
|
||||||
@@ -1270,8 +1323,7 @@ public class CoreConfigV2rayService
|
|||||||
if (prevNode is not null
|
if (prevNode is not null
|
||||||
&& prevNode.ConfigType != EConfigType.Custom
|
&& prevNode.ConfigType != EConfigType.Custom
|
||||||
&& prevNode.ConfigType != EConfigType.Hysteria2
|
&& prevNode.ConfigType != EConfigType.Hysteria2
|
||||||
&& prevNode.ConfigType != EConfigType.TUIC
|
&& prevNode.ConfigType != EConfigType.TUIC)
|
||||||
&& prevNode.ConfigType != EConfigType.WireGuard)
|
|
||||||
{
|
{
|
||||||
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var prevOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(prevNode, prevOutbound);
|
await GenOutbound(prevNode, prevOutbound);
|
||||||
@@ -1289,8 +1341,7 @@ public class CoreConfigV2rayService
|
|||||||
if (nextNode is not null
|
if (nextNode is not null
|
||||||
&& nextNode.ConfigType != EConfigType.Custom
|
&& nextNode.ConfigType != EConfigType.Custom
|
||||||
&& nextNode.ConfigType != EConfigType.Hysteria2
|
&& nextNode.ConfigType != EConfigType.Hysteria2
|
||||||
&& nextNode.ConfigType != EConfigType.TUIC
|
&& nextNode.ConfigType != EConfigType.TUIC)
|
||||||
&& nextNode.ConfigType != EConfigType.WireGuard)
|
|
||||||
{
|
{
|
||||||
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
var nextOutbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
await GenOutbound(nextNode, nextOutbound);
|
await GenOutbound(nextNode, nextOutbound);
|
||||||
|
|||||||
@@ -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++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -194,11 +194,11 @@ public class UpdateService
|
|||||||
{
|
{
|
||||||
if (Utils.IsBase64String(result2))
|
if (Utils.IsBase64String(result2))
|
||||||
{
|
{
|
||||||
result += Utils.Base64Decode(result2);
|
result += Environment.NewLine + Utils.Base64Decode(result2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result += result2;
|
result += Environment.NewLine + result2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -100,6 +100,7 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
[Reactive] public string CoreType4 { get; set; }
|
[Reactive] public string CoreType4 { get; set; }
|
||||||
[Reactive] public string CoreType5 { get; set; }
|
[Reactive] public string CoreType5 { get; set; }
|
||||||
[Reactive] public string CoreType6 { get; set; }
|
[Reactive] public string CoreType6 { get; set; }
|
||||||
|
[Reactive] public string CoreType9 { get; set; }
|
||||||
|
|
||||||
#endregion CoreType
|
#endregion CoreType
|
||||||
|
|
||||||
@@ -186,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
|
||||||
|
|
||||||
@@ -204,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
|
||||||
|
|
||||||
@@ -259,6 +260,10 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
case 6:
|
case 6:
|
||||||
CoreType6 = type;
|
CoreType6 = type;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
CoreType9 = type;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Task.CompletedTask;
|
await Task.CompletedTask;
|
||||||
@@ -341,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;
|
||||||
@@ -353,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();
|
||||||
@@ -407,6 +409,10 @@ public class OptionSettingViewModel : MyReactiveObject
|
|||||||
type = CoreType6;
|
type = CoreType6;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
type = CoreType9;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
|||||||
sepa2.IsVisible = false;
|
sepa2.IsVisible = false;
|
||||||
gridTransport.IsVisible = false;
|
gridTransport.IsVisible = false;
|
||||||
gridTls.IsVisible = false;
|
gridTls.IsVisible = false;
|
||||||
cmbCoreType.IsEnabled = false;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
@@ -813,7 +805,7 @@
|
|||||||
<Grid
|
<Grid
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
ColumnDefinitions="Auto,Auto"
|
ColumnDefinitions="Auto,Auto"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
@@ -891,6 +883,19 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin4}" />
|
Margin="{StaticResource Margin4}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="Wireguard" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbCoreType9"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
cmbCoreType4.Items.Add(it);
|
cmbCoreType4.Items.Add(it);
|
||||||
cmbCoreType5.Items.Add(it);
|
cmbCoreType5.Items.Add(it);
|
||||||
cmbCoreType6.Items.Add(it);
|
cmbCoreType6.Items.Add(it);
|
||||||
|
cmbCoreType9.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var i = 2; i <= 8; i++)
|
for (var i = 2; i <= 8; i++)
|
||||||
@@ -91,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());
|
||||||
@@ -142,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);
|
||||||
@@ -152,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);
|
||||||
@@ -160,6 +165,7 @@ public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel
|
|||||||
this.Bind(ViewModel, vm => vm.CoreType4, v => v.cmbCoreType4.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType4, v => v.cmbCoreType4.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType5, v => v.cmbCoreType5.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType5, v => v.cmbCoreType5.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.CoreType9, v => v.cmbCoreType9.SelectedValue).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
@@ -168,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
70
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
Normal file
70
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml
Normal 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>
|
||||||
33
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
Normal file
33
v2rayN/v2rayN.Desktop/Views/SudoPasswordInputView.axaml.cs
Normal 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public partial class App : Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 只打开一个进程
|
/// Open only one process
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,6 @@ internal static class WindowsUtils
|
|||||||
{
|
{
|
||||||
private static readonly string _tag = "WindowsUtils";
|
private static readonly string _tag = "WindowsUtils";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取剪贴板数
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string? GetClipboardData()
|
public static string? GetClipboardData()
|
||||||
{
|
{
|
||||||
var strData = string.Empty;
|
var strData = string.Empty;
|
||||||
@@ -35,10 +31,6 @@ internal static class WindowsUtils
|
|||||||
return strData;
|
return strData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 拷贝至剪贴板
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static void SetClipboardData(string strData)
|
public static void SetClipboardData(string strData)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ public partial class AddServerWindow
|
|||||||
sepa2.Visibility = Visibility.Collapsed;
|
sepa2.Visibility = Visibility.Collapsed;
|
||||||
gridTransport.Visibility = Visibility.Collapsed;
|
gridTransport.Visibility = Visibility.Collapsed;
|
||||||
gridTls.Visibility = Visibility.Collapsed;
|
gridTls.Visibility = Visibility.Collapsed;
|
||||||
cmbCoreType.IsEnabled = false;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -1098,6 +1115,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" />
|
||||||
@@ -1192,6 +1210,21 @@
|
|||||||
Width="200"
|
Width="200"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
Style="{StaticResource DefComboBox}" />
|
Style="{StaticResource DefComboBox}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="Wireguard" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbCoreType9"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
Style="{StaticResource DefComboBox}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public partial class OptionSettingWindow
|
|||||||
cmbCoreType4.Items.Add(it);
|
cmbCoreType4.Items.Add(it);
|
||||||
cmbCoreType5.Items.Add(it);
|
cmbCoreType5.Items.Add(it);
|
||||||
cmbCoreType6.Items.Add(it);
|
cmbCoreType6.Items.Add(it);
|
||||||
|
cmbCoreType9.Items.Add(it);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var i = 2; i <= 8; i++)
|
for (var i = 2; i <= 8; i++)
|
||||||
@@ -100,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());
|
||||||
@@ -161,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);
|
||||||
@@ -178,6 +184,7 @@ public partial class OptionSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.CoreType4, v => v.cmbCoreType4.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType4, v => v.cmbCoreType4.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType5, v => v.cmbCoreType5.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType5, v => v.cmbCoreType5.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.CoreType9, v => v.cmbCoreType9.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
<ListBox
|
<ListBox
|
||||||
x:Name="lstGroup"
|
x:Name="lstGroup"
|
||||||
MaxHeight="200"
|
MaxHeight="200"
|
||||||
|
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}"
|
||||||
FontSize="{DynamicResource StdFontSize}"
|
FontSize="{DynamicResource StdFontSize}"
|
||||||
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
|
||||||
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
|
||||||
@@ -40,6 +41,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 +51,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 +62,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 +74,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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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,11 @@
|
|||||||
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>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Margin="{StaticResource MarginLeftRight8}" VerticalAlignment="Center">
|
<StackPanel Margin="{StaticResource MarginLeftRight8}" VerticalAlignment="Center">
|
||||||
@@ -107,7 +111,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 +126,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 +141,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 +156,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 +172,36 @@
|
|||||||
</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>
|
||||||
</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>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<reactiveui:ReactiveWindow
|
<reactiveui:ReactiveWindow
|
||||||
x:Class="v2rayN.Views.SubEditWindow"
|
x:Class="v2rayN.Views.SubEditWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns: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}"
|
||||||
|
|||||||
@@ -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}"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user