Compare commits

..

12 Commits
6.58 ... 6.59

Author SHA1 Message Date
2dust
a7f3a7b1a7 up 6.59 2024-09-17 18:07:07 +08:00
2dust
71eb5f0813 HyperlinkButton Classes="WithIcon" 2024-09-17 17:26:01 +08:00
2dust
b4f50258a7 Fix style for desktop 2024-09-17 17:20:37 +08:00
2dust
346a9c5fcc Add Connections Host Filter 2024-09-17 16:59:35 +08:00
2dust
61635db5b5 Add IsNotEmpty function 2024-09-17 16:52:41 +08:00
2dust
4c0a59a715 Add Connections Host Filter
https://github.com/2dust/v2rayN/issues/5683
2024-09-17 14:50:31 +08:00
2dust
aa829a66ea Improved Style for Desktop version 2024-09-16 18:21:30 +08:00
2dust
885f193a00 Fix GetVersion 2024-09-16 15:34:35 +08:00
2dust
0a9bbf526d up PackageReference 2024-09-16 15:26:17 +08:00
2dust
ff6716b39d Restore backup file check 2024-09-16 15:23:06 +08:00
2dust
8505f2db96 Optimize backup
https://github.com/2dust/v2rayN/issues/5681
2024-09-16 13:37:38 +08:00
2dust
233d605256 Optimize the information function 2024-09-16 11:09:44 +08:00
62 changed files with 780 additions and 692 deletions

View File

@@ -9,7 +9,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.28.0" />
<PackageReference Include="Google.Protobuf" Version="3.28.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.65.0" />
<PackageReference Include="Grpc.Tools" Version="2.66.0">
<PrivateAssets>all</PrivateAssets>

View File

@@ -18,7 +18,7 @@ namespace ServiceLib.Common
Uri uri = new(url);
//Authorization Header
var headers = new WebHeaderCollection();
if (!Utils.IsNullOrEmpty(uri.UserInfo))
if (Utils.IsNotEmpty(uri.UserInfo))
{
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
}

View File

@@ -82,7 +82,7 @@ namespace ServiceLib.Common
}
try
{
if (!Utils.IsNullOrEmpty(ignoredName) && entry.Name.Contains(ignoredName))
if (Utils.IsNotEmpty(ignoredName) && entry.Name.Contains(ignoredName))
{
continue;
}
@@ -102,6 +102,24 @@ namespace ServiceLib.Common
return true;
}
public static List<string>? GetFilesFromZip(string fileName)
{
if (!File.Exists(fileName))
{
return null;
}
try
{
using ZipArchive archive = ZipFile.OpenRead(fileName);
return archive.Entries.Select(entry => entry.FullName).ToList();
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
return null;
}
}
public static bool CreateFromDirectory(string sourceDirectoryName, string destinationArchiveFileName)
{
try
@@ -139,7 +157,11 @@ namespace ServiceLib.Common
// Get the files in the source directory and copy to the destination directory
foreach (FileInfo file in dir.GetFiles())
{
if (!Utils.IsNullOrEmpty(ignoredName) && file.Name.Contains(ignoredName))
if (Utils.IsNotEmpty(ignoredName) && file.Name.Contains(ignoredName))
{
continue;
}
if (file.Extension == file.Name)
{
continue;
}

View File

@@ -22,7 +22,7 @@ namespace ServiceLib.Common
public async Task<string?> TryGetAsync(string url)
{
if (string.IsNullOrEmpty(url))
if (Utils.IsNullOrEmpty(url))
return null;
try

View File

@@ -14,6 +14,11 @@ namespace ServiceLib.Common
return string.IsNullOrWhiteSpace(value);
}
public static bool IsNotEmpty([NotNullWhen(false)] this string? value)
{
return !string.IsNullOrEmpty(value);
}
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
{
if (s.IsNullOrEmpty()) return false;

View File

@@ -417,6 +417,11 @@ namespace ServiceLib.Common
return false;
}
public static bool IsNotEmpty(string? text)
{
return !string.IsNullOrEmpty(text);
}
/// <summary>
/// 验证IP地址是否合法
/// </summary>
@@ -567,13 +572,12 @@ namespace ServiceLib.Common
{
try
{
string location = GetExePath();
if (blFull)
{
return string.Format("{0} - V{1} - {2}",
Global.AppName,
GetVersionInfo(),
File.GetLastWriteTime(location).ToString("yyyy/MM/dd"));
File.GetLastWriteTime(GetExePath()).ToString("yyyy/MM/dd"));
}
else
{
@@ -593,7 +597,7 @@ namespace ServiceLib.Common
{
try
{
return Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString() ?? "0.0";
return Assembly.GetExecutingAssembly()?.GetName()?.Version?.ToString(3) ?? "0.0";
}
catch (Exception ex)
{

View File

@@ -23,7 +23,7 @@ namespace ServiceLib.Handler
{
//载入配置文件
var result = Utils.LoadResource(Utils.GetConfigPath(configRes));
if (!Utils.IsNullOrEmpty(result))
if (Utils.IsNotEmpty(result))
{
//转成Json
config = JsonUtils.Deserialize<Config>(result);
@@ -1007,7 +1007,7 @@ namespace ServiceLib.Handler
{
return -1;
}
if (!Utils.IsNullOrEmpty(profileItem.security) && profileItem.security != Global.None)
if (Utils.IsNotEmpty(profileItem.security) && profileItem.security != Global.None)
{
profileItem.security = Global.None;
}
@@ -1045,7 +1045,7 @@ namespace ServiceLib.Handler
{
profileItem.configVersion = 2;
if (!Utils.IsNullOrEmpty(profileItem.streamSecurity))
if (Utils.IsNotEmpty(profileItem.streamSecurity))
{
if (profileItem.streamSecurity != Global.StreamSecurity
&& profileItem.streamSecurity != Global.StreamSecurityReality)
@@ -1065,7 +1065,7 @@ namespace ServiceLib.Handler
}
}
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.Networks.Contains(profileItem.network))
if (Utils.IsNotEmpty(profileItem.network) && !Global.Networks.Contains(profileItem.network))
{
profileItem.network = Global.DefaultNetwork;
}
@@ -1186,7 +1186,7 @@ namespace ServiceLib.Handler
string subFilter = string.Empty;
//remove sub items
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
RemoveServerViaSubid(config, subid, isSub);
subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
@@ -1219,7 +1219,7 @@ namespace ServiceLib.Handler
}
//exist sub items
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
var existItem = lstOriSub?.FirstOrDefault(t => t.isSub == isSub
&& config.uiItem.enableUpdateSubOnlyRemarksExist ? t.remarks == profileItem.remarks : CompareProfileItem(t, profileItem, true));
@@ -1241,7 +1241,7 @@ namespace ServiceLib.Handler
}
}
//filter
if (!Utils.IsNullOrEmpty(subFilter))
if (Utils.IsNotEmpty(subFilter))
{
if (!Regex.IsMatch(profileItem.remarks, subFilter))
{
@@ -1305,7 +1305,7 @@ namespace ServiceLib.Handler
}
if (lstProfiles != null && lstProfiles.Count > 0)
{
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
RemoveServerViaSubid(config, subid, isSub);
}
@@ -1361,7 +1361,7 @@ namespace ServiceLib.Handler
return -1;
}
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
RemoveServerViaSubid(config, subid, isSub);
}
@@ -1389,7 +1389,7 @@ namespace ServiceLib.Handler
return -1;
}
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
RemoveServerViaSubid(config, subid, isSub);
}
@@ -1421,7 +1421,7 @@ namespace ServiceLib.Handler
return -1;
}
List<ProfileItem>? lstOriSub = null;
if (isSub && !Utils.IsNullOrEmpty(subid))
if (isSub && Utils.IsNotEmpty(subid))
{
lstOriSub = LazyConfig.Instance.ProfileItems(subid);
}

View File

@@ -43,7 +43,7 @@
}
string addressFileName = node.address;
if (string.IsNullOrEmpty(addressFileName))
if (Utils.IsNullOrEmpty(addressFileName))
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
@@ -117,7 +117,7 @@
if (_config.tunModeItem.enableTun)
{
string tun = Utils.GetEmbedText(Global.ClashTunYaml);
if (!string.IsNullOrEmpty(tun))
if (Utils.IsNotEmpty(tun))
{
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
if (tunContent != null)

View File

@@ -370,7 +370,7 @@ namespace ServiceLib.Handler.CoreConfig
}
string addressFileName = node.address;
if (string.IsNullOrEmpty(addressFileName))
if (Utils.IsNullOrEmpty(addressFileName))
{
msg = ResUI.FailedGetDefaultConfiguration;
return -1;
@@ -489,7 +489,7 @@ namespace ServiceLib.Handler.CoreConfig
if (_config.routingBasicItem.enableRoutingAdvanced)
{
var routing = ConfigHandler.GetDefaultRouting(_config);
if (!Utils.IsNullOrEmpty(routing.domainStrategy4Singbox))
if (Utils.IsNotEmpty(routing.domainStrategy4Singbox))
{
inbound.domain_strategy = routing.domainStrategy4Singbox;
}
@@ -512,7 +512,7 @@ namespace ServiceLib.Handler.CoreConfig
singboxConfig.inbounds.Add(inbound4);
//auth
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
if (Utils.IsNotEmpty(_config.inbound[0].user) && Utils.IsNotEmpty(_config.inbound[0].pass))
{
inbound3.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
inbound4.users = new() { new() { username = _config.inbound[0].user, password = _config.inbound[0].pass } };
@@ -604,8 +604,8 @@ namespace ServiceLib.Handler.CoreConfig
case EConfigType.Socks:
{
outbound.version = "5";
if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id))
if (Utils.IsNotEmpty(node.security)
&& Utils.IsNotEmpty(node.id))
{
outbound.username = node.security;
outbound.password = node.id;
@@ -614,8 +614,8 @@ namespace ServiceLib.Handler.CoreConfig
}
case EConfigType.Http:
{
if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id))
if (Utils.IsNotEmpty(node.security)
&& Utils.IsNotEmpty(node.id))
{
outbound.username = node.security;
outbound.password = node.id;
@@ -649,7 +649,7 @@ namespace ServiceLib.Handler.CoreConfig
{
outbound.password = node.id;
if (!Utils.IsNullOrEmpty(node.path))
if (Utils.IsNotEmpty(node.path))
{
outbound.obfs = new()
{
@@ -695,7 +695,7 @@ namespace ServiceLib.Handler.CoreConfig
{
try
{
if (_config.coreBasicItem.muxEnabled && !Utils.IsNullOrEmpty(_config.mux4SboxItem.protocol))
if (_config.coreBasicItem.muxEnabled && Utils.IsNotEmpty(_config.mux4SboxItem.protocol))
{
var mux = new Multiplex4Sbox()
{
@@ -721,11 +721,11 @@ namespace ServiceLib.Handler.CoreConfig
if (node.streamSecurity == Global.StreamSecurityReality || node.streamSecurity == Global.StreamSecurity)
{
var server_name = string.Empty;
if (!Utils.IsNullOrEmpty(node.sni))
if (Utils.IsNotEmpty(node.sni))
{
server_name = node.sni;
}
else if (!Utils.IsNullOrEmpty(node.requestHost))
else if (Utils.IsNotEmpty(node.requestHost))
{
server_name = Utils.String2List(node.requestHost)[0];
}
@@ -736,7 +736,7 @@ namespace ServiceLib.Handler.CoreConfig
insecure = Utils.ToBool(node.allowInsecure.IsNullOrEmpty() ? _config.coreBasicItem.defAllowInsecure.ToString().ToLower() : node.allowInsecure),
alpn = node.GetAlpn(),
};
if (!Utils.IsNullOrEmpty(node.fingerprint))
if (Utils.IsNotEmpty(node.fingerprint))
{
tls.utls = new Utls4Sbox()
{
@@ -798,7 +798,7 @@ namespace ServiceLib.Handler.CoreConfig
case nameof(ETransport.ws):
transport.type = nameof(ETransport.ws);
transport.path = Utils.IsNullOrEmpty(node.path) ? null : node.path;
if (!Utils.IsNullOrEmpty(node.requestHost))
if (Utils.IsNotEmpty(node.requestHost))
{
transport.headers = new()
{
@@ -1020,7 +1020,7 @@ namespace ServiceLib.Handler.CoreConfig
outbound = item.outboundTag,
};
if (!Utils.IsNullOrEmpty(item.port))
if (Utils.IsNotEmpty(item.port))
{
if (item.port.Contains("-"))
{
@@ -1031,7 +1031,7 @@ namespace ServiceLib.Handler.CoreConfig
rule.port = new List<int> { Utils.ToInt(item.port) };
}
}
if (!Utils.IsNullOrEmpty(item.network))
if (Utils.IsNotEmpty(item.network))
{
rule.network = Utils.String2List(item.network);
}
@@ -1221,7 +1221,7 @@ namespace ServiceLib.Handler.CoreConfig
});
var lstDomain = singboxConfig.outbounds
.Where(t => !Utils.IsNullOrEmpty(t.server) && Utils.IsDomain(t.server))
.Where(t => Utils.IsNotEmpty(t.server) && Utils.IsDomain(t.server))
.Select(t => t.server)
.Distinct()
.ToList();
@@ -1324,10 +1324,10 @@ namespace ServiceLib.Handler.CoreConfig
if (_config.routingBasicItem.enableRoutingAdvanced)
{
var routing = ConfigHandler.GetDefaultRouting(_config);
if (!Utils.IsNullOrEmpty(routing.customRulesetPath4Singbox))
if (Utils.IsNotEmpty(routing.customRulesetPath4Singbox))
{
var result = Utils.LoadResource(routing.customRulesetPath4Singbox);
if (!Utils.IsNullOrEmpty(result))
if (Utils.IsNotEmpty(result))
{
customRulesets = (JsonUtils.Deserialize<List<Ruleset4Sbox>>(result) ?? [])
.Where(t => t.tag != null)

View File

@@ -392,7 +392,7 @@ namespace ServiceLib.Handler.CoreConfig
v2rayConfig.inbounds.Add(inbound4);
//auth
if (!Utils.IsNullOrEmpty(_config.inbound[0].user) && !Utils.IsNullOrEmpty(_config.inbound[0].pass))
if (Utils.IsNotEmpty(_config.inbound[0].user) && Utils.IsNotEmpty(_config.inbound[0].pass))
{
inbound3.settings.auth = "password";
inbound3.settings.accounts = new List<AccountsItem4Ray> { new AccountsItem4Ray() { user = _config.inbound[0].user, pass = _config.inbound[0].pass } };
@@ -453,7 +453,7 @@ namespace ServiceLib.Handler.CoreConfig
var routing = ConfigHandler.GetDefaultRouting(_config);
if (routing != null)
{
if (!Utils.IsNullOrEmpty(routing.domainStrategy))
if (Utils.IsNotEmpty(routing.domainStrategy))
{
v2rayConfig.routing.domainStrategy = routing.domainStrategy;
}
@@ -550,7 +550,7 @@ namespace ServiceLib.Handler.CoreConfig
}
if (!hasDomainIp)
{
if (!Utils.IsNullOrEmpty(rule.port)
if (Utils.IsNotEmpty(rule.port)
|| rule.protocol?.Count > 0
|| rule.inboundTag?.Count > 0
)
@@ -660,8 +660,8 @@ namespace ServiceLib.Handler.CoreConfig
serversItem.method = null;
serversItem.password = null;
if (!Utils.IsNullOrEmpty(node.security)
&& !Utils.IsNullOrEmpty(node.id))
if (Utils.IsNotEmpty(node.security)
&& Utils.IsNotEmpty(node.id))
{
SocksUsersItem4Ray socksUsersItem = new()
{
@@ -712,7 +712,7 @@ namespace ServiceLib.Handler.CoreConfig
if (node.streamSecurity == Global.StreamSecurityReality
|| node.streamSecurity == Global.StreamSecurity)
{
if (!Utils.IsNullOrEmpty(node.flow))
if (Utils.IsNotEmpty(node.flow))
{
usersItem.flow = node.flow;
@@ -818,11 +818,11 @@ namespace ServiceLib.Handler.CoreConfig
alpn = node.GetAlpn(),
fingerprint = node.fingerprint.IsNullOrEmpty() ? _config.coreBasicItem.defFingerprint : node.fingerprint
};
if (!Utils.IsNullOrEmpty(sni))
if (Utils.IsNotEmpty(sni))
{
tlsSettings.serverName = sni;
}
else if (!Utils.IsNullOrEmpty(host))
else if (Utils.IsNotEmpty(host))
{
tlsSettings.serverName = Utils.String2List(host)[0];
}
@@ -867,7 +867,7 @@ namespace ServiceLib.Handler.CoreConfig
{
type = node.headerType
};
if (!Utils.IsNullOrEmpty(node.path))
if (Utils.IsNotEmpty(node.path))
{
kcpSettings.seed = node.path;
}
@@ -878,15 +878,15 @@ namespace ServiceLib.Handler.CoreConfig
WsSettings4Ray wsSettings = new();
wsSettings.headers = new Headers4Ray();
string path = node.path;
if (!Utils.IsNullOrEmpty(host))
if (Utils.IsNotEmpty(host))
{
wsSettings.headers.Host = host;
}
if (!Utils.IsNullOrEmpty(path))
if (Utils.IsNotEmpty(path))
{
wsSettings.path = path;
}
if (!Utils.IsNullOrEmpty(useragent))
if (Utils.IsNotEmpty(useragent))
{
wsSettings.headers.UserAgent = useragent;
}
@@ -897,11 +897,11 @@ namespace ServiceLib.Handler.CoreConfig
case nameof(ETransport.httpupgrade):
HttpupgradeSettings4Ray httpupgradeSettings = new();
if (!Utils.IsNullOrEmpty(node.path))
if (Utils.IsNotEmpty(node.path))
{
httpupgradeSettings.path = node.path;
}
if (!Utils.IsNullOrEmpty(host))
if (Utils.IsNotEmpty(host))
{
httpupgradeSettings.host = host;
}
@@ -916,11 +916,11 @@ namespace ServiceLib.Handler.CoreConfig
maxConcurrentUploads = 10
};
if (!Utils.IsNullOrEmpty(node.path))
if (Utils.IsNotEmpty(node.path))
{
splithttpSettings.path = node.path;
}
if (!Utils.IsNullOrEmpty(host))
if (Utils.IsNotEmpty(host))
{
splithttpSettings.host = host;
}
@@ -931,7 +931,7 @@ namespace ServiceLib.Handler.CoreConfig
case nameof(ETransport.h2):
HttpSettings4Ray httpSettings = new();
if (!Utils.IsNullOrEmpty(host))
if (Utils.IsNotEmpty(host))
{
httpSettings.host = Utils.String2List(host);
}
@@ -954,7 +954,7 @@ namespace ServiceLib.Handler.CoreConfig
streamSettings.quicSettings = quicsettings;
if (node.streamSecurity == Global.StreamSecurity)
{
if (!Utils.IsNullOrEmpty(sni))
if (Utils.IsNotEmpty(sni))
{
streamSettings.tlsSettings.serverName = sni;
}
@@ -1000,7 +1000,7 @@ namespace ServiceLib.Handler.CoreConfig
request = request.Replace("$requestUserAgent$", $"\"{useragent}\"");
//Path
string pathHttp = @"/";
if (!Utils.IsNullOrEmpty(node.path))
if (Utils.IsNotEmpty(node.path))
{
string[] arrPath = node.path.Split(',');
pathHttp = string.Join("\",\"", arrPath);
@@ -1033,7 +1033,7 @@ namespace ServiceLib.Handler.CoreConfig
}
//Outbound Freedom domainStrategy
if (!Utils.IsNullOrEmpty(domainStrategy4Freedom))
if (Utils.IsNotEmpty(domainStrategy4Freedom))
{
var outbound = v2rayConfig.outbounds[1];
outbound.settings.domainStrategy = domainStrategy4Freedom;
@@ -1157,7 +1157,7 @@ namespace ServiceLib.Handler.CoreConfig
{
//fragment proxy
if (_config.coreBasicItem.enableFragment
&& !Utils.IsNullOrEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
&& Utils.IsNotEmpty(v2rayConfig.outbounds[0].streamSettings?.security))
{
var fragmentOutbound = new Outbounds4Ray
{

View File

@@ -302,7 +302,7 @@ namespace ServiceLib.Handler
{
proc.OutputDataReceived += (sender, e) =>
{
if (!Utils.IsNullOrEmpty(e.Data))
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);
@@ -310,7 +310,7 @@ namespace ServiceLib.Handler
};
proc.ErrorDataReceived += (sender, e) =>
{
if (!Utils.IsNullOrEmpty(e.Data))
if (Utils.IsNotEmpty(e.Data))
{
string msg = e.Data + Environment.NewLine;
ShowMsg(false, msg);

View File

@@ -117,7 +117,7 @@ namespace ServiceLib.Handler
try
{
var result1 = await DownloadStringAsync(url, blProxy, userAgent);
if (!Utils.IsNullOrEmpty(result1))
if (Utils.IsNotEmpty(result1))
{
return result1;
}
@@ -135,7 +135,7 @@ namespace ServiceLib.Handler
try
{
var result2 = await DownloadStringViaDownloader(url, blProxy, userAgent);
if (!Utils.IsNullOrEmpty(result2))
if (Utils.IsNotEmpty(result2))
{
return result2;
}
@@ -155,7 +155,7 @@ namespace ServiceLib.Handler
using var wc = new WebClient();
wc.Proxy = GetWebProxy(blProxy);
var result3 = await wc.DownloadStringTaskAsync(url);
if (!Utils.IsNullOrEmpty(result3))
if (Utils.IsNotEmpty(result3))
{
return result3;
}
@@ -197,7 +197,7 @@ namespace ServiceLib.Handler
Uri uri = new(url);
//Authorization Header
if (!Utils.IsNullOrEmpty(uri.UserInfo))
if (Utils.IsNotEmpty(uri.UserInfo))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Utils.Base64Encode(uri.UserInfo));
}

View File

@@ -16,12 +16,12 @@ namespace ServiceLib.Handler.Fmt
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
{
if (!Utils.IsNullOrEmpty(item.flow))
if (Utils.IsNotEmpty(item.flow))
{
dicQuery.Add("flow", item.flow);
}
if (!Utils.IsNullOrEmpty(item.streamSecurity))
if (Utils.IsNotEmpty(item.streamSecurity))
{
dicQuery.Add("security", item.streamSecurity);
}
@@ -32,27 +32,27 @@ namespace ServiceLib.Handler.Fmt
dicQuery.Add("security", securityDef);
}
}
if (!Utils.IsNullOrEmpty(item.sni))
if (Utils.IsNotEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
if (Utils.IsNotEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}
if (!Utils.IsNullOrEmpty(item.fingerprint))
if (Utils.IsNotEmpty(item.fingerprint))
{
dicQuery.Add("fp", Utils.UrlEncode(item.fingerprint));
}
if (!Utils.IsNullOrEmpty(item.publicKey))
if (Utils.IsNotEmpty(item.publicKey))
{
dicQuery.Add("pbk", Utils.UrlEncode(item.publicKey));
}
if (!Utils.IsNullOrEmpty(item.shortId))
if (Utils.IsNotEmpty(item.shortId))
{
dicQuery.Add("sid", Utils.UrlEncode(item.shortId));
}
if (!Utils.IsNullOrEmpty(item.spiderX))
if (Utils.IsNotEmpty(item.spiderX))
{
dicQuery.Add("spx", Utils.UrlEncode(item.spiderX));
}
@@ -61,21 +61,21 @@ namespace ServiceLib.Handler.Fmt
dicQuery.Add("allowInsecure", "1");
}
dicQuery.Add("type", !Utils.IsNullOrEmpty(item.network) ? item.network : nameof(ETransport.tcp));
dicQuery.Add("type", Utils.IsNotEmpty(item.network) ? item.network : nameof(ETransport.tcp));
switch (item.network)
{
case nameof(ETransport.tcp):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
if (!Utils.IsNullOrEmpty(item.requestHost))
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
if (Utils.IsNotEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
break;
case nameof(ETransport.kcp):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
if (!Utils.IsNullOrEmpty(item.path))
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("seed", Utils.UrlEncode(item.path));
}
@@ -84,11 +84,11 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.ws):
case nameof(ETransport.httpupgrade):
case nameof(ETransport.splithttp):
if (!Utils.IsNullOrEmpty(item.requestHost))
if (Utils.IsNotEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.path))
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("path", Utils.UrlEncode(item.path));
}
@@ -97,24 +97,24 @@ namespace ServiceLib.Handler.Fmt
case nameof(ETransport.http):
case nameof(ETransport.h2):
dicQuery["type"] = nameof(ETransport.http);
if (!Utils.IsNullOrEmpty(item.requestHost))
if (Utils.IsNotEmpty(item.requestHost))
{
dicQuery.Add("host", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.path))
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("path", Utils.UrlEncode(item.path));
}
break;
case nameof(ETransport.quic):
dicQuery.Add("headerType", !Utils.IsNullOrEmpty(item.headerType) ? item.headerType : Global.None);
dicQuery.Add("headerType", Utils.IsNotEmpty(item.headerType) ? item.headerType : Global.None);
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.requestHost));
dicQuery.Add("key", Utils.UrlEncode(item.path));
break;
case nameof(ETransport.grpc):
if (!Utils.IsNullOrEmpty(item.path))
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("authority", Utils.UrlEncode(item.requestHost));
dicQuery.Add("serviceName", Utils.UrlEncode(item.path));

View File

@@ -31,20 +31,20 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.sni))
if (Utils.IsNotEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
if (Utils.IsNotEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}
if (!Utils.IsNullOrEmpty(item.path))
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("obfs", "salamander");
dicQuery.Add("obfs-password", Utils.UrlEncode(item.path));

View File

@@ -30,7 +30,7 @@ namespace ServiceLib.Handler.Fmt
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
@@ -59,7 +59,7 @@ namespace ServiceLib.Handler.Fmt
ProfileItem item = new();
var base64 = match.Groups["base64"].Value.TrimEnd('/');
var tag = match.Groups["tag"].Value;
if (!Utils.IsNullOrEmpty(tag))
if (Utils.IsNotEmpty(tag))
{
item.remarks = Utils.UrlDecode(tag);
}
@@ -128,7 +128,7 @@ namespace ServiceLib.Handler.Fmt
{
//obfs-host exists
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
if (queryParameters["plugin"].Contains("obfs=http") && !Utils.IsNullOrEmpty(obfsHost))
if (queryParameters["plugin"].Contains("obfs=http") && Utils.IsNotEmpty(obfsHost))
{
obfsHost = obfsHost?.Replace("obfs-host=", "");
item.network = Global.DefaultNetwork;

View File

@@ -28,7 +28,7 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}

View File

@@ -30,7 +30,7 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}

View File

@@ -36,16 +36,16 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.sni))
if (Utils.IsNotEmpty(item.sni))
{
dicQuery.Add("sni", item.sni);
}
if (!Utils.IsNullOrEmpty(item.alpn))
if (Utils.IsNotEmpty(item.alpn))
{
dicQuery.Add("alpn", Utils.UrlEncode(item.alpn));
}

View File

@@ -33,12 +33,12 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.security))
if (Utils.IsNotEmpty(item.security))
{
dicQuery.Add("encryption", item.security);
}

View File

@@ -78,12 +78,12 @@
item.alterId = Utils.ToInt(vmessQRCode.aid);
item.security = Utils.ToString(vmessQRCode.scy);
item.security = !Utils.IsNullOrEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
if (!Utils.IsNullOrEmpty(vmessQRCode.net))
item.security = Utils.IsNotEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
if (Utils.IsNotEmpty(vmessQRCode.net))
{
item.network = vmessQRCode.net;
}
if (!Utils.IsNullOrEmpty(vmessQRCode.type))
if (Utils.IsNotEmpty(vmessQRCode.type))
{
item.headerType = vmessQRCode.type;
}

View File

@@ -34,25 +34,25 @@
string url = string.Empty;
string remark = string.Empty;
if (!Utils.IsNullOrEmpty(item.remarks))
if (Utils.IsNotEmpty(item.remarks))
{
remark = "#" + Utils.UrlEncode(item.remarks);
}
var dicQuery = new Dictionary<string, string>();
if (!Utils.IsNullOrEmpty(item.publicKey))
if (Utils.IsNotEmpty(item.publicKey))
{
dicQuery.Add("publickey", Utils.UrlEncode(item.publicKey));
}
if (!Utils.IsNullOrEmpty(item.path))
if (Utils.IsNotEmpty(item.path))
{
dicQuery.Add("reserved", Utils.UrlEncode(item.path));
}
if (!Utils.IsNullOrEmpty(item.requestHost))
if (Utils.IsNotEmpty(item.requestHost))
{
dicQuery.Add("address", Utils.UrlEncode(item.requestHost));
}
if (!Utils.IsNullOrEmpty(item.shortId))
if (Utils.IsNotEmpty(item.shortId))
{
dicQuery.Add("mtu", Utils.UrlEncode(item.shortId));
}

View File

@@ -104,11 +104,11 @@
from ProfileItem a
left join SubItem b on a.subid = b.id
where 1=1 ";
if (!Utils.IsNullOrEmpty(subid))
if (Utils.IsNotEmpty(subid))
{
sql += $" and a.subid = '{subid}'";
}
if (!Utils.IsNullOrEmpty(filter))
if (Utils.IsNotEmpty(filter))
{
if (filter.Contains('\''))
{

View File

@@ -35,7 +35,7 @@ namespace ServiceLib.Handler
private void IndexIdEnqueue(string indexId)
{
if (!Utils.IsNullOrEmpty(indexId) && !_queIndexIds.Contains(indexId))
if (Utils.IsNotEmpty(indexId) && !_queIndexIds.Contains(indexId))
{
_queIndexIds.Enqueue(indexId);
}

View File

@@ -88,7 +88,7 @@ namespace ServiceLib.Handler.Statistics
while (!res.CloseStatus.HasValue)
{
var result = Encoding.UTF8.GetString(buffer, 0, res.Count);
if (!Utils.IsNullOrEmpty(result))
if (Utils.IsNotEmpty(result))
{
ParseOutput(result, out ulong up, out ulong down);

View File

@@ -143,7 +143,7 @@ namespace ServiceLib.Handler
string url = item.url.TrimEx();
string userAgent = item.userAgent.TrimEx();
string hashCode = $"{item.remarks}->";
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (!Utils.IsNullOrEmpty(subId) && item.id != subId))
if (Utils.IsNullOrEmpty(id) || Utils.IsNullOrEmpty(url) || (Utils.IsNotEmpty(subId) && item.id != subId))
{
//_updateFunc(false, $"{hashCode}{ResUI.MsgNoValidSubscription}");
continue;
@@ -169,7 +169,7 @@ namespace ServiceLib.Handler
//one url
url = Utils.GetPunycode(url);
//convert
if (!Utils.IsNullOrEmpty(item.convertTarget))
if (Utils.IsNotEmpty(item.convertTarget))
{
var subConvertUrl = Utils.IsNullOrEmpty(config.constItem.subConvertUrl) ? Global.SubConvertUrls.FirstOrDefault() : config.constItem.subConvertUrl;
url = string.Format(subConvertUrl!, Utils.UrlEncode(url));
@@ -189,9 +189,9 @@ namespace ServiceLib.Handler
}
//more url
if (Utils.IsNullOrEmpty(item.convertTarget) && !Utils.IsNullOrEmpty(item.moreUrl.TrimEx()))
if (Utils.IsNullOrEmpty(item.convertTarget) && Utils.IsNotEmpty(item.moreUrl.TrimEx()))
{
if (!Utils.IsNullOrEmpty(result) && Utils.IsBase64String(result!))
if (Utils.IsNotEmpty(result) && Utils.IsBase64String(result!))
{
result = Utils.Base64Decode(result);
}
@@ -210,7 +210,7 @@ namespace ServiceLib.Handler
{
result2 = await downloadHandle.TryDownloadString(url2, false, userAgent);
}
if (!Utils.IsNullOrEmpty(result2))
if (Utils.IsNotEmpty(result2))
{
if (Utils.IsBase64String(result2!))
{
@@ -261,14 +261,10 @@ namespace ServiceLib.Handler
_updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
}
public void RunAvailabilityCheck(Action<bool, string> update)
public async Task RunAvailabilityCheck(Action<bool, string> update)
{
Task.Run(async () =>
{
var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
update(false, string.Format(ResUI.TestMeOutput, time));
});
var time = await (new DownloadHandler()).RunAvailabilityCheck(null);
update(false, string.Format(ResUI.TestMeOutput, time));
}
#region private
@@ -281,7 +277,7 @@ namespace ServiceLib.Handler
var url = coreInfo?.coreReleaseApiUrl;
var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName);
if (!Utils.IsNullOrEmpty(result))
if (Utils.IsNotEmpty(result))
{
return await ParseDownloadUrl(type, result, preRelease);
}

View File

@@ -105,6 +105,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Host filter 的本地化字符串。
/// </summary>
public static string ConnectionsHostFilterTitle {
get {
return ResourceManager.GetString("ConnectionsHostFilterTitle", resourceCulture);
}
}
/// <summary>
/// 查找类似 Note that custom configuration relies entirely on your own configuration and does not work with all settings. If you want to use the system proxy, please modify the listening port manually. 的本地化字符串。
/// </summary>
@@ -321,6 +330,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Invalid backup file 的本地化字符串。
/// </summary>
public static string LocalRestoreInvalidZipTips {
get {
return ResourceManager.GetString("LocalRestoreInvalidZipTips", resourceCulture);
}
}
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>

View File

@@ -1315,4 +1315,10 @@
<data name="LvWebDavDirName" xml:space="preserve">
<value>Remote folder name (optional)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>Invalid backup file</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>Host filter</value>
</data>
</root>

View File

@@ -1312,4 +1312,10 @@
<data name="LvWebDavDirName" xml:space="preserve">
<value>远程文件夹名称(可选)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>无效备份文件</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>主机过滤器</value>
</data>
</root>

View File

@@ -1192,4 +1192,10 @@
<data name="LvWebDavDirName" xml:space="preserve">
<value>遠端資料夾名稱(可選)</value>
</data>
<data name="LocalRestoreInvalidZipTips" xml:space="preserve">
<value>無效備份文件</value>
</data>
<data name="ConnectionsHostFilterTitle" xml:space="preserve">
<value>主機過濾器</value>
</data>
</root>

View File

@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>6.58</Version>
<Version>6.59.0</Version>
</PropertyGroup>
<ItemGroup>
@@ -14,7 +14,7 @@
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
<PackageReference Include="Splat.NLog" Version="15.1.1" />
<PackageReference Include="WebDav.Client" Version="2.8.0" />
<PackageReference Include="YamlDotNet" Version="16.1.0" />
<PackageReference Include="YamlDotNet" Version="16.1.2" />
<PackageReference Include="QRCoder" Version="1.6.0" />
</ItemGroup>

View File

@@ -90,7 +90,7 @@ namespace ServiceLib.ViewModels
if (ConfigHandler.AddCustomServer(_config, item, false) == 0)
{
_noticeHandler?.Enqueue(ResUI.SuccessfullyImportedCustomServer);
if (!Utils.IsNullOrEmpty(item.indexId))
if (Utils.IsNotEmpty(item.indexId))
{
SelectedSource = JsonUtils.DeepCopy(item);
}

View File

@@ -7,6 +7,9 @@ namespace ServiceLib.ViewModels
{
public class BackupAndRestoreViewModel : MyReactiveObject
{
private readonly string _guiConfigs = "guiConfigs";
private static string BackupFileName => $"backup_{DateTime.Now:yyyyMMddHHmmss}.zip";
public ReactiveCommand<Unit, Unit> RemoteBackupCmd { get; }
public ReactiveCommand<Unit, Unit> RemoteRestoreCmd { get; }
public ReactiveCommand<Unit, Unit> WebDavCheckCmd { get; }
@@ -65,7 +68,7 @@ namespace ServiceLib.ViewModels
private async Task RemoteBackup()
{
DisplayOperationMsg();
var fileName = Utils.GetBackupPath($"backup_{DateTime.Now:yyyyMMddHHmmss}.zip");
var fileName = Utils.GetBackupPath(BackupFileName);
var result = await CreateZipFileFromDirectory(fileName);
if (result)
{
@@ -122,9 +125,16 @@ namespace ServiceLib.ViewModels
{
return;
}
//check
var lstFiles = FileManager.GetFilesFromZip(fileName);
if (lstFiles is null || !lstFiles.Where(t => t.Contains(_guiConfigs)).Any())
{
DisplayOperationMsg(ResUI.LocalRestoreInvalidZipTips);
return;
}
//backup first
var fileBackup = Utils.GetBackupPath($"backup_{DateTime.Now:yyyyMMddHHmmss}.zip");
var fileBackup = Utils.GetBackupPath(BackupFileName);
var result = await CreateZipFileFromDirectory(fileBackup);
if (result)
{
@@ -145,9 +155,9 @@ namespace ServiceLib.ViewModels
var configDir = Utils.GetConfigPath();
var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}");
var configDirTemp = Path.Combine(configDirZipTemp, "guiConfigs");
var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs);
await Task.Run(() => FileManager.CopyDirectory(configDir, configDirTemp, true, "cache.db"));
await Task.Run(() => FileManager.CopyDirectory(configDir, configDirTemp, false, "cache.db"));
var ret = await Task.Run(() => FileManager.CreateFromDirectory(configDirZipTemp, fileName));
await Task.Run(() => Directory.Delete(configDirZipTemp, true));
return ret;

View File

@@ -19,6 +19,9 @@ namespace ServiceLib.ViewModels
public ReactiveCommand<Unit, Unit> ConnectionCloseCmd { get; }
public ReactiveCommand<Unit, Unit> ConnectionCloseAllCmd { get; }
[Reactive]
public string HostFilter { get; set; }
[Reactive]
public int SortingSelected { get; set; }
@@ -34,7 +37,7 @@ namespace ServiceLib.ViewModels
var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource,
selectedSource => selectedSource != null && !string.IsNullOrEmpty(selectedSource.id));
selectedSource => selectedSource != null && Utils.IsNotEmpty(selectedSource.id));
this.WhenAnyValue(
x => x.SortingSelected,
@@ -77,7 +80,7 @@ namespace ServiceLib.ViewModels
{
var lastTime = DateTime.Now;
Observable.Interval(TimeSpan.FromSeconds(10))
Observable.Interval(TimeSpan.FromSeconds(5))
.Subscribe(x =>
{
if (!(AutoRefresh && _config.uiItem.showInTaskbar && _config.IsRunningCore(ECoreType.clash)))
@@ -118,12 +121,18 @@ namespace ServiceLib.ViewModels
var lstModel = new List<ClashConnectionModel>();
foreach (var item in connections ?? [])
{
var host = $"{(Utils.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter))
{
continue;
}
ClashConnectionModel model = new();
model.id = item.id;
model.network = item.metadata.network;
model.type = item.metadata.type;
model.host = $"{(string.IsNullOrEmpty(item.metadata.host) ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
model.host = host;
var sp = (dtNow - item.start);
model.time = sp.TotalSeconds < 0 ? 1 : sp.TotalSeconds;
model.upload = item.upload;

View File

@@ -57,7 +57,7 @@ namespace ServiceLib.ViewModels
this.WhenAnyValue(
x => x.SelectedGroup,
y => y != null && !string.IsNullOrEmpty(y.name))
y => y != null && Utils.IsNotEmpty(y.name))
.Subscribe(c => RefreshProxyDetails(c));
this.WhenAnyValue(
@@ -194,7 +194,7 @@ namespace ServiceLib.ViewModels
{
foreach (var it in proxyGroups)
{
if (string.IsNullOrEmpty(it.name) || !_proxies.ContainsKey(it.name))
if (Utils.IsNullOrEmpty(it.name) || !_proxies.ContainsKey(it.name))
{
continue;
}
@@ -220,7 +220,7 @@ namespace ServiceLib.ViewModels
continue;
}
var item = _proxyGroups.Where(t => t.name == kv.Key).FirstOrDefault();
if (item != null && !string.IsNullOrEmpty(item.name))
if (item != null && Utils.IsNotEmpty(item.name))
{
continue;
}
@@ -257,7 +257,7 @@ namespace ServiceLib.ViewModels
return;
}
var name = SelectedGroup?.name;
if (string.IsNullOrEmpty(name))
if (Utils.IsNullOrEmpty(name))
{
return;
}
@@ -342,21 +342,21 @@ namespace ServiceLib.ViewModels
public void SetActiveProxy()
{
if (SelectedGroup == null || string.IsNullOrEmpty(SelectedGroup.name))
if (SelectedGroup == null || Utils.IsNullOrEmpty(SelectedGroup.name))
{
return;
}
if (SelectedDetail == null || string.IsNullOrEmpty(SelectedDetail.name))
if (SelectedDetail == null || Utils.IsNullOrEmpty(SelectedDetail.name))
{
return;
}
var name = SelectedGroup.name;
if (string.IsNullOrEmpty(name))
if (Utils.IsNullOrEmpty(name))
{
return;
}
var nameNode = SelectedDetail.name;
if (string.IsNullOrEmpty(nameNode))
if (Utils.IsNullOrEmpty(nameNode))
{
return;
}
@@ -393,7 +393,7 @@ namespace ServiceLib.ViewModels
GetClashProxies(true);
return;
}
if (string.IsNullOrEmpty(result))
if (Utils.IsNullOrEmpty(result))
{
return;
}

View File

@@ -58,7 +58,7 @@ namespace ServiceLib.ViewModels
private async Task SaveSettingAsync()
{
if (!Utils.IsNullOrEmpty(normalDNS))
if (Utils.IsNotEmpty(normalDNS))
{
var obj = JsonUtils.ParseJson(normalDNS);
if (obj != null && obj["servers"] != null)
@@ -73,7 +73,7 @@ namespace ServiceLib.ViewModels
}
}
}
if (!Utils.IsNullOrEmpty(normalDNS2))
if (Utils.IsNotEmpty(normalDNS2))
{
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(normalDNS2);
if (obj2 == null)
@@ -82,7 +82,7 @@ namespace ServiceLib.ViewModels
return;
}
}
if (!Utils.IsNullOrEmpty(tunDNS2))
if (Utils.IsNotEmpty(tunDNS2))
{
var obj2 = JsonUtils.Deserialize<Dns4Sbox>(tunDNS2);
if (obj2 == null)

View File

@@ -349,10 +349,6 @@ namespace ServiceLib.ViewModels
private void UpdateHandler(bool notify, string msg)
{
if (!_config.uiItem.showInTaskbar)
{
return;
}
_noticeHandler?.SendMessage(msg);
if (notify)
{
@@ -611,21 +607,16 @@ namespace ServiceLib.ViewModels
SetDefaultServer(SelectedServer.ID);
}
public void TestServerAvailability()
public async Task TestServerAvailability()
{
var item = ConfigHandler.GetDefaultServer(_config);
if (item == null)
{
return;
}
(new UpdateHandler()).RunAvailabilityCheck(async (bool success, string msg) =>
await (new UpdateHandler()).RunAvailabilityCheck(async (bool success, string msg) =>
{
_noticeHandler?.SendMessageEx(msg);
if (!_config.uiItem.showInTaskbar)
{
return;
}
await _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
});
}
@@ -715,7 +706,7 @@ namespace ServiceLib.ViewModels
LoadCore().ContinueWith(async task =>
{
TestServerAvailability();
await TestServerAvailability();
await _updateView?.Invoke(EViewAction.DispatcherReload, null);
});

View File

@@ -60,6 +60,10 @@ namespace ServiceLib.ViewModels
}
_blLockShow = true;
if (!_config.uiItem.showInTaskbar)
{
await Task.Delay(1000);
}
await Task.Delay(100);
var txt = string.Join("", _queueMsg.ToArray());
@@ -72,7 +76,7 @@ namespace ServiceLib.ViewModels
{
//filter msg
if (MsgFilter != _lastMsgFilter) _lastMsgFilterNotAvailable = false;
if (!Utils.IsNullOrEmpty(MsgFilter) && !_lastMsgFilterNotAvailable)
if (Utils.IsNotEmpty(MsgFilter) && !_lastMsgFilterNotAvailable)
{
try
{

View File

@@ -265,13 +265,13 @@ namespace ServiceLib.ViewModels
var item = _profileItems.Where(it => it.indexId == result.IndexId).FirstOrDefault();
if (item != null)
{
if (!Utils.IsNullOrEmpty(result.Delay))
if (Utils.IsNotEmpty(result.Delay))
{
int.TryParse(result.Delay, out int temp);
item.delay = temp;
item.delayVal = $"{result.Delay} {Global.DelayUnit}";
}
if (!Utils.IsNullOrEmpty(result.Speed))
if (Utils.IsNotEmpty(result.Speed))
{
item.speedVal = $"{result.Speed} {Global.SpeedUnit}";
}

View File

@@ -80,7 +80,7 @@ namespace ServiceLib.ViewModels
|| SelectedSource.ip?.Count > 0
|| SelectedSource.protocol?.Count > 0
|| SelectedSource.process?.Count > 0
|| !Utils.IsNullOrEmpty(SelectedSource.port);
|| Utils.IsNotEmpty(SelectedSource.port);
if (!hasRule)
{

View File

@@ -13,7 +13,10 @@
<TrayIcon.Icons>
<TrayIcons>
<TrayIcon Clicked="TrayIcon_Clicked" Icon="/Assets/NotifyIcon1.ico">
<TrayIcon
Clicked="TrayIcon_Clicked"
Icon="/Assets/NotifyIcon1.ico"
ToolTipText="v2rayN Desktop">
<TrayIcon.Menu>
<NativeMenu>
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />

View File

@@ -5,22 +5,6 @@
</Border>
</Design.PreviewWith>
<Style Selector="TextBlock.Margin4">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="StackPanel.Margin4">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="DockPanel.Margin4">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="WrapPanel.Margin4">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="Grid.Margin4">
<Setter Property="Margin" Value="8" />
</Style>
<Style Selector="TextBlock.Margin8">
<Setter Property="Margin" Value="8" />
</Style>

View File

@@ -70,7 +70,7 @@ namespace v2rayN.Desktop.ViewModels
y => y != null && !y.IsNullOrEmpty())
.Subscribe(c =>
{
if (!Utils.IsNullOrEmpty(CurrentLanguage) && _config.uiItem.currentLanguage != CurrentLanguage)
if (Utils.IsNotEmpty(CurrentLanguage) && _config.uiItem.currentLanguage != CurrentLanguage)
{
_config.uiItem.currentLanguage = CurrentLanguage;
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);

View File

@@ -16,7 +16,7 @@
<DockPanel Classes="Margin8">
<StackPanel
HorizontalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
@@ -57,14 +57,14 @@
<TextBlock
Grid.Row="0"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.menuServers}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbRemarks}" />
<TextBox
@@ -74,13 +74,13 @@
Width="400"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbAddress}" />
<TextBox
x:Name="txtAddress"
@@ -89,7 +89,7 @@
Width="400"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
IsReadOnly="True" />
<StackPanel
Grid.Row="2"
@@ -110,7 +110,7 @@
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbCoreType}" />
<ComboBox
x:Name="cmbCoreType"
@@ -118,24 +118,24 @@
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin4"
Classes="Margin8"
MaxDropDownHeight="1000" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbDisplayLog}" />
<StackPanel
Grid.Row="4"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
Orientation="Horizontal">
<ToggleSwitch
x:Name="togDisplayLog"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"
@@ -146,7 +146,7 @@
Grid.Row="5"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
<TextBox
x:Name="txtPreSocksPort"
@@ -154,12 +154,12 @@
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
<StackPanel
Grid.Row="6"
Grid.Column="1"
Grid.ColumnSpan="2"
Classes="Margin4">
Classes="Margin8">
<TextBlock
Width="500"
VerticalAlignment="Center"

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,13 @@
DockPanel.Dock="Top"
Orientation="Horizontal">
<TextBox
x:Name="txtHostFilter"
Width="200"
Margin="8,0"
VerticalContentAlignment="Center"
Watermark="{x:Static resx:ResUI.ConnectionsHostFilterTitle}" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"

View File

@@ -21,6 +21,7 @@ namespace v2rayN.Desktop.Views
this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);

View File

@@ -92,7 +92,6 @@
<DockPanel>
<ListBox
x:Name="lstProxyGroups"
Margin="0,0,5,0"
DockPanel.Dock="Left"
ItemsSource="{Binding ProxyGroups}">
<ItemsControl.ItemsPanel>
@@ -108,16 +107,17 @@
Padding="0"
Theme="{StaticResource CardBorder}">
<DockPanel>
<Grid Grid.Column="0" Classes="Margin4">
<Grid Grid.Column="0" Classes="Margin8">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition Height="1*" />
<RowDefinition Height="8" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<TextBlock DockPanel.Dock="Right" Text="{Binding type}" />
<TextBlock Text="{Binding name}" />
</DockPanel>
<TextBlock Grid.Row="1" Text="{Binding now}" />
<TextBlock Grid.Row="2" Text="{Binding now}" />
</Grid>
</DockPanel>
</Border>
@@ -141,6 +141,7 @@
<DataTemplate>
<Border
Width="160"
Margin="0"
Padding="0"
Theme="{StaticResource CardBorder}">
<DockPanel>
@@ -152,16 +153,17 @@
CornerRadius="4"
DockPanel.Dock="Left"
IsVisible="{Binding isActive}" />
<Grid Classes="Margin4">
<Grid Classes="Margin8">
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
<RowDefinition Height="8" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Text="{Binding name}"
TextWrapping="WrapWithOverflow" />
<DockPanel Grid.Row="1">
<DockPanel Grid.Row="2">
<TextBlock
DockPanel.Dock="Right"
Foreground="{Binding Path=delay, Converter={StaticResource DelayColorConverter}}"

View File

@@ -16,7 +16,7 @@
<DockPanel Classes="Margin8">
<StackPanel
HorizontalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
@@ -43,9 +43,9 @@
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
<TextBlock VerticalAlignment="Center" Classes="Margin8">
<Button Click="linkDnsObjectDoc_Click">
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
</Button>
</HyperlinkButton>
</TextBlock>
<Button
x:Name="btnImportDefConfig4V2ray"
@@ -95,7 +95,7 @@
BorderThickness="1"
Classes="TextArea Margin8"
TextWrapping="Wrap"
ToolTip.Tip="Http/Socks" />
Watermark="Http/Socks" />
</DockPanel>
</TabItem>
@@ -103,9 +103,9 @@
<DockPanel Classes="Margin8">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Classes="Margin8">
<Button Click="linkDnsSingboxObjectDoc_Click">
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
</Button>
</HyperlinkButton>
</TextBlock>
<Button
x:Name="btnImportDefConfig4Singbox"
@@ -153,7 +153,7 @@
BorderThickness="1"
Classes="TextArea Margin8"
TextWrapping="Wrap"
ToolTip.Tip="Http/Socks" />
Watermark="Http/Socks" />
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
@@ -165,7 +165,7 @@
BorderThickness="1"
Classes="TextArea Margin8"
TextWrapping="Wrap"
ToolTip.Tip="{x:Static resx:ResUI.TbSettingsTunMode}" />
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
</Grid>
</DockPanel>
</TabItem>

View File

@@ -15,7 +15,7 @@
mc:Ignorable="d">
<DockPanel Classes="Margin8">
<StackPanel
Classes="Margin4"
Classes="Margin8"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
@@ -60,13 +60,13 @@
<TextBlock
Grid.Row="0"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbGlobalHotkeySetting}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbDisplayGUI}" />
@@ -74,68 +74,68 @@
x:Name="txtGlobalHotkey0"
Grid.Row="1"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
IsReadOnly="True" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbClearSystemProxy}" />
<TextBox
x:Name="txtGlobalHotkey1"
Grid.Row="2"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
IsReadOnly="True" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSetSystemProxy}" />
<TextBox
x:Name="txtGlobalHotkey2"
Grid.Row="3"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
IsReadOnly="True" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbNotChangeSystemProxy}" />
<TextBox
x:Name="txtGlobalHotkey3"
Grid.Row="4"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
IsReadOnly="True" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbSystemProxyPac}" />
<TextBox
x:Name="txtGlobalHotkey4"
Grid.Row="5"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
IsReadOnly="True" />
</Grid>
<TextBlock
Grid.Row="1"
Classes="Margin4"
Classes="Margin8"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbGlobalHotkeySettingTip}" />
</Grid>

View File

@@ -148,7 +148,8 @@
<ToggleSwitch
x:Name="togEnableTun"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8"
Theme="{StaticResource SimpleToggleSwitch}" />
</StackPanel>
<StackPanel

View File

@@ -20,7 +20,7 @@
Width="200"
Margin="8,0"
VerticalContentAlignment="Center"
ToolTip.Tip="{x:Static resx:ResUI.MsgFilterTitle}" />
Watermark="{x:Static resx:ResUI.MsgFilterTitle}" />
<Button
x:Name="btnCopy"
@@ -62,7 +62,8 @@
x:Name="togAutoRefresh"
Margin="8,0"
HorizontalAlignment="Left"
IsChecked="True" />
IsChecked="True"
Theme="{StaticResource SimpleToggleSwitch}" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"
@@ -71,7 +72,8 @@
x:Name="togScrollToEnd"
Margin="8,0"
HorizontalAlignment="Left"
IsChecked="True" />
IsChecked="True"
Theme="{StaticResource SimpleToggleSwitch}" />
</WrapPanel>
<TextBox
Name="txtMsg"

View File

@@ -16,7 +16,7 @@
<DockPanel Classes="Margin8">
<StackPanel
HorizontalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
@@ -113,7 +113,7 @@
<ListBox
x:Name="clbdestOverride"
HorizontalAlignment="Left"
Classes="Margin4"
Classes="Margin8"
SelectionMode="Multiple"
Theme="{DynamicResource PureCardRadioGroupListBox}" />
</StackPanel>
@@ -309,12 +309,12 @@
x:Name="txtUpMbps"
Width="90"
Classes="Margin8"
ToolTip.Tip="Up" />
Watermark="Up" />
<TextBox
x:Name="txtDownMbps"
Width="90"
Classes="Margin8"
ToolTip.Tip="Down" />
Watermark="Down" />
</StackPanel>
<TextBlock

View File

@@ -75,7 +75,7 @@
Width="200"
Margin="4,0"
VerticalContentAlignment="Center"
ToolTip.Tip="{x:Static resx:ResUI.MsgServerTitle}" />
Watermark="{x:Static resx:ResUI.MsgServerTitle}" />
</WrapPanel>
<DataGrid
x:Name="lstProfiles"

View File

@@ -32,27 +32,27 @@
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="outboundTag" />
<ComboBox
x:Name="cmbOutboundTag"
Grid.Row="0"
Grid.Column="1"
Width="200"
Classes="Margin4"
Classes="Margin8"
MaxDropDownHeight="1000" />
<TextBlock
Grid.Row="0"
Grid.Column="2"
HorizontalAlignment="Left"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="port" />
<TextBox
x:Name="txtPort"
@@ -60,29 +60,29 @@
Grid.Column="1"
Width="200"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center"
Classes="Margin4">
<Button Click="linkRuleobjectDoc_Click">
Classes="Margin8">
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
</Button>
</HyperlinkButton>
</TextBlock>
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="protocol" />
<ListBox
x:Name="clbProtocol"
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin4"
Classes="Margin8"
SelectionMode="Multiple"
Theme="{DynamicResource PureCardRadioGroupListBox}" />
@@ -90,13 +90,13 @@
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="inboundTag" />
<ListBox
x:Name="clbInboundTag"
Grid.Row="3"
Grid.Column="1"
Classes="Margin4"
Classes="Margin8"
SelectionMode="Multiple"
Theme="{DynamicResource PureCardRadioGroupListBox}" />
@@ -104,34 +104,34 @@
Grid.Row="4"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="network" />
<ComboBox
x:Name="cmbNetwork"
Grid.Row="4"
Grid.Column="1"
Width="200"
Classes="Margin4"
Classes="Margin8"
MaxDropDownHeight="1000" />
<TextBlock
Grid.Row="5"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="enabled" />
<ToggleSwitch
x:Name="togEnabled"
Grid.Row="5"
Grid.Column="1"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
Grid.Row="5"
Grid.Column="2"
HorizontalAlignment="Left"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbRoutingTips}" />
</Grid>

View File

@@ -62,7 +62,7 @@
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvRemarks}" />
<StackPanel
Grid.Row="0"
@@ -76,25 +76,25 @@
Width="300"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap" />
<TextBlock
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvSort}" />
<TextBox
x:Name="txtSort"
Width="100"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
</StackPanel>
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbdomainStrategy}" />
<StackPanel
Grid.Row="1"
@@ -103,22 +103,22 @@
<ComboBox
x:Name="cmbdomainStrategy"
Width="200"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
<ComboBox
x:Name="cmbdomainStrategy4Singbox"
Width="200"
Classes="Margin4" />
Classes="Margin8" />
</StackPanel>
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvUrl}" />
<TextBox
x:Name="txtUrl"
@@ -127,14 +127,14 @@
Width="600"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvCustomIcon}" />
<TextBox
x:Name="txtCustomIcon"
@@ -143,23 +143,23 @@
Width="600"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap" />
<Button
x:Name="btnBrowseCustomIcon"
Grid.Row="3"
Grid.Column="2"
Classes="Margin4"
Classes="Margin8"
Content="{x:Static resx:ResUI.TbBrowse}" />
<TextBlock
Grid.Row="4"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4">
<Button Click="linkCustomRulesetPath4Singbox">
Classes="Margin8">
<HyperlinkButton Classes="WithIcon" Click="linkCustomRulesetPath4Singbox">
<TextBlock Text="{x:Static resx:ResUI.LvCustomRulesetPath4Singbox}" />
</Button>
</HyperlinkButton>
</TextBlock>
<TextBox
x:Name="txtCustomRulesetPath4Singbox"
@@ -168,13 +168,13 @@
Width="600"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap" />
<Button
x:Name="btnBrowseCustomRulesetPath4Singbox"
Grid.Row="4"
Grid.Column="2"
Classes="Margin4"
Classes="Margin8"
Content="{x:Static resx:ResUI.TbBrowse}" />
</Grid>

View File

@@ -26,9 +26,9 @@
</Menu>
<TextBlock Margin="8,0,0,0" VerticalAlignment="Center">
<Button Click="linkdomainStrategy_Click">
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
</Button>
</HyperlinkButton>
</TextBlock>
<ComboBox
x:Name="cmbdomainStrategy"
@@ -45,9 +45,9 @@
Margin="8,0,0,0" />
<Separator />
<TextBlock Margin="8,0,0,0" VerticalAlignment="Center">
<Button Click="linkdomainStrategy4Singbox_Click">
<HyperlinkButton Classes="WithIcon" Click="linkdomainStrategy4Singbox_Click">
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
</Button>
</HyperlinkButton>
</TextBlock>
<ComboBox
x:Name="cmbdomainStrategy4Singbox"

View File

@@ -17,7 +17,7 @@
<DockPanel Classes="Margin8">
<StackPanel
HorizontalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
@@ -60,14 +60,14 @@
<TextBlock
Grid.Row="0"
Grid.Column="0"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.menuSubscription}" />
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvRemarks}" />
<TextBox
@@ -75,53 +75,53 @@
Grid.Row="1"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvUrl}" />
<TextBox
x:Name="txtUrl"
Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap"
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvEnabled}" />
<DockPanel
Grid.Row="3"
Grid.Column="1"
Classes="Margin4">
Classes="Margin8">
<ToggleSwitch
x:Name="togEnable"
HorizontalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Left" />
<TextBox
x:Name="txtAutoUpdateInterval"
Width="200"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
DockPanel.Dock="Right"
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
</DockPanel>
@@ -129,21 +129,21 @@
Grid.Row="5"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvFilter}" />
<TextBox
x:Name="txtFilter"
Grid.Row="5"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
Classes="Margin8"
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<TextBlock
Grid.Row="6"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvConvertTarget}" />
<ComboBox
x:Name="cmbConvertTarget"
@@ -151,29 +151,29 @@
Grid.Column="1"
Width="200"
VerticalAlignment=" "
Classes="Margin4"
Classes="Margin8"
ToolTip.Tip="{x:Static resx:ResUI.LvConvertTargetTip}" />
<TextBlock
Grid.Row="7"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvUserAgent}" />
<TextBox
x:Name="txtUserAgent"
Grid.Row="7"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
TextWrapping="Wrap"
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
<TextBlock
Grid.Row="8"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvSort}" />
<TextBox
x:Name="txtSort"
@@ -181,42 +181,42 @@
Grid.Column="1"
Width="100"
HorizontalAlignment="Left"
Classes="Margin4" />
Classes="Margin8" />
<TextBlock
Grid.Row="9"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvPrevProfile}" />
<TextBox
x:Name="txtPrevProfile"
Grid.Row="9"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
ToolTip.Tip="{x:Static resx:ResUI.LvPrevProfileTip}" />
Classes="Margin8"
Watermark="{x:Static resx:ResUI.LvPrevProfileTip}" />
<TextBlock
Grid.Row="10"
Grid.Column="0"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvNextProfile}" />
<TextBox
x:Name="txtNextProfile"
Grid.Row="10"
Grid.Column="1"
VerticalAlignment="Center"
Classes="Margin4"
ToolTip.Tip="{x:Static resx:ResUI.LvPrevProfileTip}" />
Classes="Margin8"
Watermark="{x:Static resx:ResUI.LvPrevProfileTip}" />
<TextBlock
Grid.Row="11"
Grid.Column="0"
Margin="4"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.TbPreSocksPort4Sub}" />
<TextBox
x:Name="txtPreSocksPort"
@@ -225,15 +225,16 @@
Width="200"
Margin="4"
HorizontalAlignment="Left"
Classes="Margin4"
ToolTip.Tip="{x:Static resx:ResUI.TipPreSocksPort}" />
Classes="Margin8"
ToolTip.Tip="{x:Static resx:ResUI.TipPreSocksPort}"
Watermark="{x:Static resx:ResUI.TipPreSocksPort}" />
<TextBlock
Grid.Row="12"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalAlignment="Center"
Classes="Margin4"
Classes="Margin8"
Text="{x:Static resx:ResUI.LvMoreUrl}" />
<TextBox
x:Name="txtMoreUrl"
@@ -242,10 +243,10 @@
MinHeight="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Classes="TextArea Margin4"
Classes="TextArea Margin8"
MinLines="4"
TextWrapping="Wrap"
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
</Grid>
</ScrollViewer>
</DockPanel>

View File

@@ -25,8 +25,8 @@
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.3" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.1.3" />
<PackageReference Include="MessageBox.Avalonia" Version="3.1.6" />
<PackageReference Include="Semi.Avalonia" Version="11.1.0.3" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.1.0.3" />
<PackageReference Include="Semi.Avalonia" Version="11.1.0.4" />
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.1.0.4" />
<PackageReference Include="ReactiveUI" Version="20.1.1" />
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
</ItemGroup>

View File

@@ -11,7 +11,7 @@ namespace v2rayN.Converters
try
{
var fontFamily = LazyConfig.Instance.Config.uiItem.currentFontFamily;
if (!Utils.IsNullOrEmpty(fontFamily))
if (Utils.IsNotEmpty(fontFamily))
{
var fontPath = Utils.GetFontsPath();
MyFont = new FontFamily(new Uri(@$"file:///{fontPath}\"), $"./#{fontFamily}");

View File

@@ -156,7 +156,7 @@ namespace v2rayN.ViewModels
y => y != null && !y.IsNullOrEmpty())
.Subscribe(c =>
{
if (!Utils.IsNullOrEmpty(CurrentLanguage) && _config.uiItem.currentLanguage != CurrentLanguage)
if (Utils.IsNotEmpty(CurrentLanguage) && _config.uiItem.currentLanguage != CurrentLanguage)
{
_config.uiItem.currentLanguage = CurrentLanguage;
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);

View File

@@ -1,11 +1,11 @@
<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ClashConnectionsView"
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450"
@@ -20,6 +20,15 @@
DockPanel.Dock="Top"
Orientation="Horizontal">
<TextBox
x:Name="txtHostFilter"
Width="200"
Margin="8,0"
VerticalContentAlignment="Center"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.ConnectionsHostFilterTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
Style="{StaticResource DefTextBox}" />
<TextBlock
Margin="8,0"
VerticalAlignment="Center"

View File

@@ -23,6 +23,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);