Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abdafc9b3b | ||
|
|
8f93c50151 | ||
|
|
fe7c505cc9 | ||
|
|
0d5afa4ff5 | ||
|
|
2ad716a4ad | ||
|
|
cddf88730f | ||
|
|
3eb49aa24c | ||
|
|
45c987fd86 | ||
|
|
7bec05ec23 | ||
|
|
606b216cd0 | ||
|
|
bb4f33559f | ||
|
|
c7f3e53f28 | ||
|
|
0035e836d7 |
34
.github/workflows/build-linux.yml
vendored
34
.github/workflows/build-linux.yml
vendored
@@ -99,3 +99,37 @@ jobs:
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
# release RHEL package
|
||||
- name: Package RPM (RHEL-family)
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-rhel.sh
|
||||
# Build for both x86_64 and aarch64 in one go (explicit version passed; no --buildfrom)
|
||||
./package-rhel.sh "${{ github.event.inputs.release_tag }}" --arch all
|
||||
|
||||
- name: Collect RPMs into workspace
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
mkdir -p "${{ github.workspace }}/dist/rpm"
|
||||
rsync -av "$HOME/rpmbuild/RPMS/" "${{ github.workspace }}/dist/rpm/"
|
||||
# Rename to requested filenames
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.x86_64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-x64.rpm" \; || true
|
||||
find "${{ github.workspace }}/dist/rpm" -name "v2rayN-*-1.aarch64.rpm" -exec mv {} "${{ github.workspace }}/dist/rpm/v2rayN-linux-rhel-arm64.rpm" \; || true
|
||||
|
||||
- name: Upload RPM artifacts
|
||||
if: github.event.inputs.release_tag != ''
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: v2rayN-rpm
|
||||
path: |
|
||||
${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
|
||||
- name: Upload RPMs to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
if: github.event.inputs.release_tag != ''
|
||||
with:
|
||||
file: ${{ github.workspace }}/dist/rpm/**/*.rpm
|
||||
tag: ${{ github.event.inputs.release_tag }}
|
||||
file_glob: true
|
||||
prerelease: true
|
||||
|
||||
@@ -332,6 +332,7 @@ download_xray() {
|
||||
# Download Xray core and install to outdir/xray
|
||||
local outdir="$1" ver="${XRAY_VER:-}" url tmp zipname="xray.zip"
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${XRAY_VER:-}" ]]; then ver="${XRAY_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/XTLS/Xray-core/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
@@ -353,6 +354,7 @@ download_singbox() {
|
||||
# Download sing-box core and install to outdir/sing-box
|
||||
local outdir="$1" ver="${SING_VER:-}" url tmp tarname="singbox.tar.gz" bin
|
||||
mkdir -p "$outdir"
|
||||
if [[ -n "${SING_VER:-}" ]]; then ver="${SING_VER}"; fi
|
||||
if [[ -z "$ver" ]]; then
|
||||
ver="$(curl -fsSL https://api.github.com/repos/SagerNet/sing-box/releases/latest \
|
||||
| grep -Eo '"tag_name":\s*"v[^"]+"' | sed -E 's/.*"v([^"]+)".*/\1/' | head -n1)" || true
|
||||
@@ -372,6 +374,22 @@ download_singbox() {
|
||||
install -Dm755 "$bin" "$outdir/sing-box"
|
||||
}
|
||||
|
||||
# ---- NEW: download_mihomo (REQUIRED in --netcore mode) ----
|
||||
download_mihomo() {
|
||||
# Download mihomo into outroot/bin/mihomo/mihomo
|
||||
local outroot="$1"
|
||||
local url=""
|
||||
if [[ "$RID_DIR" == "linux-arm64" ]]; then
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-arm64/bin/mihomo/mihomo"
|
||||
else
|
||||
url="https://raw.githubusercontent.com/2dust/v2rayN-core-bin/refs/heads/master/v2rayN-linux-64/bin/mihomo/mihomo"
|
||||
fi
|
||||
echo "[+] Download mihomo: $url"
|
||||
mkdir -p "$outroot/bin/mihomo"
|
||||
curl -fL "$url" -o "$outroot/bin/mihomo/mihomo"
|
||||
chmod +x "$outroot/bin/mihomo/mihomo" || true
|
||||
}
|
||||
|
||||
# Move geo files to a unified path: outroot/bin/xray/
|
||||
unify_geo_layout() {
|
||||
local outroot="$1"
|
||||
@@ -451,7 +469,8 @@ download_v2rayn_bundle() {
|
||||
fi
|
||||
|
||||
rm -f "$outroot/v2rayn.zip" 2>/dev/null || true
|
||||
find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||
# keep mihomo
|
||||
# find "$outroot" -type d -name "mihomo" -prune -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
local nested_dir
|
||||
nested_dir="$(find "$outroot" -maxdepth 1 -type d -name 'v2rayN-linux-*' | head -n1 || true)"
|
||||
@@ -561,6 +580,8 @@ build_for_arch() {
|
||||
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
||||
fi
|
||||
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
||||
# ---- REQUIRED: always fetch mihomo in netcore mode, per-arch ----
|
||||
download_mihomo "$WORKDIR/$PKGROOT" || echo "[!] mihomo download failed (skipped)"
|
||||
fi
|
||||
|
||||
# Tarball
|
||||
@@ -583,6 +604,7 @@ Release: 1%{?dist}
|
||||
Summary: v2rayN (Avalonia) GUI client for Linux (x86_64/aarch64)
|
||||
License: GPL-3.0-only
|
||||
URL: https://github.com/2dust/v2rayN
|
||||
BugURL: https://github.com/2dust/v2rayN/issues
|
||||
ExclusiveArch: aarch64 x86_64
|
||||
Source0: __PKGROOT__.tar.gz
|
||||
|
||||
@@ -591,10 +613,11 @@ Requires: libX11, libXrandr, libXcursor, libXi, libXext, libxcb, libXrende
|
||||
Requires: fontconfig, freetype, cairo, pango, mesa-libEGL, mesa-libGL
|
||||
|
||||
%description
|
||||
v2rayN GUI client built with Avalonia.
|
||||
Installs self-contained publish under /opt/v2rayN and a launcher 'v2rayn'.
|
||||
Cores (if bundled): /opt/v2rayN/bin/xray, /opt/v2rayN/bin/sing_box.
|
||||
Geo files for Xray are placed at /opt/v2rayN/bin/xray; launcher will symlink them into user's XDG data dir on first run.
|
||||
v2rayN Linux for Red Hat Enterprise Linux
|
||||
Support vless / vmess / Trojan / http / socks / Anytls / Hysteria2 / Shadowsocks / tuic / WireGuard
|
||||
Support Red Hat Enterprise Linux / Fedora Linux / Rocky Linux / AlmaLinux / CentOS
|
||||
For more information, Please visit our website
|
||||
https://github.com/2dust/v2rayN
|
||||
|
||||
%prep
|
||||
%setup -q -n __PKGROOT__
|
||||
@@ -645,7 +668,7 @@ cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF'
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=v2rayN
|
||||
Comment=GUI client for Xray / sing-box
|
||||
Comment=v2rayN for Red Hat Enterprise Linux
|
||||
Exec=v2rayn
|
||||
Icon=v2rayn
|
||||
Terminal=false
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.14.2</Version>
|
||||
<Version>7.14.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -15,5 +15,6 @@ public enum ECoreType
|
||||
brook = 27,
|
||||
overtls = 28,
|
||||
shadowquic = 29,
|
||||
mieru = 30,
|
||||
v2rayN = 99
|
||||
}
|
||||
|
||||
@@ -560,6 +560,7 @@ public class Global
|
||||
{ ECoreType.brook, "txthinking/brook" },
|
||||
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
||||
{ ECoreType.shadowquic, "spongebob888/shadowquic" },
|
||||
{ ECoreType.mieru, "enfein/mieru" },
|
||||
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace ServiceLib.Handler.Fmt;
|
||||
|
||||
public class HtmlPageFmt : BaseFmt
|
||||
|
||||
@@ -197,6 +197,8 @@ public static class SubscriptionHandler
|
||||
updateFunc?.Invoke(false, $"{hashCode}{result}");
|
||||
}
|
||||
|
||||
updateFunc?.Invoke(false, $"{hashCode}{ResUI.MsgStartParsingSubscription}");
|
||||
|
||||
// Add servers to configuration
|
||||
var ret = await ConfigHandler.AddBatchServers(config, result, id, true);
|
||||
if (ret <= 0)
|
||||
|
||||
@@ -26,7 +26,7 @@ public sealed class SQLiteHelper
|
||||
|
||||
public async Task<int> InsertAllAsync(IEnumerable models)
|
||||
{
|
||||
return await _dbAsync.InsertAllAsync(models);
|
||||
return await _dbAsync.InsertAllAsync(models, runInTransaction: true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<int> InsertAsync(object model)
|
||||
@@ -46,7 +46,7 @@ public sealed class SQLiteHelper
|
||||
|
||||
public async Task<int> UpdateAllAsync(IEnumerable models)
|
||||
{
|
||||
return await _dbAsync.UpdateAllAsync(models);
|
||||
return await _dbAsync.UpdateAllAsync(models, runInTransaction: true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<int> DeleteAsync(object model)
|
||||
|
||||
@@ -80,6 +80,10 @@ public sealed class CoreInfoManager
|
||||
Url = GetCoreUrl(ECoreType.v2fly),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "-version",
|
||||
Environment = new Dictionary<string, string?>()
|
||||
{
|
||||
{ Global.V2RayLocalAsset, Utils.GetBinPath("") },
|
||||
},
|
||||
},
|
||||
|
||||
new CoreInfo
|
||||
@@ -90,6 +94,10 @@ public sealed class CoreInfoManager
|
||||
Url = GetCoreUrl(ECoreType.v2fly_v5),
|
||||
Match = "V2Ray",
|
||||
VersionArg = "version",
|
||||
Environment = new Dictionary<string, string?>()
|
||||
{
|
||||
{ Global.V2RayLocalAsset, Utils.GetBinPath("") },
|
||||
},
|
||||
},
|
||||
|
||||
new CoreInfo
|
||||
@@ -107,6 +115,11 @@ public sealed class CoreInfoManager
|
||||
DownloadUrlOSXArm64 = urlXray + "/download/{0}/Xray-macos-arm64-v8a.zip",
|
||||
Match = "Xray",
|
||||
VersionArg = "-version",
|
||||
Environment = new Dictionary<string, string?>()
|
||||
{
|
||||
{ Global.XrayLocalAsset, Utils.GetBinPath("") },
|
||||
{ Global.XrayLocalCert, Utils.GetBinPath("") },
|
||||
},
|
||||
},
|
||||
|
||||
new CoreInfo
|
||||
@@ -205,12 +218,24 @@ public sealed class CoreInfoManager
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.shadowquic,
|
||||
CoreExes = [ "shadowquic", "shadowquic"],
|
||||
CoreExes = [ "shadowquic" ],
|
||||
Arguments = "-c {0}",
|
||||
Url = GetCoreUrl(ECoreType.shadowquic),
|
||||
AbsolutePath = false,
|
||||
}
|
||||
},
|
||||
|
||||
new CoreInfo
|
||||
{
|
||||
CoreType = ECoreType.mieru,
|
||||
CoreExes = [ "mieru" ],
|
||||
Arguments = "run",
|
||||
Url = GetCoreUrl(ECoreType.mieru),
|
||||
AbsolutePath = false,
|
||||
Environment = new Dictionary<string, string?>()
|
||||
{
|
||||
{ "MIERU_CONFIG_JSON_FILE", "{0}" },
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,6 @@ public class CoreManager
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.XrayLocalCert, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
|
||||
//Copy the bin folder to the storage location (for init)
|
||||
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||
{
|
||||
@@ -277,6 +273,10 @@ public class CoreManager
|
||||
StandardErrorEncoding = displayLog ? Encoding.UTF8 : null,
|
||||
}
|
||||
};
|
||||
foreach (var kv in coreInfo.Environment)
|
||||
{
|
||||
proc.StartInfo.Environment[kv.Key] = string.Format(kv.Value, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath);
|
||||
}
|
||||
|
||||
if (displayLog)
|
||||
{
|
||||
|
||||
@@ -17,4 +17,5 @@ public class CoreInfo
|
||||
public string? Match { get; set; }
|
||||
public string? VersionArg { get; set; }
|
||||
public bool AbsolutePath { get; set; }
|
||||
public IDictionary<string, string?> Environment { get; set; } = new Dictionary<string, string?>();
|
||||
}
|
||||
|
||||
61
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
61
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -1860,6 +1860,15 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Start parsing and processing subscription content 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string MsgStartParsingSubscription {
|
||||
get {
|
||||
return ResourceManager.GetString("MsgStartParsingSubscription", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Started updating {0}... 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3736,28 +3745,9 @@ namespace ServiceLib.Resx {
|
||||
/// 查找类似 Auto Route 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunAutoRoute {
|
||||
get { return ResourceManager.GetString("TbSettingsTunAutoRoute", resourceCulture); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Strict Route 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunStrictRoute {
|
||||
get { return ResourceManager.GetString("TbSettingsTunStrictRoute", resourceCulture); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Stack 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunStack {
|
||||
get { return ResourceManager.GetString("TbSettingsTunStack", resourceCulture); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 MTU 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunMtu {
|
||||
get { return ResourceManager.GetString("TbSettingsTunMtu", resourceCulture); }
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunAutoRoute", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -3769,6 +3759,33 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 MTU 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunMtu {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunMtu", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Stack 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunStack {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunStack", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Strict Route 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsTunStrictRoute {
|
||||
get {
|
||||
return ResourceManager.GetString("TbSettingsTunStrictRoute", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Enable UDP 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -1509,4 +1509,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>Start parsing and processing subscription content</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1509,4 +1509,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>Start parsing and processing subscription content</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1509,4 +1509,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>Start parsing and processing subscription content</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1509,4 +1509,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>Эта функция предназначена для продвинутых пользователей и особых случаев. После включения игнорируются базовые настройки ядра, DNS и маршрутизации. Вы должны самостоятельно корректно задать порт системного прокси, учёт трафика и другие связанные параметры — всё настраивается вручную.</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>Start parsing and processing subscription content</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1506,4 +1506,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>此功能供高级用户和有特殊需求的用户使用。 启用此功能后,将忽略 Core 的基础设置,DNS 设置 ,路由设置。你需要保证系统代理的端口和流量统计等功能的配置正确,一切都由你来设置。</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>开始解析和处理订阅内容</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1506,4 +1506,7 @@
|
||||
<data name="TbFullConfigTemplateDesc" xml:space="preserve">
|
||||
<value>This feature is intended for advanced users and those with special requirements. Once enabled, it will ignore the Core's basic settings, DNS settings, and routing settings. You must ensure that the system proxy port, traffic statistics, and other related configurations are set correctly — everything will be configured by you.</value>
|
||||
</data>
|
||||
<data name="MsgStartParsingSubscription" xml:space="preserve">
|
||||
<value>開始解析和處理訂閱內容</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -80,25 +80,31 @@ public partial class CoreConfigSingboxService
|
||||
hostsDns.predefined = Global.PredefinedHosts;
|
||||
}
|
||||
|
||||
if (simpleDNSItem.UseSystemHosts == true)
|
||||
{
|
||||
var systemHosts = Utils.GetSystemHosts();
|
||||
if (systemHosts != null && systemHosts.Count > 0)
|
||||
{
|
||||
foreach (var host in systemHosts)
|
||||
{
|
||||
hostsDns.predefined.TryAdd(host.Key, new List<string> { host.Value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||
{
|
||||
var userHostsMap = simpleDNSItem.Hosts?
|
||||
var userHostsMap = simpleDNSItem.Hosts
|
||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Where(line => line.Contains(' '))
|
||||
.Select(line => line.Trim())
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(' '))
|
||||
.Select(line => line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
.Where(parts => parts.Length >= 2)
|
||||
.GroupBy(parts => parts[0])
|
||||
.ToDictionary(
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return parts[0];
|
||||
},
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var values = parts.Skip(1).ToList();
|
||||
return values;
|
||||
}
|
||||
) ?? new Dictionary<string, List<string>>();
|
||||
group => group.Key,
|
||||
group => group.SelectMany(parts => parts.Skip(1)).ToList()
|
||||
);
|
||||
|
||||
foreach (var kvp in userHostsMap)
|
||||
{
|
||||
@@ -106,22 +112,6 @@ public partial class CoreConfigSingboxService
|
||||
}
|
||||
}
|
||||
|
||||
if (simpleDNSItem.UseSystemHosts == true)
|
||||
{
|
||||
var systemHosts = Utils.GetSystemHosts();
|
||||
if (systemHosts.Count > 0)
|
||||
{
|
||||
foreach (var host in systemHosts)
|
||||
{
|
||||
if (hostsDns.predefined[host.Key] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
hostsDns.predefined[host.Key] = new List<string> { host.Value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var host in hostsDns.predefined)
|
||||
{
|
||||
if (finalDns.server == host.Key)
|
||||
|
||||
@@ -10,7 +10,7 @@ public partial class CoreConfigSingboxService
|
||||
singboxConfig.inbounds = [];
|
||||
|
||||
if (!_config.TunModeItem.EnableTun
|
||||
|| _config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box)
|
||||
|| (_config.TunModeItem.EnableTun && _config.TunModeItem.EnableExInbound && _config.RunningCoreType == ECoreType.sing_box))
|
||||
{
|
||||
var inbound = new Inbound4Sbox()
|
||||
{
|
||||
@@ -78,7 +78,7 @@ public partial class CoreConfigSingboxService
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
}
|
||||
return 0;
|
||||
return await Task.FromResult(0);
|
||||
}
|
||||
|
||||
private Inbound4Sbox GetInbound(Inbound4Sbox inItem, EInboundProtocol protocol, bool bSocks)
|
||||
|
||||
@@ -248,43 +248,31 @@ public partial class CoreConfigV2rayService
|
||||
if (simpleDNSItem.UseSystemHosts == true)
|
||||
{
|
||||
var systemHosts = Utils.GetSystemHosts();
|
||||
if (systemHosts.Count > 0)
|
||||
var normalHost = v2rayConfig?.dns?.hosts;
|
||||
|
||||
if (normalHost != null && systemHosts?.Count > 0)
|
||||
{
|
||||
var normalHost = v2rayConfig.dns.hosts;
|
||||
if (normalHost != null)
|
||||
foreach (var host in systemHosts)
|
||||
{
|
||||
foreach (var host in systemHosts)
|
||||
{
|
||||
if (normalHost[host.Key] != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
normalHost[host.Key] = new List<string> { host.Value };
|
||||
}
|
||||
normalHost.TryAdd(host.Key, new List<string> { host.Value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var userHostsMap = simpleDNSItem.Hosts?
|
||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line))
|
||||
.Where(line => line.Contains(' '))
|
||||
.ToDictionary(
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return parts[0];
|
||||
},
|
||||
line =>
|
||||
{
|
||||
var parts = line.Trim().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var values = parts.Skip(1).ToList();
|
||||
return values;
|
||||
}
|
||||
);
|
||||
|
||||
if (userHostsMap != null)
|
||||
if (!simpleDNSItem.Hosts.IsNullOrEmpty())
|
||||
{
|
||||
var userHostsMap = simpleDNSItem.Hosts
|
||||
.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(line => line.Trim())
|
||||
.Where(line => !string.IsNullOrWhiteSpace(line) && line.Contains(' '))
|
||||
.Select(line => line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
.Where(parts => parts.Length >= 2)
|
||||
.GroupBy(parts => parts[0])
|
||||
.ToDictionary(
|
||||
group => group.Key,
|
||||
group => group.SelectMany(parts => parts.Skip(1)).ToList()
|
||||
);
|
||||
|
||||
foreach (var kvp in userHostsMap)
|
||||
{
|
||||
v2rayConfig.dns.hosts[kvp.Key] = kvp.Value;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Sockets;
|
||||
|
||||
@@ -477,7 +477,7 @@ public class MainWindowViewModel : MyReactiveObject
|
||||
|
||||
public async Task UpdateSubscriptionProcess(string subId, bool blProxy)
|
||||
{
|
||||
await SubscriptionHandler.UpdateProcess(_config, subId, blProxy, UpdateTaskHandler);
|
||||
await Task.Run(async () => await SubscriptionHandler.UpdateProcess(_config, subId, blProxy, UpdateTaskHandler));
|
||||
}
|
||||
|
||||
#endregion Subscription
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<x:Double x:Key="IconButtonWidth">32</x:Double>
|
||||
<x:Double x:Key="IconButtonHeight">32</x:Double>
|
||||
<x:Double x:Key="MenuFlyoutMaxHeight">1000</x:Double>
|
||||
|
||||
<Thickness x:Key="Margin2">2</Thickness>
|
||||
<Thickness x:Key="MarginLr4">4,0</Thickness>
|
||||
|
||||
@@ -23,14 +23,12 @@
|
||||
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>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
|
||||
@@ -23,14 +23,12 @@
|
||||
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>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
|
||||
@@ -24,14 +24,12 @@
|
||||
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>
|
||||
|
||||
@@ -331,8 +329,7 @@
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4V2rayCompatible"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -415,8 +412,7 @@
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4SingboxCompatible"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||
InitializeComponent();
|
||||
|
||||
_config = AppManager.Instance.Config;
|
||||
Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||
|
||||
@@ -100,4 +101,9 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
||||
{
|
||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
}
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
btnCancel.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,14 +23,12 @@
|
||||
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>
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
||||
InitializeComponent();
|
||||
|
||||
_config = AppManager.Instance.Config;
|
||||
Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
ViewModel = new FullConfigTemplateViewModel(UpdateViewHandler);
|
||||
|
||||
@@ -49,4 +50,8 @@ public partial class FullConfigTemplateWindow : WindowBase<FullConfigTemplateVie
|
||||
{
|
||||
ProcUtils.ProcessStart("https://github.com/2dust/v2rayN/wiki/Description-of-some-ui#%E5%AE%8C%E6%95%B4%E9%85%8D%E7%BD%AE%E6%A8%A1%E6%9D%BF%E8%AE%BE%E7%BD%AE");
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
btnCancel.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,14 +28,12 @@
|
||||
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>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
|
||||
@@ -22,6 +22,7 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
||||
btnReset.Click += btnReset_Click;
|
||||
|
||||
HotkeyManager.Instance.IsPause = true;
|
||||
Loaded += Window_Loaded;
|
||||
this.Closing += (s, e) => HotkeyManager.Instance.IsPause = false;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
|
||||
@@ -134,4 +135,8 @@ public partial class GlobalHotkeySettingWindow : WindowBase<GlobalHotkeySettingV
|
||||
|
||||
return res.ToString();
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
btnCancel.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@
|
||||
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>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Reactive.Disposables;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using ReactiveUI;
|
||||
using ServiceLib.Manager;
|
||||
using v2rayN.Desktop.Base;
|
||||
@@ -14,6 +15,7 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = AppManager.Instance.Config;
|
||||
|
||||
@@ -209,4 +211,8 @@ public partial class OptionSettingWindow : WindowBase<OptionSettingViewModel>
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
btnCancel.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,14 +167,12 @@
|
||||
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>
|
||||
|
||||
|
||||
@@ -27,22 +27,20 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Right"
|
||||
DockPanel.Dock="Bottom"
|
||||
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>
|
||||
|
||||
@@ -54,8 +52,8 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
@@ -67,27 +65,27 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
@@ -98,8 +96,8 @@
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Singbox"
|
||||
@@ -110,17 +108,17 @@
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.LvUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtUrl"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!--
|
||||
@@ -150,8 +148,8 @@
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}">
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center">
|
||||
<HyperlinkButton Classes="WithIcon" Click="linkCustomRulesetPath4Singbox">
|
||||
<TextBlock Text="{x:Static resx:ResUI.LvCustomRulesetPath4Singbox}" />
|
||||
</HyperlinkButton>
|
||||
@@ -161,9 +159,9 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowseCustomRulesetPath4Singbox"
|
||||
|
||||
@@ -35,14 +35,12 @@
|
||||
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>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += Window_Loaded;
|
||||
this.Closing += RoutingSettingWindow_Closing;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
this.KeyDown += RoutingSettingWindow_KeyDown;
|
||||
@@ -134,4 +135,8 @@ public partial class RoutingSettingWindow : WindowBase<RoutingSettingViewModel>
|
||||
}
|
||||
}
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
btnCancel.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,12 @@
|
||||
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>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Reactive.Disposables;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using DialogHostAvalonia;
|
||||
using DynamicData;
|
||||
@@ -19,7 +20,9 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||
InitializeComponent();
|
||||
|
||||
menuClose.Click += menuClose_Click;
|
||||
Loaded += Window_Loaded;
|
||||
this.Closing += SubSettingWindow_Closing;
|
||||
this.KeyDown += SubSettingWindow_KeyDown;
|
||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||
@@ -106,4 +109,16 @@ public partial class SubSettingWindow : WindowBase<SubSettingViewModel>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SubSettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape)
|
||||
{
|
||||
menuClose_Click(null, null);
|
||||
}
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
lstSubscription.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@
|
||||
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>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows.Media.Imaging;
|
||||
using v2rayN.Manager;
|
||||
|
||||
namespace v2rayN.Manager;
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -35,7 +34,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -43,7 +42,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -35,7 +34,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
@@ -396,7 +394,6 @@
|
||||
x:Name="btnImportDefConfig4V2rayCompatible"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -489,7 +486,6 @@
|
||||
x:Name="btnImportDefConfig4SingboxCompatible"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -35,7 +34,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -41,7 +40,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -35,7 +34,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -198,7 +198,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -206,7 +205,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -84,7 +83,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -61,7 +61,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -69,7 +68,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand"
|
||||
IsDefault="True"
|
||||
Style="{StaticResource DefButton}" />
|
||||
<Button
|
||||
@@ -42,7 +41,6 @@
|
||||
Width="100"
|
||||
Margin="{StaticResource MarginLeftRight8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="true"
|
||||
Style="{StaticResource DefButton}" />
|
||||
</StackPanel>
|
||||
|
||||
Reference in New Issue
Block a user