Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
438eaba4d5 | ||
|
|
3c8baa99d5 | ||
|
|
e70658f311 | ||
|
|
2dd10cf5a1 | ||
|
|
96781a784b | ||
|
|
9748fbb076 | ||
|
|
aa5e4378ab | ||
|
|
a7de149fd7 | ||
|
|
ae38be36f5 | ||
|
|
a20e989211 | ||
|
|
579f47ba0d | ||
|
|
24cad87954 | ||
|
|
84d72cd110 | ||
|
|
c0cd46a5aa | ||
|
|
98613c43ca | ||
|
|
555960e210 | ||
|
|
a18ae5582b | ||
|
|
6d6894591c | ||
|
|
984b97fc14 | ||
|
|
a7f35d4495 | ||
|
|
add92cfa7c | ||
|
|
6079e76be5 | ||
|
|
166c7cb2f5 | ||
|
|
dbd3ca44c2 | ||
|
|
ae495dde54 | ||
|
|
4ae25b2f34 | ||
|
|
cdfb621c59 | ||
|
|
29e8df7d2e | ||
|
|
72ff947d95 | ||
|
|
3edaac5739 | ||
|
|
5777a97119 | ||
|
|
aeddbc1dcc | ||
|
|
2f3e409487 | ||
|
|
aa133bb50b | ||
|
|
3bc79a4ba1 | ||
|
|
064a04fbad | ||
|
|
39ed13cf8a | ||
|
|
a1edacb196 | ||
|
|
c9f79e4b47 | ||
|
|
40c1498226 | ||
|
|
390061f9bd | ||
|
|
42324a2c9e | ||
|
|
b9b4ca6360 | ||
|
|
565697bc0b | ||
|
|
2e6c82c851 | ||
|
|
ee75dd37af | ||
|
|
4859dcda08 | ||
|
|
2e962e555d | ||
|
|
ab73e5acb2 | ||
|
|
4e3e5ce130 | ||
|
|
bb8eef3bf5 | ||
|
|
eee87ded29 |
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -3,6 +3,13 @@ description: 在提出问题前请先自行排除服务器端问题和升级到
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: input
|
||||
id: "os-version"
|
||||
attributes:
|
||||
label: "操作系统和版本"
|
||||
description: "操作系统和版本"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: "expectation"
|
||||
attributes:
|
||||
|
||||
69
.github/workflows/build-all.yml
vendored
Normal file
69
.github/workflows/build-all.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
name: release all platforms
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Trigger build windows
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows.yml/dispatches \
|
||||
-d "{
|
||||
\"ref\": \"master\",
|
||||
\"inputs\": {
|
||||
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||
}
|
||||
}"
|
||||
|
||||
- name: Trigger build linux
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-linux.yml/dispatches \
|
||||
-d "{
|
||||
\"ref\": \"master\",
|
||||
\"inputs\": {
|
||||
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||
}
|
||||
}"
|
||||
|
||||
- name: Trigger build osx
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-osx.yml/dispatches \
|
||||
-d "{
|
||||
\"ref\": \"master\",
|
||||
\"inputs\": {
|
||||
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||
}
|
||||
}"
|
||||
|
||||
- name: Trigger build windows desktop
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows-desktop.yml/dispatches \
|
||||
-d "{
|
||||
\"ref\": \"master\",
|
||||
\"inputs\": {
|
||||
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||
}
|
||||
}"
|
||||
10
.github/workflows/build-linux.yml
vendored
10
.github/workflows/build-linux.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Setup
|
||||
uses: actions/setup-dotnet@v4.3.0
|
||||
@@ -42,7 +45,7 @@ jobs:
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: v2rayN-linux
|
||||
path: |
|
||||
@@ -68,9 +71,8 @@ jobs:
|
||||
- name: Package AppImage
|
||||
if: github.event.inputs.release_tag != ''
|
||||
run: |
|
||||
chmod 755 package-appimage.sh
|
||||
./package-appimage.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||
./package-appimage.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||
chmod a+x package-appimage.sh
|
||||
./package-appimage.sh
|
||||
|
||||
- name: Upload AppImage to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
|
||||
5
.github/workflows/build-osx.yml
vendored
5
.github/workflows/build-osx.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Setup
|
||||
uses: actions/setup-dotnet@v4.3.0
|
||||
@@ -42,7 +45,7 @@ jobs:
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: v2rayN-macos
|
||||
path: |
|
||||
|
||||
5
.github/workflows/build-windows-desktop.yml
vendored
5
.github/workflows/build-windows-desktop.yml
vendored
@@ -27,6 +27,9 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.2.2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
fetch-depth: '0'
|
||||
|
||||
- name: Setup
|
||||
uses: actions/setup-dotnet@v4.3.0
|
||||
@@ -42,7 +45,7 @@ jobs:
|
||||
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: v2rayN-windows-desktop
|
||||
path: |
|
||||
|
||||
2
.github/workflows/build-windows.yml
vendored
2
.github/workflows/build-windows.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4.6.0
|
||||
uses: actions/upload-artifact@v4.6.1
|
||||
with:
|
||||
name: v2rayN-windows
|
||||
path: |
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "v2rayN/GlobalHotKeys"]
|
||||
path = v2rayN/GlobalHotKeys
|
||||
url = https://github.com/2dust/GlobalHotKeys
|
||||
@@ -1,71 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
Arch="$1"
|
||||
OutputPath="$2"
|
||||
Version="$3"
|
||||
|
||||
FileName="v2rayN-${Arch}.zip"
|
||||
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||
7z x $FileName -aoa
|
||||
cp -rf v2rayN-${Arch}/* $OutputPath
|
||||
|
||||
PackagePath="v2rayN-Package-${Arch}"
|
||||
mkdir -p "${PackagePath}/AppDir/opt"
|
||||
cp -rf $OutputPath "${PackagePath}/AppDir/opt/v2rayN"
|
||||
echo "When this file exists, app will not store configs under this folder" >"${PackagePath}/AppDir/opt/v2rayN/NotStoreConfigHere.txt"
|
||||
|
||||
if [ $Arch = "linux-64" ]; then
|
||||
Arch2="x86_64"
|
||||
Arch3="amd64"
|
||||
else
|
||||
Arch2="aarch64"
|
||||
Arch3="arm64"
|
||||
fi
|
||||
echo $Arch2
|
||||
|
||||
# basic
|
||||
cat >"${PackagePath}/AppDir/AppRun" <<-EOF
|
||||
#!/bin/sh
|
||||
HERE="\$(dirname "\$(readlink -f "\${0}")")"
|
||||
export PATH="\${HERE}"/opt/v2rayN/:"\${PATH}"
|
||||
export LD_LIBRARY_PATH="\${HERE}"/opt/v2rayN/:"\${LD_LIBRARY_PATH}"
|
||||
exec "\${HERE}/opt/v2rayN/v2rayN" \$@
|
||||
EOF
|
||||
|
||||
cat >"${PackagePath}/AppDir/v2rayN.desktop" <<-EOF
|
||||
[Desktop Entry]
|
||||
Name=v2rayN
|
||||
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
Exec=v2rayN
|
||||
Icon=v2rayN
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;
|
||||
EOF
|
||||
|
||||
sudo cp "${PackagePath}/AppDir/opt/v2rayN/v2rayN.png" "${PackagePath}/AppDir/v2rayN.png"
|
||||
sudo dpkg --add-architecture ${Arch3}
|
||||
mkdir deb_folder
|
||||
cd deb_folder
|
||||
apt download libicu74:${Arch3}
|
||||
apt download libfontconfig1:${Arch3} || true
|
||||
apt download libfontconfig:${Arch3} || true
|
||||
mkdir ../output_folder
|
||||
for deb in *.deb; do
|
||||
dpkg-deb -x "$deb" ../output_folder/
|
||||
done
|
||||
cd ..
|
||||
find output_folder -type f -name "*.so*" -exec cp {} ${PackagePath}/AppDir/opt/v2rayN/ \;
|
||||
find output_folder -type l -name "*.so*" -exec cp {} ${PackagePath}/AppDir/opt/v2rayN/ \;
|
||||
rm -rf deb_folder output_folder
|
||||
|
||||
sudo chmod 0755 "${PackagePath}/AppDir/opt/v2rayN/v2rayN"
|
||||
sudo chmod 0755 "${PackagePath}/AppDir/AppRun"
|
||||
|
||||
# desktop && PATH
|
||||
|
||||
wget "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod a+x appimagetool-x86_64.AppImage
|
||||
sudo apt update -y
|
||||
sudo apt install -y libfuse2
|
||||
sudo ./appimagetool-x86_64.AppImage "${PackagePath}/AppDir"
|
||||
sudo mv "v2rayN-${Arch2}.AppImage" "v2rayN-${Arch}.AppImage"
|
||||
wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage
|
||||
chmod a+x pkg2appimage
|
||||
export AppImageOutputArch=$OutputArch
|
||||
export OutputPath=$OutputPath64
|
||||
./pkg2appimage ./pkg2appimage.yml
|
||||
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||
export AppImageOutputArch=$OutputArchArm
|
||||
export OutputPath=$OutputPathArm64
|
||||
./pkg2appimage ./pkg2appimage.yml
|
||||
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||
|
||||
37
pkg2appimage.yml
Normal file
37
pkg2appimage.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
app: v2rayN
|
||||
binpatch: true
|
||||
|
||||
ingredients:
|
||||
script:
|
||||
- export FileName="v2rayN-${AppImageOutputArch}.zip"
|
||||
- wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/${FileName}"
|
||||
- 7z x $FileName -aoa
|
||||
- cp -rf v2rayN-${AppImageOutputArch}/* $OutputPath
|
||||
|
||||
script:
|
||||
- mkdir -p usr/bin usr/lib
|
||||
- cp -rf $OutputPath usr/lib/v2rayN
|
||||
- echo "When this file exists, app will not store configs under this folder" > usr/lib/v2rayN/NotStoreConfigHere.txt
|
||||
- ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN
|
||||
- chmod a+x usr/lib/v2rayN/v2rayN
|
||||
- find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \;
|
||||
- install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png
|
||||
- install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png
|
||||
- cat > v2rayN.desktop <<EOF
|
||||
- [Desktop Entry]
|
||||
- Name=v2rayN
|
||||
- Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||
- Exec=v2rayN
|
||||
- Icon=v2rayN
|
||||
- Terminal=false
|
||||
- Type=Application
|
||||
- Categories=Network;
|
||||
- EOF
|
||||
- install -Dm644 v2rayN.desktop usr/share/applications/v2rayN.desktop
|
||||
- cat > AppRun <<\EOF
|
||||
- #!/bin/sh
|
||||
- HERE="$(dirname "$(readlink -f "${0}")")"
|
||||
- cd ${HERE}/usr/lib/v2rayN
|
||||
- exec ${HERE}/usr/lib/v2rayN/v2rayN $@
|
||||
- EOF
|
||||
- chmod a+x AppRun
|
||||
@@ -1,29 +1,39 @@
|
||||
namespace AmazTool
|
||||
namespace AmazTool
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.Guidelines);
|
||||
Thread.Sleep(5000);
|
||||
Utils.WriteLine(Resx.Resource.Guidelines);
|
||||
Utils.Waiting(5);
|
||||
return;
|
||||
}
|
||||
|
||||
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||
if (argData.Equals("rebootas"))
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
Utils.Waiting(1);
|
||||
Utils.StartV2RayN();
|
||||
return;
|
||||
}
|
||||
|
||||
var tryTimes = 0;
|
||||
UpgradeApp.Init();
|
||||
while (tryTimes++ < 3)
|
||||
{
|
||||
if (!UpgradeApp.Upgrade(argData))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UpgradeApp.Upgrade(argData);
|
||||
Utils.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Utils.Waiting(3);
|
||||
Utils.StartV2RayN();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,99 @@ namespace AmazTool
|
||||
{
|
||||
internal class UpgradeApp
|
||||
{
|
||||
public static void Upgrade(string fileName)
|
||||
public static bool Upgrade(string fileName)
|
||||
{
|
||||
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||
|
||||
Utils.Waiting(5);
|
||||
Utils.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||
return;
|
||||
Utils.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||
Utils.Waiting(5);
|
||||
|
||||
KillV2rayN();
|
||||
|
||||
Utils.WriteLine(Resx.Resource.StartUnzipping);
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
{
|
||||
var splitKey = "/";
|
||||
|
||||
using var archive = ZipFile.OpenRead(fileName);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Utils.WriteLine(entry.FullName);
|
||||
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
var entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
//In the bin folder, if the file already exists, it will be skipped
|
||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
Utils.WriteLine(entryOutputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(ex.Message);
|
||||
sb.Append(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||
}
|
||||
|
||||
if (sb.Length <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Utils.WriteLine(sb.ToString());
|
||||
Utils.WriteLine(Resx.Resource.FailedUpgrade);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Init()
|
||||
{
|
||||
//Process temporary files generated by the last update
|
||||
var files = Directory.GetFiles(Utils.GetPath(""), "*.tmp");
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.Contains(Utils.AmazTool))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
var destFileName = $"{Utils.GetExePath()}{Guid.NewGuid().ToString("N")[..8]}.tmp";
|
||||
File.Move(Utils.GetExePath(), destFileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool KillV2rayN()
|
||||
{
|
||||
Utils.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||
try
|
||||
{
|
||||
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
||||
@@ -35,71 +115,10 @@ namespace AmazTool
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Access may be denied without admin right. The user may not be an administrator.
|
||||
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||
Utils.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.StartUnzipping);
|
||||
StringBuilder sb = new();
|
||||
try
|
||||
{
|
||||
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||
File.Delete(thisAppOldFile);
|
||||
var splitKey = "/";
|
||||
|
||||
using var archive = ZipFile.OpenRead(fileName);
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine(entry.FullName);
|
||||
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1)
|
||||
continue;
|
||||
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
|
||||
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.Move(Utils.GetExePath(), thisAppOldFile);
|
||||
}
|
||||
|
||||
var entryOutputPath = Utils.GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
//In the bin folder, if the file already exists, it will be skipped
|
||||
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
Console.WriteLine(entryOutputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sb.Append(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||
//return;
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
|
||||
//return;
|
||||
}
|
||||
|
||||
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||
Utils.Waiting(2);
|
||||
|
||||
Utils.StartV2RayN();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AmazTool
|
||||
{
|
||||
@@ -14,9 +14,9 @@ namespace AmazTool
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
public static string GetPath(string fileName)
|
||||
public static string GetPath(string? fileName)
|
||||
{
|
||||
string startupPath = StartupPath();
|
||||
var startupPath = StartupPath();
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return startupPath;
|
||||
@@ -25,6 +25,7 @@ namespace AmazTool
|
||||
}
|
||||
|
||||
public static string V2rayN => "v2rayN";
|
||||
public static string AmazTool => "AmazTool";
|
||||
|
||||
public static void StartV2RayN()
|
||||
{
|
||||
@@ -44,9 +45,14 @@ namespace AmazTool
|
||||
{
|
||||
for (var i = second; i > 0; i--)
|
||||
{
|
||||
Console.WriteLine(i);
|
||||
Utils.WriteLine(i);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteLine(object obj)
|
||||
{
|
||||
Console.WriteLine(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.9.1</Version>
|
||||
<Version>7.10.1</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.4" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" />
|
||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" />
|
||||
<PackageVersion Include="CliWrap" Version="3.8.0" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.5" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.5" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.5" />
|
||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.5" />
|
||||
<PackageVersion Include="CliWrap" Version="3.8.1" />
|
||||
<PackageVersion Include="Downloader" Version="3.3.3" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" />
|
||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
||||
<PackageVersion Include="ReactiveUI" Version="20.1.63" />
|
||||
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
<PackageVersion Include="ReactiveUI.WPF" Version="20.1.63" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.4" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.4" />
|
||||
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.5" />
|
||||
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.5" />
|
||||
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
||||
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.11.0" />
|
||||
<PackageVersion Include="TaskScheduler" Version="2.12.0" />
|
||||
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
|
||||
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||
|
||||
1
v2rayN/GlobalHotKeys
Submodule
1
v2rayN/GlobalHotKeys
Submodule
Submodule v2rayN/GlobalHotKeys added at b3b635ef46
@@ -20,9 +20,13 @@ public static class ProcUtils
|
||||
try
|
||||
{
|
||||
if (fileName.Contains(' '))
|
||||
{
|
||||
fileName = fileName.AppendQuotes();
|
||||
}
|
||||
if (arguments.Contains(' '))
|
||||
{
|
||||
arguments = arguments.AppendQuotes();
|
||||
}
|
||||
|
||||
Process proc = new()
|
||||
{
|
||||
|
||||
@@ -857,7 +857,7 @@ namespace ServiceLib.Common
|
||||
private static async Task<string?> GetLinuxUserId()
|
||||
{
|
||||
var arg = new List<string>() { "-c", "id -u" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||
}
|
||||
|
||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||
@@ -868,14 +868,14 @@ namespace ServiceLib.Common
|
||||
fileName = fileName.AppendQuotes();
|
||||
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||
}
|
||||
|
||||
public static async Task<string?> GetLinuxFontFamily(string lang)
|
||||
{
|
||||
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
||||
var arg = new List<string>() { "-c", $"fc-list : family" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||
}
|
||||
|
||||
public static string? GetHomePath()
|
||||
@@ -885,12 +885,6 @@ namespace ServiceLib.Common
|
||||
: Environment.GetEnvironmentVariable("HOME");
|
||||
}
|
||||
|
||||
public static async Task<string?> GetListNetworkServices()
|
||||
{
|
||||
var arg = new List<string>() { "-c", $"networksetup -listallnetworkservices" };
|
||||
return await GetCliWrapOutput("/bin/bash", arg);
|
||||
}
|
||||
|
||||
#endregion Platform
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace ServiceLib
|
||||
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
||||
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
||||
public const string PacFileName = NamespaceSample + "pac";
|
||||
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
||||
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
||||
|
||||
public const string DefaultSecurity = "auto";
|
||||
public const string DefaultNetwork = "tcp";
|
||||
@@ -67,10 +69,11 @@ namespace ServiceLib
|
||||
public const int MinFontSize = 8;
|
||||
public const string RebootAs = "rebootas";
|
||||
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA";
|
||||
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
|
||||
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
||||
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
||||
public const int SpeedTestPageSize = 1000;
|
||||
public const string LinuxBash = "/bin/bash";
|
||||
|
||||
public static readonly List<string> IEProxyProtocols =
|
||||
[
|
||||
@@ -426,12 +429,12 @@ namespace ServiceLib
|
||||
"fakedns+others"
|
||||
];
|
||||
|
||||
public static readonly List<string> TunMtus =
|
||||
public static readonly List<int> TunMtus =
|
||||
[
|
||||
"1280",
|
||||
"1408",
|
||||
"1500",
|
||||
"9000"
|
||||
1280,
|
||||
1408,
|
||||
1500,
|
||||
9000
|
||||
];
|
||||
|
||||
public static readonly List<string> TunStacks =
|
||||
@@ -507,6 +510,13 @@ namespace ServiceLib
|
||||
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
||||
};
|
||||
|
||||
public static readonly List<string> OtherGeoUrls =
|
||||
[
|
||||
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
|
||||
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
|
||||
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
||||
];
|
||||
|
||||
#endregion const
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace ServiceLib.Handler
|
||||
task.Settings.RunOnlyIfIdle = false;
|
||||
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
|
||||
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(20) });
|
||||
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
|
||||
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace ServiceLib.Handler
|
||||
if (File.Exists(launchAgentPath))
|
||||
{
|
||||
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
|
||||
await Utils.GetCliWrapOutput("/bin/bash", args);
|
||||
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||
|
||||
File.Delete(launchAgentPath);
|
||||
}
|
||||
@@ -197,7 +197,7 @@ namespace ServiceLib.Handler
|
||||
await File.WriteAllTextAsync(launchAgentPath, plistContent);
|
||||
|
||||
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
|
||||
await Utils.GetCliWrapOutput("/bin/bash", args);
|
||||
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -158,6 +158,7 @@ namespace ServiceLib.Handler
|
||||
Length = "100-200",
|
||||
Interval = "10-20"
|
||||
};
|
||||
config.GlobalHotkeys ??= new();
|
||||
|
||||
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||
{
|
||||
@@ -216,6 +217,7 @@ namespace ServiceLib.Handler
|
||||
item.Remarks = profileItem.Remarks;
|
||||
item.Address = profileItem.Address;
|
||||
item.Port = profileItem.Port;
|
||||
item.Ports = profileItem.Ports;
|
||||
|
||||
item.Id = profileItem.Id;
|
||||
item.AlterId = profileItem.AlterId;
|
||||
@@ -724,7 +726,7 @@ namespace ServiceLib.Handler
|
||||
profileItem.Network = string.Empty;
|
||||
if (profileItem.ShortId.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.ShortId = Global.TunMtus.FirstOrDefault();
|
||||
profileItem.ShortId = Global.TunMtus.First().ToString();
|
||||
}
|
||||
|
||||
if (profileItem.Id.IsNullOrEmpty())
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace ServiceLib.Handler
|
||||
StartInfo = new()
|
||||
{
|
||||
FileName = fileName,
|
||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath) : configPath),
|
||||
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = displayLog,
|
||||
@@ -380,7 +380,7 @@ namespace ServiceLib.Handler
|
||||
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||
{
|
||||
//Shell scripts
|
||||
var shFilePath = Utils.GetBinPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||
File.Delete(shFilePath);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("#!/bin/sh");
|
||||
|
||||
@@ -1,202 +1,33 @@
|
||||
namespace ServiceLib.Handler.SysProxy
|
||||
namespace ServiceLib.Handler.SysProxy
|
||||
{
|
||||
public class ProxySettingLinux
|
||||
{
|
||||
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||
|
||||
public static async Task SetProxy(string host, int port, string exceptions)
|
||||
{
|
||||
var lstCmd = GetSetCmds(host, port, exceptions);
|
||||
|
||||
await ExecCmd(lstCmd);
|
||||
List<string> args = ["manual", host, port.ToString(), exceptions];
|
||||
await ExecCmd(args);
|
||||
}
|
||||
|
||||
public static async Task UnsetProxy()
|
||||
{
|
||||
var lstCmd = GetUnsetCmds();
|
||||
|
||||
await ExecCmd(lstCmd);
|
||||
List<string> args = ["none"];
|
||||
await ExecCmd(args);
|
||||
}
|
||||
|
||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
||||
private static async Task ExecCmd(List<string> args)
|
||||
{
|
||||
foreach (var cmd in lstCmd)
|
||||
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
await Task.Delay(10);
|
||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
||||
}
|
||||
}
|
||||
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
|
||||
await File.AppendAllTextAsync(fileName, contents);
|
||||
|
||||
private static List<CmdItem> GetSetCmds(string host, int port, string exceptions)
|
||||
{
|
||||
var isKde = IsKde(out var configDir);
|
||||
List<string> lstType = ["", "http", "https", "socks", "ftp"];
|
||||
List<CmdItem> lstCmd = [];
|
||||
|
||||
//GNOME
|
||||
foreach (var type in lstType)
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
||||
}
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Gnome("exceptions", exceptions, 0));
|
||||
await Utils.SetLinuxChmod(fileName);
|
||||
}
|
||||
|
||||
if (isKde)
|
||||
{
|
||||
foreach (var type in lstType)
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
|
||||
}
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
lstCmd.AddRange(GetSetCmd4Kde("exceptions", exceptions, 0, configDir));
|
||||
}
|
||||
|
||||
// Notify system to reload
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "dbus-send",
|
||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
||||
});
|
||||
}
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetUnsetCmds()
|
||||
{
|
||||
var isKde = IsKde(out var configDir);
|
||||
List<CmdItem> lstCmd = [];
|
||||
|
||||
//GNOME
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
||||
});
|
||||
|
||||
if (isKde)
|
||||
{
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = GetKdeVersion(),
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
|
||||
});
|
||||
|
||||
// Notify system to reload
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "dbus-send",
|
||||
Arguments = ["--type=signal", "/KIO/Scheduler", "org.kde.KIO.Scheduler.reparseSlaveConfiguration", "string:''"]
|
||||
});
|
||||
}
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
var cmd = GetKdeVersion();
|
||||
|
||||
if (type.IsNullOrEmpty())
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
|
||||
});
|
||||
}
|
||||
else if (type == "exceptions")
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "NoProxyFor", host]
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var type2 = type.Equals("https") ? "http" : type;
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = cmd,
|
||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
|
||||
});
|
||||
}
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmd4Gnome(string type, string host, int port)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
|
||||
if (type.IsNullOrEmpty())
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
|
||||
});
|
||||
}
|
||||
else if (type == "exceptions")
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", $"org.gnome.system.proxy", "ignore-hosts", JsonUtils.Serialize(host.Split(','), false)]
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "host", host]
|
||||
});
|
||||
|
||||
lstCmd.Add(new()
|
||||
{
|
||||
Cmd = "gsettings",
|
||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "port", $"{port}"]
|
||||
});
|
||||
}
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static bool IsKde(out string configDir)
|
||||
{
|
||||
configDir = "/home";
|
||||
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
|
||||
var desktop2 = Environment.GetEnvironmentVariable("XDG_SESSION_DESKTOP");
|
||||
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop, "plasma", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop2, "KDE", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(desktop2, "plasma", StringComparison.OrdinalIgnoreCase);
|
||||
if (isKde)
|
||||
{
|
||||
var homeDir = Environment.GetEnvironmentVariable("HOME");
|
||||
if (homeDir != null)
|
||||
{
|
||||
configDir = Path.Combine(homeDir, ".config");
|
||||
}
|
||||
}
|
||||
|
||||
return isKde;
|
||||
}
|
||||
|
||||
private static string GetKdeVersion()
|
||||
{
|
||||
var ver = Environment.GetEnvironmentVariable("KDE_SESSION_VERSION") ?? "0";
|
||||
return ver switch
|
||||
{
|
||||
"6" => "kwriteconfig6",
|
||||
_ => "kwriteconfig5"
|
||||
};
|
||||
await Utils.GetCliWrapOutput(fileName, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,101 +1,38 @@
|
||||
namespace ServiceLib.Handler.SysProxy
|
||||
namespace ServiceLib.Handler.SysProxy
|
||||
{
|
||||
public class ProxySettingOSX
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用接口类型
|
||||
/// </summary>
|
||||
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge", "USB 10/100/1000 LAN"];
|
||||
|
||||
/// <summary>
|
||||
/// 代理类型,对应 http,https,socks
|
||||
/// </summary>
|
||||
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
|
||||
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||
|
||||
public static async Task SetProxy(string host, int port, string exceptions)
|
||||
{
|
||||
var lstInterface = await GetListNetworkServices();
|
||||
var lstCmd = GetSetCmds(lstInterface, host, port, exceptions);
|
||||
await ExecCmd(lstCmd);
|
||||
List<string> args = ["set", host, port.ToString()];
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
args.AddRange(exceptions.Split(','));
|
||||
}
|
||||
|
||||
await ExecCmd(args);
|
||||
}
|
||||
|
||||
public static async Task UnsetProxy()
|
||||
{
|
||||
var lstInterface = await GetListNetworkServices();
|
||||
var lstCmd = GetUnsetCmds(lstInterface);
|
||||
await ExecCmd(lstCmd);
|
||||
List<string> args = ["clear"];
|
||||
await ExecCmd(args);
|
||||
}
|
||||
|
||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
||||
private static async Task ExecCmd(List<string> args)
|
||||
{
|
||||
foreach (var cmd in lstCmd)
|
||||
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
|
||||
await File.AppendAllTextAsync(fileName, contents);
|
||||
|
||||
await Task.Delay(10);
|
||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetSetCmds(List<string> lstInterface, string host, int port, string exceptions)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
foreach (var interf in lstInterface)
|
||||
{
|
||||
foreach (var type in LstTypes)
|
||||
{
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "networksetup",
|
||||
Arguments = [$"-{type}", interf, host, port.ToString()]
|
||||
});
|
||||
}
|
||||
if (exceptions.IsNotEmpty())
|
||||
{
|
||||
List<string> args = [$"-setproxybypassdomains", interf];
|
||||
args.AddRange(exceptions.Split(','));
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "networksetup",
|
||||
Arguments = args
|
||||
});
|
||||
}
|
||||
await Utils.SetLinuxChmod(fileName);
|
||||
}
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
private static List<CmdItem> GetUnsetCmds(List<string> lstInterface)
|
||||
{
|
||||
List<CmdItem> lstCmd = [];
|
||||
foreach (var interf in lstInterface)
|
||||
{
|
||||
foreach (var type in LstTypes)
|
||||
{
|
||||
lstCmd.Add(new CmdItem()
|
||||
{
|
||||
Cmd = "networksetup",
|
||||
Arguments = [$"-{type}state", interf, "off"]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return lstCmd;
|
||||
}
|
||||
|
||||
public static async Task<List<string>> GetListNetworkServices()
|
||||
{
|
||||
var services = await Utils.GetListNetworkServices();
|
||||
if (services.IsNullOrEmpty())
|
||||
{
|
||||
return LstInterface;
|
||||
}
|
||||
|
||||
var lst = services.Split(Environment.NewLine).Where(t => t.Length > 0 && t.Contains('*') == false);
|
||||
return lst.ToList();
|
||||
await Utils.GetCliWrapOutput(fileName, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ namespace ServiceLib.Models
|
||||
{
|
||||
public int UpMbps { get; set; }
|
||||
public int DownMbps { get; set; }
|
||||
public int HopInterval { get; set; } = 30;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using SQLite;
|
||||
using SQLite;
|
||||
|
||||
namespace ServiceLib.Models
|
||||
{
|
||||
@@ -64,11 +64,11 @@ namespace ServiceLib.Models
|
||||
|
||||
[PrimaryKey]
|
||||
public string IndexId { get; set; }
|
||||
|
||||
public EConfigType ConfigType { get; set; }
|
||||
public int ConfigVersion { get; set; }
|
||||
public string Address { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string Ports { get; set; }
|
||||
public string Id { get; set; }
|
||||
public int AlterId { get; set; }
|
||||
public string Security { get; set; }
|
||||
@@ -93,4 +93,4 @@ namespace ServiceLib.Models
|
||||
public string SpiderX { get; set; }
|
||||
public string Extra { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace ServiceLib.Models
|
||||
namespace ServiceLib.Models
|
||||
{
|
||||
public class SingboxConfig
|
||||
{
|
||||
@@ -101,21 +101,23 @@
|
||||
public string tag { get; set; }
|
||||
public string? server { get; set; }
|
||||
public int? server_port { get; set; }
|
||||
public string uuid { get; set; }
|
||||
public string security { get; set; }
|
||||
public List<string>? server_ports { get; set; }
|
||||
public string? uuid { get; set; }
|
||||
public string? security { get; set; }
|
||||
public int? alter_id { get; set; }
|
||||
public string flow { get; set; }
|
||||
public string? flow { get; set; }
|
||||
public string? hop_interval { get; set; }
|
||||
public int? up_mbps { get; set; }
|
||||
public int? down_mbps { get; set; }
|
||||
public string auth_str { get; set; }
|
||||
public string? auth_str { get; set; }
|
||||
public int? recv_window_conn { get; set; }
|
||||
public int? recv_window { get; set; }
|
||||
public bool? disable_mtu_discovery { get; set; }
|
||||
public string? detour { get; set; }
|
||||
public string method { get; set; }
|
||||
public string username { get; set; }
|
||||
public string password { get; set; }
|
||||
public string congestion_control { get; set; }
|
||||
public string? method { get; set; }
|
||||
public string? username { get; set; }
|
||||
public string? password { get; set; }
|
||||
public string? congestion_control { get; set; }
|
||||
public string? version { get; set; }
|
||||
public string? network { get; set; }
|
||||
public string? packet_encoding { get; set; }
|
||||
@@ -252,4 +254,4 @@
|
||||
public string? download_detour { get; set; }
|
||||
public string? update_interval { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
20
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -2536,6 +2536,24 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Server port range 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbPorts7 {
|
||||
get {
|
||||
return ResourceManager.GetString("TbPorts7", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Will cover the port, separate with commas (,) 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbPorts7Tips {
|
||||
get {
|
||||
return ResourceManager.GetString("TbPorts7Tips", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Socks port 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2879,7 +2897,7 @@ namespace ServiceLib.Resx {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 Install the font to the system and restart the settings 的本地化字符串。
|
||||
/// 查找类似 Install the font to the system, select or fill in the font name, restart the settings 的本地化字符串。
|
||||
/// </summary>
|
||||
public static string TbSettingsCurrentFontFamilyLinuxTip {
|
||||
get {
|
||||
|
||||
@@ -1396,4 +1396,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>Removed {0} invalid test results.</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>Server port range</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Will cover the port, separate with commas (,)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1396,4 +1396,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>Removed {0} invalid test results.</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>Server port range</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Will cover the port, separate with commas (,)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1334,7 +1334,7 @@
|
||||
<value>Please do not use the insecure HTTP protocol subscription address</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||
<value>Install the font to the system and restart the settings</value>
|
||||
<value>Install the font to the system, select or fill in the font name, restart the settings</value>
|
||||
</data>
|
||||
<data name="menuExitTips" xml:space="preserve">
|
||||
<value>Are you sure to exit?</value>
|
||||
@@ -1396,4 +1396,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>Removed {0} invalid test results.</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>Server port range</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Will cover the port, separate with commas (,)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1396,4 +1396,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>Removed {0} invalid test results.</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>Server port range</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>Will cover the port, separate with commas (,)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1331,7 +1331,7 @@
|
||||
<value>请不要使用不安全的HTTP协议订阅地址</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||
<value>安装字体到系统中,重启设置</value>
|
||||
<value>安装字体到系统中,选择或填入字体名称,重启设置</value>
|
||||
</data>
|
||||
<data name="menuExitTips" xml:space="preserve">
|
||||
<value>是否确定退出?</value>
|
||||
@@ -1393,4 +1393,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>移除无效测试结果 {0} 个。</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>跳跃端口范围</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>会覆盖端口,多组时用逗号(,)隔开</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -1212,7 +1212,7 @@
|
||||
<value>請不要使用不安全的HTTP協定訂閱位址</value>
|
||||
</data>
|
||||
<data name="TbSettingsCurrentFontFamilyLinuxTip" xml:space="preserve">
|
||||
<value>安裝字型到系統中,重新啟動設定</value>
|
||||
<value>安裝字體到系統中,選擇或填入字體名稱,重新啟動設定</value>
|
||||
</data>
|
||||
<data name="menuExitTips" xml:space="preserve">
|
||||
<value>是否確定退出?</value>
|
||||
@@ -1394,4 +1394,10 @@
|
||||
<data name="RemoveInvalidServerResultTip" xml:space="preserve">
|
||||
<value>移除無效測試結果 {0} 個。</value>
|
||||
</data>
|
||||
<data name="TbPorts7" xml:space="preserve">
|
||||
<value>跳躍端口範圍</value>
|
||||
</data>
|
||||
<data name="TbPorts7Tips" xml:space="preserve">
|
||||
<value>會覆蓋端口,多組時用逗號(,)隔開</value>
|
||||
</data>
|
||||
</root>
|
||||
118
v2rayN/ServiceLib/Sample/proxy_set_linux_sh
Normal file
118
v2rayN/ServiceLib/Sample/proxy_set_linux_sh
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to set proxy for GNOME
|
||||
set_gnome_proxy() {
|
||||
local MODE=$1
|
||||
local PROXY_IP=$2
|
||||
local PROXY_PORT=$3
|
||||
local IGNORE_HOSTS=$4
|
||||
|
||||
# Set the proxy mode
|
||||
gsettings set org.gnome.system.proxy mode "$MODE"
|
||||
|
||||
if [ "$MODE" == "manual" ]; then
|
||||
# List of protocols
|
||||
local PROTOCOLS=("http" "https" "ftp" "socks")
|
||||
|
||||
# Loop through protocols to set the proxy
|
||||
for PROTOCOL in "${PROTOCOLS[@]}"; do
|
||||
gsettings set org.gnome.system.proxy.$PROTOCOL host "$PROXY_IP"
|
||||
gsettings set org.gnome.system.proxy.$PROTOCOL port "$PROXY_PORT"
|
||||
done
|
||||
|
||||
# Set ignored hosts
|
||||
gsettings set org.gnome.system.proxy ignore-hosts "['$IGNORE_HOSTS']"
|
||||
|
||||
echo "GNOME: Manual proxy settings applied."
|
||||
echo "Proxy IP: $PROXY_IP"
|
||||
echo "Proxy Port: $PROXY_PORT"
|
||||
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||
elif [ "$MODE" == "none" ]; then
|
||||
echo "GNOME: Proxy disabled."
|
||||
else
|
||||
echo "GNOME: Invalid mode. Use 'none' or 'manual'."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to set proxy for KDE
|
||||
set_kde_proxy() {
|
||||
local MODE=$1
|
||||
local PROXY_IP=$2
|
||||
local PROXY_PORT=$3
|
||||
local IGNORE_HOSTS=$4
|
||||
|
||||
# Determine the correct kwriteconfig command based on KDE_SESSION_VERSION
|
||||
if [ "$KDE_SESSION_VERSION" == "6" ]; then
|
||||
KWRITECONFIG="kwriteconfig6"
|
||||
else
|
||||
KWRITECONFIG="kwriteconfig5"
|
||||
fi
|
||||
|
||||
# KDE uses kwriteconfig to modify proxy settings
|
||||
if [ "$MODE" == "manual" ]; then
|
||||
# Set proxy for all protocols
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 1
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key httpsProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ftpProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key socksProxy "http://$PROXY_IP:$PROXY_PORT"
|
||||
|
||||
# Set ignored hosts
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key NoProxyFor "$IGNORE_HOSTS"
|
||||
|
||||
echo "KDE: Manual proxy settings applied."
|
||||
echo "Proxy IP: $PROXY_IP"
|
||||
echo "Proxy Port: $PROXY_PORT"
|
||||
echo "Ignored Hosts: $IGNORE_HOSTS"
|
||||
elif [ "$MODE" == "none" ]; then
|
||||
# Disable proxy
|
||||
$KWRITECONFIG --file kioslaverc --group "Proxy Settings" --key ProxyType 0
|
||||
echo "KDE: Proxy disabled."
|
||||
else
|
||||
echo "KDE: Invalid mode. Use 'none' or 'manual'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Apply changes by restarting KDE's network settings
|
||||
dbus-send --type=signal /KIO/Scheduler org.kde.KIO.Scheduler.reparseSlaveConfiguration string:""
|
||||
}
|
||||
|
||||
# Detect the current desktop environment
|
||||
detect_desktop_environment() {
|
||||
if [ "$XDG_CURRENT_DESKTOP" == "GNOME" ] || [ "$XDG_CURRENT_DESKTOP" == "ubuntu:GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "GNOME" ] || [ "$XDG_SESSION_DESKTOP" == "ubuntu:GNOME" ]; then
|
||||
echo "gnome"
|
||||
elif [ "$XDG_CURRENT_DESKTOP" == "KDE" ] || [ "$XDG_CURRENT_DESKTOP" == "plasma" ] || [ "$XDG_SESSION_DESKTOP" == "KDE" ] || [ "$XDG_SESSION_DESKTOP" == "plasma" ]; then
|
||||
echo "kde"
|
||||
else
|
||||
echo "unsupported"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "Usage: $0 <mode> [proxy_ip proxy_port ignore_hosts]"
|
||||
echo " mode: 'none' or 'manual'"
|
||||
echo " If mode is 'manual', provide proxy IP, port, and ignore hosts."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the mode
|
||||
MODE=$1
|
||||
PROXY_IP=$2
|
||||
PROXY_PORT=$3
|
||||
IGNORE_HOSTS=$4
|
||||
|
||||
# Detect desktop environment
|
||||
DE=$(detect_desktop_environment)
|
||||
|
||||
# Apply settings based on the desktop environment
|
||||
if [ "$DE" == "gnome" ]; then
|
||||
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||
elif [ "$DE" == "kde" ]; then
|
||||
set_gnome_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||
set_kde_proxy "$MODE" "$PROXY_IP" "$PROXY_PORT" "$IGNORE_HOSTS"
|
||||
else
|
||||
echo "Unsupported desktop environment: $DE"
|
||||
exit 1
|
||||
fi
|
||||
74
v2rayN/ServiceLib/Sample/proxy_set_osx_sh
Normal file
74
v2rayN/ServiceLib/Sample/proxy_set_osx_sh
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to set proxy
|
||||
set_proxy() {
|
||||
PROXY_IP=$1
|
||||
PROXY_PORT=$2
|
||||
|
||||
shift 2
|
||||
BYPASS_DOMAINS=("$@")
|
||||
# If no bypass domains are provided, set it to empty by default
|
||||
if [ ${#BYPASS_DOMAINS[@]} -eq 0 ]; then
|
||||
BYPASS_DOMAINS=("")
|
||||
fi
|
||||
|
||||
# Get all network service names
|
||||
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
|
||||
|
||||
# Loop through each network service
|
||||
echo "$SERVICES" | while read -r SERVICE; do
|
||||
echo "Setting proxy for network service '$SERVICE'..."
|
||||
# Set HTTP proxy
|
||||
networksetup -setwebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||
|
||||
# Set HTTPS proxy
|
||||
networksetup -setsecurewebproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||
|
||||
# Set SOCKS proxy
|
||||
networksetup -setsocksfirewallproxy "$SERVICE" "$PROXY_IP" "$PROXY_PORT"
|
||||
|
||||
# Set bypass domains
|
||||
networksetup -setproxybypassdomains "$SERVICE" "${BYPASS_DOMAINS[@]}"
|
||||
echo "Proxy for network service '$SERVICE' has been set to $PROXY_IP:$PROXY_PORT"
|
||||
done
|
||||
echo "Proxy settings for all network services are complete!"
|
||||
}
|
||||
|
||||
# Function to disable proxy
|
||||
clear_proxy() {
|
||||
# Get all network service names
|
||||
SERVICES=$(networksetup -listallnetworkservices | grep -v '*')
|
||||
|
||||
# Loop through each network service
|
||||
echo "$SERVICES" | while read -r SERVICE; do
|
||||
echo "Disabling proxy and clearing bypass domains for network service '$SERVICE'..."
|
||||
# Disable HTTP proxy
|
||||
networksetup -setwebproxystate "$SERVICE" off
|
||||
|
||||
# Disable HTTPS proxy
|
||||
networksetup -setsecurewebproxystate "$SERVICE" off
|
||||
|
||||
# Disable SOCKS proxy
|
||||
networksetup -setsocksfirewallproxystate "$SERVICE" off
|
||||
|
||||
echo "Proxy for network service '$SERVICE' has been disabled"
|
||||
done
|
||||
echo "Proxy for all network services has been disabled!"
|
||||
}
|
||||
|
||||
# Main script logic
|
||||
if [ "$1" == "set" ]; then
|
||||
# Check if enough parameters are passed for setting proxy
|
||||
if [ "$#" -lt 3 ]; then
|
||||
echo "Usage: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
|
||||
exit 1
|
||||
fi
|
||||
set_proxy "$2" "$3" "${@:4}"
|
||||
elif [ "$1" == "clear" ]; then
|
||||
clear_proxy
|
||||
else
|
||||
echo "Usage:"
|
||||
echo " To set proxy: $0 set <IP Address> <Port> [Bypass Domain 1 Bypass Domain 2 ...]"
|
||||
echo " To clear proxy: $0 clear"
|
||||
exit 1
|
||||
fi
|
||||
@@ -29,6 +29,8 @@
|
||||
<EmbeddedResource Include="Sample\dns_singbox_normal" />
|
||||
<EmbeddedResource Include="Sample\dns_v2ray_normal" />
|
||||
<EmbeddedResource Include="Sample\pac" />
|
||||
<EmbeddedResource Include="Sample\proxy_set_linux_sh" />
|
||||
<EmbeddedResource Include="Sample\proxy_set_osx_sh" />
|
||||
<EmbeddedResource Include="Sample\SampleClientConfig" />
|
||||
<EmbeddedResource Include="Sample\SampleHttpRequest" />
|
||||
<EmbeddedResource Include="Sample\SampleHttpResponse" />
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
//enable tun mode
|
||||
if (_config.TunModeItem.EnableTun)
|
||||
{
|
||||
string tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
||||
var tun = EmbedUtils.GetEmbedText(Global.ClashTunYaml);
|
||||
if (Utils.IsNotEmpty(tun))
|
||||
{
|
||||
var tunContent = YamlUtils.FromYaml<Dictionary<string, object>>(tun);
|
||||
|
||||
@@ -599,7 +599,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
{
|
||||
if (_config.TunModeItem.Mtu <= 0)
|
||||
{
|
||||
_config.TunModeItem.Mtu = Utils.ToInt(Global.TunMtus.First());
|
||||
_config.TunModeItem.Mtu = Global.TunMtus.First();
|
||||
}
|
||||
if (Utils.IsNullOrEmpty(_config.TunModeItem.Stack))
|
||||
{
|
||||
@@ -730,6 +730,13 @@ namespace ServiceLib.Services.CoreConfig
|
||||
|
||||
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
|
||||
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
|
||||
if (node.Ports.IsNotEmpty())
|
||||
{
|
||||
outbound.server_port = null;
|
||||
outbound.server_ports = node.Ports.Split(",").ToList();
|
||||
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case EConfigType.TUIC:
|
||||
@@ -745,7 +752,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
outbound.peer_public_key = node.PublicKey;
|
||||
outbound.reserved = Utils.String2List(node.Path)?.Select(int.Parse).ToList();
|
||||
outbound.local_address = Utils.String2List(node.RequestHost);
|
||||
outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.FirstOrDefault() : node.ShortId);
|
||||
outbound.mtu = Utils.ToInt(node.ShortId.IsNullOrEmpty() ? Global.TunMtus.First() : node.ShortId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1324,7 +1331,7 @@ namespace ServiceLib.Services.CoreConfig
|
||||
singboxConfig.experimental.cache_file = new CacheFile4Sbox()
|
||||
{
|
||||
enabled = true,
|
||||
path = Utils.GetBinConfigPath("cache.db")
|
||||
path = Utils.GetBinPath("cache.db")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Sockets;
|
||||
@@ -222,20 +222,20 @@ namespace ServiceLib.Services
|
||||
|
||||
public async Task<int> RunAvailabilityCheck(IWebProxy? webProxy)
|
||||
{
|
||||
var responseTime = -1;
|
||||
try
|
||||
{
|
||||
webProxy ??= await GetWebProxy(true);
|
||||
var config = AppHandler.Instance.Config;
|
||||
|
||||
try
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var config = AppHandler.Instance.Config;
|
||||
var responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||
return responseTime;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
responseTime = await GetRealPingTime(config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||
if (responseTime > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
await Task.Delay(500);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -243,6 +243,7 @@ namespace ServiceLib.Services
|
||||
Logging.SaveLog(_tag, ex);
|
||||
return -1;
|
||||
}
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
public async Task<int> GetRealPingTime(string url, IWebProxy? webProxy, int downloadTimeout)
|
||||
@@ -319,4 +320,4 @@ namespace ServiceLib.Services
|
||||
ServicePointManager.DefaultConnectionLimit = 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,10 +261,17 @@ namespace ServiceLib.Services
|
||||
if (pid > 0)
|
||||
{
|
||||
await Task.Delay(500);
|
||||
await DoRealPing(downloadHandle, it);
|
||||
var delay = await DoRealPing(downloadHandle, it);
|
||||
if (blSpeedTest)
|
||||
{
|
||||
await DoSpeedTest(downloadHandle, it);
|
||||
if (delay > 0)
|
||||
{
|
||||
await DoSpeedTest(downloadHandle, it);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateFunc(it.IndexId, "", ResUI.SpeedtestingSkip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -289,13 +296,14 @@ namespace ServiceLib.Services
|
||||
Task.WaitAll(tasks.ToArray());
|
||||
}
|
||||
|
||||
private async Task DoRealPing(DownloadService downloadHandle, ServerTestItem it)
|
||||
private async Task<int> DoRealPing(DownloadService downloadHandle, ServerTestItem it)
|
||||
{
|
||||
var webProxy = new WebProxy($"socks5://{Global.Loopback}:{it.Port}");
|
||||
var responseTime = await downloadHandle.GetRealPingTime(_config.SpeedTestItem.SpeedPingTestUrl, webProxy, 10);
|
||||
|
||||
ProfileExHandler.Instance.SetTestDelay(it.IndexId, responseTime);
|
||||
UpdateFunc(it.IndexId, responseTime.ToString());
|
||||
return responseTime;
|
||||
}
|
||||
|
||||
private async Task DoSpeedTest(DownloadService downloadHandle, ServerTestItem it)
|
||||
@@ -328,21 +336,19 @@ namespace ServiceLib.Services
|
||||
ipAddress = ipHostInfo.AddressList.First();
|
||||
}
|
||||
|
||||
var timer = Stopwatch.StartNew();
|
||||
|
||||
IPEndPoint endPoint = new(ipAddress, port);
|
||||
using Socket clientSocket = new(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
var timer = Stopwatch.StartNew();
|
||||
var result = clientSocket.BeginConnect(endPoint, null, null);
|
||||
if (!result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
throw new TimeoutException("connect timeout (5s): " + url);
|
||||
}
|
||||
|
||||
clientSocket.EndConnect(result);
|
||||
|
||||
timer.Stop();
|
||||
responseTime = (int)timer.Elapsed.TotalMilliseconds;
|
||||
|
||||
clientSocket.EndConnect(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -237,8 +237,8 @@ namespace ServiceLib.Services
|
||||
|
||||
public async Task UpdateGeoFileAll(Config config, Action<bool, string> updateFunc)
|
||||
{
|
||||
await UpdateGeoFile("geosite", config, updateFunc);
|
||||
await UpdateGeoFile("geoip", config, updateFunc);
|
||||
await UpdateGeoFiles(config, updateFunc);
|
||||
await UpdateOtherFiles(config, updateFunc);
|
||||
await UpdateSrsFileAll(config, updateFunc);
|
||||
_updateFunc?.Invoke(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo"));
|
||||
}
|
||||
@@ -472,14 +472,14 @@ namespace ServiceLib.Services
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
return await Task.FromResult("");
|
||||
}
|
||||
|
||||
#endregion CheckUpdate private
|
||||
|
||||
#region Geo private
|
||||
|
||||
private async Task UpdateGeoFile(string geoName, Config config, Action<bool, string> updateFunc)
|
||||
private async Task UpdateGeoFiles(Config config, Action<bool, string> updateFunc)
|
||||
{
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
@@ -487,11 +487,28 @@ namespace ServiceLib.Services
|
||||
? Global.GeoUrl
|
||||
: config.ConstItem.GeoSourceUrl;
|
||||
|
||||
var fileName = $"{geoName}.dat";
|
||||
var targetPath = Utils.GetBinPath($"{fileName}");
|
||||
var url = string.Format(geoUrl, geoName);
|
||||
List<string> files = ["geosite", "geoip"];
|
||||
foreach (var geoName in files)
|
||||
{
|
||||
var fileName = $"{geoName}.dat";
|
||||
var targetPath = Utils.GetBinPath($"{fileName}");
|
||||
var url = string.Format(geoUrl, geoName);
|
||||
|
||||
await DownloadGeoFile(url, fileName, targetPath, updateFunc);
|
||||
await DownloadGeoFile(url, fileName, targetPath, updateFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateOtherFiles(Config config, Action<bool, string> updateFunc)
|
||||
{
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
foreach (var url in Global.OtherGeoUrls)
|
||||
{
|
||||
var fileName = Path.GetFileName(url);
|
||||
var targetPath = Utils.GetBinPath($"{fileName}");
|
||||
|
||||
await DownloadGeoFile(url, fileName, targetPath, updateFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateSrsFileAll(Config config, Action<bool, string> updateFunc)
|
||||
|
||||
65
v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs
Normal file
65
v2rayN/ServiceLib/ViewModels/GlobalHotkeySettingViewModel.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Reactive;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace ServiceLib.ViewModels
|
||||
{
|
||||
public class GlobalHotkeySettingViewModel : MyReactiveObject
|
||||
{
|
||||
private readonly List<KeyEventItem> _globalHotkeys;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SaveCmd { get; }
|
||||
|
||||
public GlobalHotkeySettingViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
|
||||
{
|
||||
_config = AppHandler.Instance.Config;
|
||||
_updateView = updateView;
|
||||
|
||||
_globalHotkeys = JsonUtils.DeepCopy(_config.GlobalHotkeys);
|
||||
|
||||
SaveCmd = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
await SaveSettingAsync();
|
||||
});
|
||||
}
|
||||
|
||||
public KeyEventItem GetKeyEventItem(EGlobalHotkey eg)
|
||||
{
|
||||
var item = _globalHotkeys.FirstOrDefault((it) => it.EGlobalHotkey == eg);
|
||||
if (item != null)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
item = new()
|
||||
{
|
||||
EGlobalHotkey = eg,
|
||||
Control = false,
|
||||
Alt = false,
|
||||
Shift = false,
|
||||
KeyCode = null
|
||||
};
|
||||
_globalHotkeys.Add(item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public void ResetKeyEventItem()
|
||||
{
|
||||
_globalHotkeys.Clear();
|
||||
}
|
||||
|
||||
private async Task SaveSettingAsync()
|
||||
{
|
||||
_config.GlobalHotkeys = _globalHotkeys;
|
||||
|
||||
if (await ConfigHandler.SaveConfig(_config) == 0)
|
||||
{
|
||||
_updateView?.Invoke(EViewAction.CloseWindow, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
NoticeHandler.Instance.Enqueue(ResUI.OperationFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,6 +316,8 @@ namespace ServiceLib.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
_updateView?.Invoke(EViewAction.DispatcherServerAvailability, ResUI.Speedtesting);
|
||||
|
||||
var msg = await (new UpdateService()).RunAvailabilityCheck();
|
||||
|
||||
NoticeHandler.Instance.SendMessageEx(msg);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceInclude Source="Assets/GlobalResources.axaml" />
|
||||
<ResourceInclude Source="Controls/AutoCompleteBox.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
@@ -8,4 +8,13 @@
|
||||
<StreamGeometry x:Key="building_refresh">M849.652671 679.144788l111.007233-174.965917-50.615794 0C905.498584 274.107915 717.720873 88.965218 486.575446 88.965218c-233.998405 0-423.716304 189.698456-423.716304 423.707095 0 233.998405 189.716876 423.715281 423.716304 423.715281 113.936959 0 217.278605-45.079708 293.440216-118.235868l-62.46568-108.306728c-55.750745 65.205071-138.455375 106.709347-230.974535 106.709347-167.843706 0-303.882032-136.039349-303.882032-303.883055S318.732763 208.788234 486.575446 208.788234c164.951843 0 298.899554 131.522476 303.44508 295.389614l-51.357691 0L849.652671 679.144788z</StreamGeometry>
|
||||
<StreamGeometry x:Key="building_ping">M273.28 899.328c-6.4 6.4-16 9.6-25.6 9.6-6.4 0-12.8-3.2-18.56-6.4-102.4-85.76-162.56-209.92-162.56-343.68 0-245.12 200.32-445.44 445.44-445.44s445.44 200.32 445.44 445.44c0 133.76-56.96 257.92-162.56 343.68-12.16 12.8-34.56 9.6-44.16-3.2-12.8-12.8-9.6-35.2 3.2-44.8a377.152 377.152 0 0 0 136.96-292.48c0-209.92-172.16-382.08-382.08-382.08-206.72-3.2-378.88 168.96-378.88 378.88 0 114.56 51.2 222.72 140.16 295.68 12.8 12.8 16 32 3.2 44.8z m394.88-540.8c12.8-12.8 31.36-12.8 44.16 0 12.8 12.8 12.8 32 0 44.8l-138.88 138.88c1.28 5.12 2.56 10.88 2.56 16.64 0 35.2-28.8 64-64 64-5.76 0-11.52-1.28-16.64-2.56l-24.32 24.32c-6.4 6.4-12.8 9.6-22.4 9.6-9.6 0-16-3.2-22.4-9.6-12.8-12.8-12.8-31.36 0-44.16l24.32-24.96a69.76 69.76 0 0 1-1.92-16.64c0-35.2 28.16-63.36 63.36-63.36 5.76 0 11.52 0.64 16.64 1.92z</StreamGeometry>
|
||||
|
||||
<x:Double x:Key="IconButtonWidth">32</x:Double>
|
||||
<x:Double x:Key="IconButtonHeight">32</x:Double>
|
||||
|
||||
<Thickness x:Key="Margin2">2</Thickness>
|
||||
<Thickness x:Key="MarginLr4">4,0</Thickness>
|
||||
<Thickness x:Key="Margin4">4</Thickness>
|
||||
<Thickness x:Key="MarginLr8">8,0</Thickness>
|
||||
<Thickness x:Key="MarginTb8">0,8</Thickness>
|
||||
<Thickness x:Key="Margin8">8</Thickness>
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -5,22 +5,12 @@
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="TextBlock.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="DockPanel.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="WrapPanel.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="Grid.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="DataGrid">
|
||||
<Setter Property="RowHeight" Value="24" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="PathIcon">
|
||||
<Setter Property="Width" Value="16" />
|
||||
<Setter Property="Height" Value="16" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
@@ -10,9 +10,9 @@ namespace v2rayN.Desktop.Common
|
||||
var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC");
|
||||
return appBuilder.With(new FontManagerOptions()
|
||||
{
|
||||
DefaultFamilyName = uri,
|
||||
//DefaultFamilyName = uri,
|
||||
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.axaml
Normal file
48
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.axaml
Normal file
@@ -0,0 +1,48 @@
|
||||
<ResourceDictionary
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:v2rayN.Desktop.Controls">
|
||||
<!-- Add Resources Here -->
|
||||
<ControlTheme x:Key="{x:Type controls:AutoCompleteBox}" TargetType="controls:AutoCompleteBox">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="MinHeight" Value="{DynamicResource AutoCompleteBoxDefaultHeight}" />
|
||||
<Setter Property="MaxDropDownHeight" Value="{DynamicResource AutoCompleteMaxDropdownHeight}" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="AutoCompleteBox">
|
||||
<Panel>
|
||||
<TextBox
|
||||
Name="PART_TextBox"
|
||||
MinHeight="{TemplateBinding MinHeight}"
|
||||
VerticalAlignment="Stretch"
|
||||
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
|
||||
InnerLeftContent="{TemplateBinding InnerLeftContent}"
|
||||
InnerRightContent="{TemplateBinding InnerRightContent}"
|
||||
Watermark="{TemplateBinding Watermark}" />
|
||||
<Popup
|
||||
Name="PART_Popup"
|
||||
MaxHeight="{TemplateBinding MaxDropDownHeight}"
|
||||
IsLightDismissEnabled="True"
|
||||
PlacementTarget="{TemplateBinding}">
|
||||
<Border
|
||||
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Margin="{DynamicResource AutoCompleteBoxPopupMargin}"
|
||||
Padding="{DynamicResource AutoCompleteBoxPopupPadding}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{DynamicResource AutoCompleteBoxPopupBackground}"
|
||||
BorderBrush="{DynamicResource AutoCompleteBoxPopupBorderBrush}"
|
||||
BorderThickness="{DynamicResource AutoCompleteBoxPopupBorderThickness}"
|
||||
BoxShadow="{DynamicResource AutoCompleteBoxPopupBoxShadow}"
|
||||
CornerRadius="{DynamicResource AutoCompleteBoxPopupCornerRadius}">
|
||||
<ListBox
|
||||
Name="PART_SelectingItemsControl"
|
||||
Foreground="{TemplateBinding Foreground}"
|
||||
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto" />
|
||||
</Border>
|
||||
</Popup>
|
||||
</Panel>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
38
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.cs
Normal file
38
v2rayN/v2rayN.Desktop/Controls/AutoCompleteBox.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace v2rayN.Desktop.Controls;
|
||||
|
||||
public class AutoCompleteBox : Avalonia.Controls.AutoCompleteBox
|
||||
{
|
||||
static AutoCompleteBox()
|
||||
{
|
||||
MinimumPrefixLengthProperty.OverrideDefaultValue<AutoCompleteBox>(0);
|
||||
}
|
||||
|
||||
public AutoCompleteBox()
|
||||
{
|
||||
AddHandler(PointerPressedEvent, OnBoxPointerPressed, RoutingStrategies.Tunnel);
|
||||
}
|
||||
|
||||
private void OnBoxPointerPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (Equals(sender, this) && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnGotFocus(GotFocusEventArgs e)
|
||||
{
|
||||
base.OnGotFocus(e);
|
||||
if (IsDropDownOpen)
|
||||
return;
|
||||
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
SetCurrentValue(SelectedItemProperty, null);
|
||||
}
|
||||
}
|
||||
91
v2rayN/v2rayN.Desktop/Handler/HotkeyHandler.cs
Normal file
91
v2rayN/v2rayN.Desktop/Handler/HotkeyHandler.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System.Reactive.Linq;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Win32.Input;
|
||||
using GlobalHotKeys;
|
||||
|
||||
namespace v2rayN.Desktop.Handler
|
||||
{
|
||||
public sealed class HotkeyHandler
|
||||
{
|
||||
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||
public static HotkeyHandler Instance = _instance.Value;
|
||||
private readonly Dictionary<int, EGlobalHotkey> _hotkeyTriggerDic = new();
|
||||
private HotKeyManager? _hotKeyManager;
|
||||
|
||||
private Config? _config;
|
||||
|
||||
private event Action<EGlobalHotkey>? _updateFunc;
|
||||
|
||||
public bool IsPause { get; set; } = false;
|
||||
|
||||
public void Init(Config config, Action<EGlobalHotkey> updateFunc)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
Register();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_hotKeyManager?.Dispose();
|
||||
}
|
||||
|
||||
private void Register()
|
||||
{
|
||||
if (_config.GlobalHotkeys.Any(t => t.KeyCode > 0) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_hotKeyManager ??= new GlobalHotKeys.HotKeyManager();
|
||||
_hotkeyTriggerDic.Clear();
|
||||
|
||||
foreach (var item in _config.GlobalHotkeys)
|
||||
{
|
||||
if (item.KeyCode is null or 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||
var modifiers = Modifiers.None;
|
||||
if (item.Control)
|
||||
{
|
||||
modifiers |= Modifiers.Control;
|
||||
}
|
||||
if (item.Shift)
|
||||
{
|
||||
modifiers |= Modifiers.Shift;
|
||||
}
|
||||
if (item.Alt)
|
||||
{
|
||||
modifiers |= Modifiers.Alt;
|
||||
}
|
||||
|
||||
var result = _hotKeyManager?.Register((VirtualKeyCode)vKey, modifiers);
|
||||
if (result?.IsSuccessful == true)
|
||||
{
|
||||
_hotkeyTriggerDic.Add(result.Id, item.EGlobalHotkey);
|
||||
}
|
||||
}
|
||||
|
||||
_hotKeyManager?.HotKeyPressed
|
||||
.ObserveOn(AvaloniaScheduler.Instance)
|
||||
.Subscribe(OnNext);
|
||||
}
|
||||
|
||||
private void OnNext(HotKey key)
|
||||
{
|
||||
if (_updateFunc == null || IsPause)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hotkeyTriggerDic.TryGetValue(key.Id, out var value))
|
||||
{
|
||||
_updateFunc?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.AddServer2Window"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -6,17 +6,17 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="v2rayN"
|
||||
Title="{x:Static resx:ResUI.menuAddCustomServer}"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:DataType="vms:AddServer2ViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
@@ -28,7 +28,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -39,14 +39,14 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
|
||||
<TextBox
|
||||
@@ -54,24 +54,24 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
@@ -80,46 +80,46 @@
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
Margin="2,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
<Button
|
||||
x:Name="btnEdit"
|
||||
Margin="2,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Content="{x:Static resx:ResUI.TbEdit}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
MaxDropDownHeight="1000" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Orientation="Horizontal">
|
||||
<ToggleSwitch
|
||||
x:Name="togDisplayLog"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
||||
</StackPanel>
|
||||
@@ -127,21 +127,21 @@
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPreSocksPort"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin8">
|
||||
Margin="{StaticResource Margin4}">
|
||||
<TextBlock
|
||||
Width="500"
|
||||
VerticalAlignment="Center"
|
||||
@@ -149,7 +149,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Width="500"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.CustomServerTips}"
|
||||
TextWrapping="Wrap" />
|
||||
@@ -157,4 +157,4 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.AddServerWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -13,10 +13,10 @@
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
@@ -28,7 +28,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -44,7 +44,7 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
@@ -53,52 +53,52 @@
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Width="100"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TbCoreType}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPort"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="1" Margin="0,10" />
|
||||
<Separator Grid.Row="1" Margin="{StaticResource MarginTb8}" />
|
||||
|
||||
<Grid
|
||||
x:Name="gridVMess"
|
||||
@@ -110,48 +110,48 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId}" />
|
||||
<TextBox
|
||||
x:Name="txtId"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<Button
|
||||
x:Name="btnGUID"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="4,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Content="{x:Static resx:ResUI.TbGUID}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAlterId}" />
|
||||
<TextBox
|
||||
x:Name="txtAlterId"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSecurity}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSecurity"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridSs"
|
||||
@@ -163,28 +163,28 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId3"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSecurity3}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSecurity3"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridSocks"
|
||||
@@ -196,28 +196,28 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSecurity4}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity4"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId4}" />
|
||||
<TextBox
|
||||
x:Name="txtId4"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridVLESS"
|
||||
@@ -229,48 +229,48 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId5}" />
|
||||
<TextBox
|
||||
x:Name="txtId5"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<Button
|
||||
x:Name="btnGUID5"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="4,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Content="{x:Static resx:ResUI.TbGUID}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbFlow5}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFlow5"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSecurity5}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity5"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTrojan"
|
||||
@@ -282,61 +282,80 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId6"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbFlow5}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFlow6"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridHysteria2"
|
||||
Grid.Row="2"
|
||||
ColumnDefinitions="180,Auto"
|
||||
ColumnDefinitions="180,Auto,Auto"
|
||||
IsVisible="False"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId7"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPath7}" />
|
||||
<TextBox
|
||||
x:Name="txtPath7"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPorts7}" />
|
||||
<TextBox
|
||||
x:Name="txtPorts7"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPorts7Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTuic"
|
||||
@@ -348,41 +367,41 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId}" />
|
||||
<TextBox
|
||||
x:Name="txtId8"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity8"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType8}" />
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType8"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridWireguard"
|
||||
@@ -394,75 +413,75 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPrivateKey}" />
|
||||
<TextBox
|
||||
x:Name="txtId9"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPublicKey}" />
|
||||
<TextBox
|
||||
x:Name="txtPublicKey9"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbReserved}" />
|
||||
<TextBox
|
||||
x:Name="txtPath9"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbLocalAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtRequestHost9"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Mtu" />
|
||||
<TextBox
|
||||
x:Name="txtShortId9"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<Separator
|
||||
x:Name="sepa2"
|
||||
Grid.Row="3"
|
||||
Margin="0,10" />
|
||||
Margin="{StaticResource MarginTb8}" />
|
||||
|
||||
<Grid
|
||||
x:Name="gridTransport"
|
||||
@@ -473,34 +492,34 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.GbTransport}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbNetwork}" />
|
||||
<ComboBox
|
||||
x:Name="cmbNetwork"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TipNetwork}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="labHeaderType"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType}" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
@@ -510,35 +529,32 @@
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnExtra"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="10,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_more}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TransportExtraTip}" />
|
||||
<TextBox
|
||||
x:Name="txtExtra"
|
||||
Width="400"
|
||||
MinHeight="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Classes="TextArea Margin8"
|
||||
Classes="TextArea"
|
||||
MinLines="6"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
@@ -550,52 +566,52 @@
|
||||
x:Name="tipHeaderType"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRequestHost}" />
|
||||
<TextBox
|
||||
x:Name="txtRequestHost"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
x:Name="tipRequestHost"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbRequestHost}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPath}" />
|
||||
<TextBox
|
||||
x:Name="txtPath"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
x:Name="tipPath"
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPath}" />
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="5" Margin="0,10" />
|
||||
<Separator Grid.Row="5" Margin="{StaticResource MarginTb8}" />
|
||||
|
||||
<Grid
|
||||
x:Name="gridTls"
|
||||
@@ -606,15 +622,15 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbStreamSecurity}" />
|
||||
<ComboBox
|
||||
x:Name="cmbStreamSecurity"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTlsMore"
|
||||
@@ -626,55 +642,55 @@
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSNI}" />
|
||||
<TextBox
|
||||
x:Name="txtSNI"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFingerprint"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAlpn}" />
|
||||
<ComboBox
|
||||
x:Name="cmbAlpn"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbAllowInsecure}" />
|
||||
<ComboBox
|
||||
x:Name="cmbAllowInsecure"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
@@ -686,74 +702,74 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSNI}" />
|
||||
<TextBox
|
||||
x:Name="txtSNI2"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFingerprint2"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPublicKey}" />
|
||||
<TextBox
|
||||
x:Name="txtPublicKey"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbShortId}" />
|
||||
<TextBox
|
||||
x:Name="txtShortId"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSpiderX}" />
|
||||
<TextBox
|
||||
x:Name="txtSpiderX"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Separator Grid.Row="8" Margin="0,10" />
|
||||
<Separator Grid.Row="8" Margin="{StaticResource MarginTb8}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -178,6 +178,7 @@ namespace v2rayN.Desktop.Views
|
||||
case EConfigType.Hysteria2:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.TUIC:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.BackupAndRestoreView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -14,90 +14,87 @@
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel Classes="Margin8" DockPanel.Dock="Bottom">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel Margin="{StaticResource Margin4}" DockPanel.Dock="Bottom">
|
||||
<TextBlock
|
||||
Name="txtMsg"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel>
|
||||
<Border
|
||||
Margin="4"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ColumnDefinitions="300,200"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuLocalBackupAndRestore}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuLocalBackup}" />
|
||||
<Button
|
||||
Name="menuLocalBackup"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.menuLocalBackup}" />
|
||||
|
||||
<Separator
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2" />
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource MarginTb8}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuLocalRestore}" />
|
||||
<Button
|
||||
Name="menuLocalRestore"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.menuLocalRestore}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Margin="4"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ColumnDefinitions="300,200"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto">
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Classes="Margin8" Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||
<TextBlock Margin="{StaticResource Margin4}" Text="{x:Static resx:ResUI.menuRemoteBackupAndRestore}" />
|
||||
|
||||
<Button
|
||||
Width="30"
|
||||
Height="30"
|
||||
MinWidth="30"
|
||||
Margin="10,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
MinWidth="{StaticResource IconButtonWidth}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_more}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
@@ -107,7 +104,7 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvWebDavUrl}" />
|
||||
|
||||
<TextBox
|
||||
@@ -115,14 +112,14 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvWebDavUserName}" />
|
||||
|
||||
<TextBox
|
||||
@@ -130,13 +127,13 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvWebDavPassword}" />
|
||||
|
||||
<TextBox
|
||||
@@ -144,13 +141,13 @@
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvWebDavDirName}" />
|
||||
|
||||
<TextBox
|
||||
@@ -158,7 +155,7 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<Button
|
||||
x:Name="menuWebDavCheck"
|
||||
@@ -166,7 +163,7 @@
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.LvWebDavCheck}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
@@ -180,35 +177,36 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuRemoteBackup}" />
|
||||
<Button
|
||||
Name="menuRemoteBackup"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.menuRemoteBackup}" />
|
||||
|
||||
<Separator
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2" />
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="{StaticResource MarginTb8}" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuRemoteRestore}" />
|
||||
<Button
|
||||
Name="menuRemoteRestore"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.menuRemoteRestore}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.CheckUpdateView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -11,40 +11,45 @@
|
||||
x:DataType="vms:CheckUpdateViewModel"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<Border
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
|
||||
<TextBlock
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableCheckPreReleaseUpdate}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableCheckPreReleaseUpdate"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<Button
|
||||
x:Name="btnCheckUpdate"
|
||||
Width="100"
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.menuCheckUpdate}" />
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableCheckPreReleaseUpdate}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableCheckPreReleaseUpdate"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<Button
|
||||
x:Name="btnCheckUpdate"
|
||||
Width="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.menuCheckUpdate}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Margin="4"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Theme="{DynamicResource CardBorder}">
|
||||
|
||||
<ListBox
|
||||
x:Name="lstCheckUpdates"
|
||||
BorderThickness="1"
|
||||
ItemsSource="{Binding CheckUpdateModels}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
ItemsSource="{Binding CheckUpdateModels}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
@@ -57,7 +62,7 @@
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Grid.Column="0"
|
||||
Margin="8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IsChecked="{Binding IsSelected}" />
|
||||
@@ -79,4 +84,4 @@
|
||||
</ListBox>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -14,59 +14,51 @@
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBox
|
||||
x:Name="txtHostFilter"
|
||||
Width="200"
|
||||
Margin="8,0"
|
||||
VerticalContentAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Watermark="{x:Static resx:ResUI.ConnectionsHostFilterTitle}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnConnectionCloseAll"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Classes="Success"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_delete}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_delete}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="btnAutofitColumnWidth"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Classes="Success"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_fit}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_fit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left" />
|
||||
HorizontalAlignment="Left"
|
||||
Margin="{StaticResource MarginLr8}" />
|
||||
</WrapPanel>
|
||||
|
||||
<DataGrid
|
||||
@@ -108,4 +100,4 @@
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -17,32 +17,32 @@
|
||||
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.menuRulemode}" />
|
||||
<ComboBox
|
||||
x:Name="cmbRulemode"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
Margin="{StaticResource MarginLr8}">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeRule}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeGlobal}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuModeDirect}" />
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSorting"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
Margin="{StaticResource MarginLr8}">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDefault}" />
|
||||
@@ -50,53 +50,44 @@
|
||||
|
||||
<Button
|
||||
x:Name="menuProxiesReload"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesReload}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_refresh}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_refresh}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="menuProxiesDelaytest"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesDelaytest}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_ping}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_ping}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
HorizontalAlignment="Left" />
|
||||
</WrapPanel>
|
||||
<DockPanel>
|
||||
<ListBox
|
||||
x:Name="lstProxyGroups"
|
||||
DockPanel.Dock="Left"
|
||||
ItemsSource="{Binding ProxyGroups}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
ItemsSource="{Binding ProxyGroups}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
@@ -104,27 +95,24 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
<Label
|
||||
Width="160"
|
||||
Margin="-8,-4"
|
||||
Margin="-4,-6"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
Theme="{DynamicResource TagLabel}">
|
||||
<Grid Margin="{StaticResource Margin4}" RowDefinitions="1*,8,1*">
|
||||
<DockPanel Grid.Row="0">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding Type}" />
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
</DockPanel>
|
||||
<TextBlock Grid.Row="2" Text="{Binding Now}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Label>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<ListBox
|
||||
x:Name="lstProxyDetails"
|
||||
ItemsSource="{Binding ProxyDetails}"
|
||||
Theme="{StaticResource ButtonRadioGroupListBox}">
|
||||
<ListBox x:Name="lstProxyDetails" ItemsSource="{Binding ProxyDetails}">
|
||||
<ItemsControl.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
|
||||
@@ -138,11 +126,11 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
<Label
|
||||
Width="160"
|
||||
Margin="-12,-4"
|
||||
Margin="-10,-6"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
Theme="{DynamicResource TagLabel}">
|
||||
<DockPanel>
|
||||
<Border
|
||||
Width="5"
|
||||
@@ -151,7 +139,7 @@
|
||||
CornerRadius="4"
|
||||
DockPanel.Dock="Left"
|
||||
IsVisible="{Binding IsActive}" />
|
||||
<Grid Classes="Margin8" RowDefinitions="1*,8,1*">
|
||||
<Grid Margin="{StaticResource Margin4}" RowDefinitions="1*,8,1*">
|
||||
<TextBlock Grid.Row="0" Text="{Binding Name}" />
|
||||
<DockPanel Grid.Row="2">
|
||||
<TextBlock
|
||||
@@ -162,10 +150,10 @@
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Label>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.DNSSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -13,10 +13,10 @@
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
@@ -28,7 +28,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -36,21 +36,21 @@
|
||||
|
||||
<TabControl HorizontalContentAlignment="Left">
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Classes="Margin8">
|
||||
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
||||
<HyperlinkButton Classes="WithIcon" Click="linkDnsObjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
|
||||
</HyperlinkButton>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4V2ray"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
@@ -58,44 +58,45 @@
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togUseSystemHosts"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Freedom"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainDNSAddress"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Classes="Margin8">
|
||||
<Grid Margin="{StaticResource Margin4}">
|
||||
<TextBox
|
||||
x:Name="txtnormalDNS"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
Classes="TextArea"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="HTTP/SOCKS" />
|
||||
</Grid>
|
||||
@@ -103,16 +104,16 @@
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Classes="Margin8">
|
||||
<TextBlock Margin="{StaticResource Margin4}" VerticalAlignment="Center">
|
||||
<HyperlinkButton Classes="WithIcon" Click="linkDnsSingboxObjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
|
||||
</HyperlinkButton>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4Singbox"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
@@ -120,28 +121,28 @@
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Out"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainDNSAddress2"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Classes="Margin8" ColumnDefinitions="*,10,*">
|
||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="*,10,*">
|
||||
|
||||
<TextBox
|
||||
x:Name="txtnormalDNS2"
|
||||
@@ -150,7 +151,8 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
Classes="TextArea"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="HTTP/SOCKS" />
|
||||
|
||||
@@ -163,7 +165,8 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
Classes="TextArea"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
||||
</Grid>
|
||||
@@ -171,4 +174,4 @@
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.GlobalHotkeySettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -6,23 +6,23 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuSetting}"
|
||||
Title="{x:Static resx:ResUI.menuGlobalHotkeySetting}"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:DataType="vms:SubEditViewModel"
|
||||
x:DataType="vms:GlobalHotkeySettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnReset"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbReset}" />
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
@@ -33,7 +33,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -49,85 +49,85 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbGlobalHotkeySetting}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbDisplayGUI}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbClearSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey1"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSetSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey2"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbNotChangeSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey3"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSystemProxyPac}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsReadOnly="True" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbGlobalHotkeySettingTip}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -1,129 +1,138 @@
|
||||
using Avalonia.Controls;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Text;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Handler;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class GlobalHotkeySettingWindow : Window
|
||||
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||
{
|
||||
private static Config _config = default!;
|
||||
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
|
||||
private readonly List<object> _textBoxKeyEventItem = new();
|
||||
|
||||
public GlobalHotkeySettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||
|
||||
btnReset.Click += btnReset_Click;
|
||||
|
||||
HotkeyHandler.Instance.IsPause = true;
|
||||
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = AppHandler.Instance.Config;
|
||||
//_config.globalHotkeys ??= new List<KeyEventItem>();
|
||||
|
||||
//txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
//txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
//txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
//txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
//txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
//HotkeyHandler.Instance.IsPause = true;
|
||||
//this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
//InitData();
|
||||
Init();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
//private void InitData()
|
||||
//{
|
||||
// _TextBoxKeyEventItem = new()
|
||||
// {
|
||||
// { txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.ShowForm) },
|
||||
// { txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyClear) },
|
||||
// { txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxySet) },
|
||||
// { txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyUnchanged)},
|
||||
// { txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.globalHotkeys,EGlobalHotkey.SystemProxyPac)}
|
||||
// };
|
||||
// BindingData();
|
||||
//}
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
//private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||
//{
|
||||
// e.Handled = true;
|
||||
// var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
|
||||
// Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
|
||||
// _TextBoxKeyEventItem[sender].KeyCode = (int)(e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key));
|
||||
// _TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
|
||||
// _TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
|
||||
// _TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||
// (sender as TextBox)!.Text = KeyEventItemToString(_TextBoxKeyEventItem[sender]);
|
||||
//}
|
||||
private void Init()
|
||||
{
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||
|
||||
//private KeyEventItem GetKeyEventItemByEGlobalHotkey(List<KeyEventItem> KEList, EGlobalHotkey eg)
|
||||
//{
|
||||
// return JsonUtils.DeepCopy(KEList.Find((it) => it.eGlobalHotkey == eg) ?? new()
|
||||
// {
|
||||
// eGlobalHotkey = eg,
|
||||
// Control = false,
|
||||
// Alt = false,
|
||||
// Shift = false,
|
||||
// KeyCode = null
|
||||
// });
|
||||
//}
|
||||
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||
{
|
||||
var sender = _textBoxKeyEventItem[index];
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
txtBox.Tag = (EGlobalHotkey)index;
|
||||
txtBox.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
|
||||
//private string KeyEventItemToString(KeyEventItem item)
|
||||
//{
|
||||
// var res = new StringBuilder();
|
||||
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if (item.Control) res.Append($"{ModifierKeys.Control}+");
|
||||
// if (item.Shift) res.Append($"{ModifierKeys.Shift}+");
|
||||
// if (item.Alt) res.Append($"{ModifierKeys.Alt}+");
|
||||
// if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
// res.Append($"{(Key)item.KeyCode}");
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||
|
||||
// return res.ToString();
|
||||
//}
|
||||
item.KeyCode = (int)(e.Key == Key.System ? modifierKeys.Contains(Key.System) ? Key.None : Key.System : modifierKeys.Contains(e.Key) ? Key.None : e.Key);
|
||||
item.Alt = (e.KeyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt;
|
||||
item.Control = (e.KeyModifiers & KeyModifiers.Control) == KeyModifiers.Control;
|
||||
item.Shift = (e.KeyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift;
|
||||
|
||||
//private void BindingData()
|
||||
//{
|
||||
// foreach (var item in _TextBoxKeyEventItem)
|
||||
// {
|
||||
// if (item.Value.KeyCode != null && (Key)item.Value.KeyCode != Key.None)
|
||||
// {
|
||||
// (item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// (item.Key as TextBox)!.Text = string.Empty;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
|
||||
//private void btnSave_Click(object? sender, RoutedEventArgs e)
|
||||
//{
|
||||
// _config.globalHotkeys = _TextBoxKeyEventItem.Values.ToList();
|
||||
private void BindingData()
|
||||
{
|
||||
foreach (var sender in _textBoxKeyEventItem)
|
||||
{
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (ConfigHandler.SaveConfig(_config, false) == 0)
|
||||
// {
|
||||
// HotkeyHandler.Instance.ReLoad();
|
||||
// this.Close();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// UI.Show(ResUI.OperationFailed);
|
||||
// }
|
||||
//}
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
}
|
||||
|
||||
//private void btnReset_Click(object? sender, RoutedEventArgs e)
|
||||
//{
|
||||
// foreach (var k in _TextBoxKeyEventItem.Keys)
|
||||
// {
|
||||
// _TextBoxKeyEventItem[k].Alt = false;
|
||||
// _TextBoxKeyEventItem[k].Control = false;
|
||||
// _TextBoxKeyEventItem[k].Shift = false;
|
||||
// _TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
|
||||
// }
|
||||
// BindingData();
|
||||
//}
|
||||
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ResetKeyEventItem();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
//private void GlobalHotkeySettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
//{
|
||||
// if (e.Key == Key.Escape)
|
||||
// {
|
||||
// this.Close();
|
||||
// }
|
||||
//}
|
||||
private string KeyEventItemToString(KeyEventItem? item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var res = new StringBuilder();
|
||||
|
||||
if (item.Control)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Control} +");
|
||||
}
|
||||
|
||||
if (item.Shift)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Shift} +");
|
||||
}
|
||||
|
||||
if (item.Alt)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Alt} +");
|
||||
}
|
||||
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
{
|
||||
res.Append($"{(Key)item.KeyCode}");
|
||||
}
|
||||
|
||||
return res.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
CloseOnClickAway="True"
|
||||
DisableOpeningAnimation="True">
|
||||
<DockPanel>
|
||||
<DockPanel Classes="Margin8" DockPanel.Dock="Top">
|
||||
<DockPanel Margin="{StaticResource Margin8}" DockPanel.Dock="Top">
|
||||
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
|
||||
<Menu Margin="0,1">
|
||||
<MenuItem Padding="8,0">
|
||||
|
||||
@@ -12,6 +12,7 @@ using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using v2rayN.Desktop.Common;
|
||||
using v2rayN.Desktop.Handler;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
@@ -138,8 +139,7 @@ namespace v2rayN.Desktop.Views
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||
|
||||
menuGlobalHotkeySetting.IsVisible = false;
|
||||
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -156,7 +156,6 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
RestoreUI();
|
||||
AddHelpMenuItem();
|
||||
//WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||
}
|
||||
|
||||
@@ -233,6 +232,7 @@ namespace v2rayN.Desktop.Views
|
||||
StorageUI();
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
HotkeyHandler.Instance.Dispose();
|
||||
desktop.Shutdown();
|
||||
}
|
||||
break;
|
||||
@@ -247,7 +247,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
case EViewAction.AddServerViaClipboard:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.AdjustMainLvColWidth:
|
||||
@@ -268,21 +271,12 @@ namespace v2rayN.Desktop.Views
|
||||
ShowHideWindow(null);
|
||||
break;
|
||||
|
||||
//case EGlobalHotkey.SystemProxyClear:
|
||||
// ViewModel?.SetListenerType(ESysProxyType.ForcedClear);
|
||||
// break;
|
||||
|
||||
//case EGlobalHotkey.SystemProxySet:
|
||||
// ViewModel?.SetListenerType(ESysProxyType.ForcedChange);
|
||||
// break;
|
||||
|
||||
//case EGlobalHotkey.SystemProxyUnchanged:
|
||||
// ViewModel?.SetListenerType(ESysProxyType.Unchanged);
|
||||
// break;
|
||||
|
||||
//case EGlobalHotkey.SystemProxyPac:
|
||||
// ViewModel?.SetListenerType(ESysProxyType.Pac);
|
||||
// break;
|
||||
case EGlobalHotkey.SystemProxyClear:
|
||||
case EGlobalHotkey.SystemProxySet:
|
||||
case EGlobalHotkey.SystemProxyUnchanged:
|
||||
case EGlobalHotkey.SystemProxyPac:
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.SetListenerType((ESysProxyType)((int)e - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,7 +297,10 @@ namespace v2rayN.Desktop.Views
|
||||
break;
|
||||
|
||||
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
|
||||
await ViewModel?.MyAppExitAsync(true);
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -318,7 +315,10 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
case Key.V:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
break;
|
||||
|
||||
case Key.S:
|
||||
@@ -367,7 +367,11 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
return;
|
||||
}
|
||||
await ViewModel?.ScanImageResult(fileName);
|
||||
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.ScanImageResult(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuCheckUpdate_Click(object? sender, RoutedEventArgs e)
|
||||
@@ -391,8 +395,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
_blCloseByUser = true;
|
||||
StorageUI();
|
||||
|
||||
await ViewModel?.MyAppExitAsync(false);
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Event
|
||||
@@ -414,18 +420,17 @@ namespace v2rayN.Desktop.Views
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utils.IsOSX() || _config.UiItem.Hide2TrayWhenClose)
|
||||
{
|
||||
foreach (var ownedWindow in this.OwnedWindows)
|
||||
{
|
||||
ownedWindow.Close();
|
||||
}
|
||||
this.Hide();
|
||||
}
|
||||
else
|
||||
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var ownedWindow in this.OwnedWindows)
|
||||
{
|
||||
ownedWindow.Close();
|
||||
}
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
_config.UiItem.ShowInTaskbar = bl;
|
||||
|
||||
@@ -10,80 +10,72 @@
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBox
|
||||
x:Name="cmbMsgFilter"
|
||||
Width="200"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalContentAlignment="Center"
|
||||
Watermark="{x:Static resx:ResUI.MsgFilterTitle}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnCopy"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Classes="Success"
|
||||
Click="menuMsgViewCopyAll_Click"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewCopyAll}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_copy}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_copy}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="btnClear"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="8,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Classes="Success"
|
||||
Click="menuMsgViewClear_Click"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewClear}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_delete}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_delete}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True"
|
||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoScrollToEnd}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togScrollToEnd"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True"
|
||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||
</WrapPanel>
|
||||
<TextBox
|
||||
Name="txtMsg"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="0"
|
||||
Classes="TextArea"
|
||||
IsReadOnly="True"
|
||||
TextAlignment="Left"
|
||||
VerticalAlignment="Stretch"
|
||||
TextWrapping="Wrap">
|
||||
<TextBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
@@ -107,4 +99,4 @@
|
||||
</TextBox.ContextMenu>
|
||||
</TextBox>
|
||||
</DockPanel>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -74,18 +74,11 @@ namespace v2rayN.Desktop.Views
|
||||
{
|
||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||
}
|
||||
Global.SpeedTestUrls.ForEach(it =>
|
||||
{
|
||||
cmbSpeedTestUrl.Items.Add(it);
|
||||
});
|
||||
Global.SpeedPingTestUrls.ForEach(it =>
|
||||
{
|
||||
cmbSpeedPingTestUrl.Items.Add(it);
|
||||
});
|
||||
Global.SubConvertUrls.ForEach(it =>
|
||||
{
|
||||
cmbSubConvertUrl.Items.Add(it);
|
||||
});
|
||||
|
||||
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||
|
||||
Global.GeoFilesSources.ForEach(it =>
|
||||
{
|
||||
cmbGetFilesSourceUrl.Items.Add(it);
|
||||
@@ -139,12 +132,12 @@ namespace v2rayN.Desktop.Views
|
||||
this.Bind(ViewModel, vm => vm.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MixedConcurrencyCount, v => v.cmbMixedConcurrencyCount.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
@@ -174,15 +167,27 @@ namespace v2rayN.Desktop.Views
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
txbSettingsExceptionTip2.IsVisible = false;
|
||||
|
||||
txtLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPasswordTip.IsVisible = false;
|
||||
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
}
|
||||
else
|
||||
else if (Utils.IsLinux())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
}
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
@@ -203,8 +208,9 @@ namespace v2rayN.Desktop.Views
|
||||
private async Task InitSettingFont()
|
||||
{
|
||||
var lstFonts = await GetFonts();
|
||||
lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
||||
cmbcurrentFontFamily.Items.Add(string.Empty);
|
||||
|
||||
lstFonts.Add(string.Empty);
|
||||
cmbcurrentFontFamily.ItemsSource = lstFonts;
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetFonts()
|
||||
@@ -242,7 +248,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,65 +19,59 @@
|
||||
<WrapPanel Margin="2" DockPanel.Dock="Top">
|
||||
<ListBox
|
||||
x:Name="lstGroup"
|
||||
MaxHeight="200"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
DisplayMemberBinding="{Binding Remarks}"
|
||||
ItemsSource="{Binding SubItems}"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
</ListBox>
|
||||
|
||||
<Button
|
||||
x:Name="btnEditSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubEdit}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
Data="{StaticResource building_edit}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_edit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="btnAddSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubAdd}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
Data="{StaticResource building_add}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_add}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="btnAutofitColumnWidth"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource BorderlessButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="24"
|
||||
Height="24"
|
||||
Data="{StaticResource building_fit}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_fit}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBox
|
||||
x:Name="txtServerFilter"
|
||||
Width="200"
|
||||
Margin="4,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
VerticalContentAlignment="Center"
|
||||
Watermark="{x:Static resx:ResUI.MsgServerTitle}" />
|
||||
</WrapPanel>
|
||||
@@ -85,11 +79,13 @@
|
||||
x:Name="lstProfiles"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
CanUserReorderColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="All"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding ProfileItems}">
|
||||
ItemsSource="{Binding ProfileItems}"
|
||||
ScrollViewer.AllowAutoHide="False">
|
||||
<DataGrid.KeyBindings>
|
||||
<KeyBinding Command="{Binding Export2ShareUrlCmd}" Gesture="Ctrl+C" />
|
||||
<KeyBinding Command="{Binding SetDefaultServerCmd}" Gesture="Enter" />
|
||||
@@ -161,9 +157,9 @@
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Margin="8,0" Orientation="Horizontal">
|
||||
<StackPanel Margin="{StaticResource MarginLr8}" Orientation="Horizontal">
|
||||
<Label
|
||||
Margin="0,0,8,0"
|
||||
Margin="{StaticResource MarginLr4}"
|
||||
Classes="Solid Red"
|
||||
Content="{x:Static resx:ResUI.TipActiveServer}"
|
||||
IsVisible="{Binding IsActive}"
|
||||
@@ -209,7 +205,7 @@
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{Binding Delay, Converter={StaticResource DelayColorConverter}}"
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace v2rayN.Desktop.Views
|
||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||
|
||||
|
||||
//servers export
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
||||
@@ -102,11 +102,16 @@ namespace v2rayN.Desktop.Views
|
||||
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
await ViewModel?.SortServer(e.Column.Tag.ToString());
|
||||
|
||||
if (ViewModel != null && e.Column?.Tag?.ToString() != null)
|
||||
{
|
||||
await ViewModel.SortServer(e.Column.Tag.ToString());
|
||||
}
|
||||
|
||||
e.Handled = false;
|
||||
}
|
||||
|
||||
//#region Event
|
||||
#region Event
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
@@ -179,7 +184,9 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshServersBiz(),
|
||||
{
|
||||
_ = RefreshServersBiz();
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
@@ -198,9 +205,25 @@ namespace v2rayN.Desktop.Views
|
||||
await DialogHost.Show(dialog);
|
||||
}
|
||||
|
||||
public async Task RefreshServersBiz()
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.RefreshServersBiz();
|
||||
}
|
||||
|
||||
if (lstProfiles.SelectedIndex > 0)
|
||||
{
|
||||
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
@@ -333,9 +356,9 @@ namespace v2rayN.Desktop.Views
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion Event
|
||||
#endregion Event
|
||||
|
||||
//#region UI
|
||||
#region UI
|
||||
|
||||
private void RestoreUI()
|
||||
{
|
||||
@@ -372,9 +395,8 @@ namespace v2rayN.Desktop.Views
|
||||
private void StorageUI(string? n = null)
|
||||
{
|
||||
List<ColumnItem> lvColumnItem = new();
|
||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
||||
foreach (var item2 in lstProfiles.Columns)
|
||||
{
|
||||
var item2 = lstProfiles.Columns[k];
|
||||
if (item2.Tag == null)
|
||||
{
|
||||
continue;
|
||||
@@ -389,9 +411,9 @@ namespace v2rayN.Desktop.Views
|
||||
_config.UiItem.MainColumnItem = lvColumnItem;
|
||||
}
|
||||
|
||||
//#endregion UI
|
||||
#endregion UI
|
||||
|
||||
//#region Drag and Drop
|
||||
#region Drag and Drop
|
||||
|
||||
//private Point startPoint = new();
|
||||
//private int startIndex = -1;
|
||||
@@ -481,6 +503,6 @@ namespace v2rayN.Desktop.Views
|
||||
// }
|
||||
//}
|
||||
|
||||
//#endregion Drag and Drop
|
||||
#endregion Drag and Drop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.QrcodeView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -7,7 +7,7 @@
|
||||
d:DesignHeight="480"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="30" RowDefinitions="Auto,Auto">
|
||||
<Grid Margin="32" RowDefinitions="Auto,Auto">
|
||||
<Image
|
||||
Name="imgQrcode"
|
||||
Width="300"
|
||||
@@ -17,10 +17,11 @@
|
||||
x:Name="txtContent"
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Margin="0,8"
|
||||
MaxHeight="100"
|
||||
Margin="{StaticResource MarginTb8}"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True"
|
||||
MaxLines="1" />
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
@@ -17,7 +18,7 @@ namespace v2rayN.Desktop.Views
|
||||
txtContent.Text = url;
|
||||
imgQrcode.Source = GetQRCode(url);
|
||||
|
||||
// btnCancel.Click += (s, e) => this.Close();
|
||||
txtContent.GotFocus += (_, _) => Dispatcher.UIThread.Post(() => { txtContent.SelectAll(); });
|
||||
}
|
||||
|
||||
private Bitmap? GetQRCode(string? url)
|
||||
@@ -29,7 +30,9 @@ namespace v2rayN.Desktop.Views
|
||||
private Bitmap? ByteToBitmap(byte[]? bytes)
|
||||
{
|
||||
if (bytes is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var ms = new MemoryStream(bytes);
|
||||
return new Bitmap(ms);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -15,7 +15,7 @@
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
@@ -23,7 +23,7 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
@@ -31,39 +31,39 @@
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnabled"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="outboundTag" />
|
||||
<ComboBox
|
||||
x:Name="cmbOutboundTag"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
MaxDropDownHeight="1000" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="port" />
|
||||
<TextBox
|
||||
x:Name="txtPort"
|
||||
@@ -71,12 +71,12 @@
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8">
|
||||
Margin="{StaticResource Margin4}">
|
||||
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
||||
</HyperlinkButton>
|
||||
@@ -86,14 +86,14 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="protocol" />
|
||||
<ListBox
|
||||
x:Name="clbProtocol"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
SelectionMode="Multiple,Toggle"
|
||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||
|
||||
@@ -101,20 +101,20 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="inboundTag" />
|
||||
<ListBox
|
||||
x:Name="clbInboundTag"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
SelectionMode="Multiple,Toggle"
|
||||
Theme="{DynamicResource CardCheckGroupListBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
|
||||
|
||||
|
||||
@@ -122,26 +122,26 @@
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="network" />
|
||||
<ComboBox
|
||||
x:Name="cmbNetwork"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
MaxDropDownHeight="1000" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<StackPanel
|
||||
@@ -161,13 +161,13 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Classes="Margin8" ColumnDefinitions="1*,10,1*,10,1*">
|
||||
<Grid Margin="{StaticResource Margin4}" ColumnDefinitions="1*,10,1*,10,1*">
|
||||
<HeaderedContentControl
|
||||
Grid.Column="0"
|
||||
BorderBrush="Gray"
|
||||
@@ -208,4 +208,4 @@
|
||||
</HeaderedContentControl>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -85,12 +85,18 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingRuleSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -15,7 +15,7 @@
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
<Menu>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
@@ -40,14 +40,14 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ColumnDefinitions="Auto,Auto,Auto"
|
||||
DockPanel.Dock="Top"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
|
||||
@@ -55,7 +55,7 @@
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
@@ -69,25 +69,25 @@
|
||||
Width="300"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
@@ -96,22 +96,22 @@
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Singbox"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtUrl"
|
||||
@@ -120,7 +120,7 @@
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!--
|
||||
@@ -128,7 +128,7 @@
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||
<TextBox
|
||||
x:Name="txtCustomIcon"
|
||||
@@ -137,13 +137,13 @@
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowseCustomIcon"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
-->
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8">
|
||||
Margin="{StaticResource Margin4}">
|
||||
<HyperlinkButton Classes="WithIcon" Click="linkCustomRulesetPath4Singbox">
|
||||
<TextBlock Text="{x:Static resx:ResUI.LvCustomRulesetPath4Singbox}" />
|
||||
</HyperlinkButton>
|
||||
@@ -163,13 +163,13 @@
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowseCustomRulesetPath4Singbox"
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
</Grid>
|
||||
|
||||
@@ -242,4 +242,4 @@
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -167,7 +167,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRules_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<DockPanel>
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal"
|
||||
Spacing="4">
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<StackPanel
|
||||
@@ -63,7 +63,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -123,4 +123,4 @@
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
</Window>
|
||||
|
||||
@@ -108,7 +108,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
x:DataType="vms:StatusBarViewModel"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<DockPanel Margin="4">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
DockPanel.Dock="Right">
|
||||
<TextBlock x:Name="txtSpeedProxyDisplay" HorizontalAlignment="Right" />
|
||||
<Border Margin="1" />
|
||||
@@ -22,8 +22,8 @@
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
DockPanel.Dock="Left">
|
||||
<TextBlock x:Name="txtInboundDisplay" />
|
||||
<Border Margin="1" />
|
||||
@@ -32,30 +32,30 @@
|
||||
|
||||
<StackPanel
|
||||
x:Name="spEnableTun"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
DockPanel.Dock="Left"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Text="{x:Static resx:ResUI.TbEnableTunAs}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableTun"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Theme="{DynamicResource SimpleToggleSwitch}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
DockPanel.Dock="Left"
|
||||
Orientation="Horizontal">
|
||||
<ComboBox
|
||||
x:Name="cmbSystemProxy"
|
||||
Width="160"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSystemproxy}">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||
@@ -66,13 +66,13 @@
|
||||
<ComboBox
|
||||
x:Name="cmbRoutings2"
|
||||
Width="160"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
DisplayMemberBinding="{Binding Remarks}"
|
||||
ItemsSource="{Binding RoutingItems}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuRouting}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="8,0" VerticalAlignment="Center">
|
||||
<StackPanel VerticalAlignment="Center" Margin="{StaticResource MarginLr8}">
|
||||
<TextBlock x:Name="txtRunningServerDisplay" />
|
||||
<Border Margin="1" />
|
||||
<TextBlock x:Name="txtRunningInfoDisplay" />
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
@@ -27,7 +27,7 @@
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand"
|
||||
IsCancel="True" />
|
||||
@@ -39,66 +39,63 @@
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Text="{x:Static resx:ResUI.menuSubscription}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtUrl"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
<Button
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="10,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_more}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvMoreUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtMoreUrl"
|
||||
Width="400"
|
||||
MinHeight="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Classes="TextArea Margin8"
|
||||
Classes="TextArea"
|
||||
MinLines="4"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
@@ -110,150 +107,148 @@
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvEnabled}" />
|
||||
|
||||
<DockPanel
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8">
|
||||
Margin="{StaticResource Margin4}">
|
||||
<ToggleSwitch
|
||||
x:Name="togEnable"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Left" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtAutoUpdateInterval"
|
||||
Width="100"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Right"
|
||||
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
|
||||
</DockPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvConvertTarget}" />
|
||||
<ComboBox
|
||||
x:Name="cmbConvertTarget"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.LvConvertTargetTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvUserAgent}" />
|
||||
<TextBox
|
||||
x:Name="txtUserAgent"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
TextWrapping="Wrap"
|
||||
Watermark="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvPrevProfile}" />
|
||||
<TextBox
|
||||
x:Name="txtPrevProfile"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Watermark="{x:Static resx:ResUI.LvPrevProfileTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvNextProfile}" />
|
||||
<TextBox
|
||||
x:Name="txtNextProfile"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Watermark="{x:Static resx:ResUI.LvPrevProfileTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Margin="4"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbPreSocksPort4Sub}" />
|
||||
<TextBox
|
||||
x:Name="txtPreSocksPort"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Margin="4"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TipPreSocksPort}"
|
||||
Watermark="{x:Static resx:ResUI.TipPreSocksPort}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.LvMemo}" />
|
||||
<TextBox
|
||||
x:Name="txtMemo"
|
||||
Grid.Row="12"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Window
|
||||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.SubSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -19,9 +19,9 @@
|
||||
CloseOnClickAway="True"
|
||||
DisableOpeningAnimation="True"
|
||||
Identifier="dialogHostSub">
|
||||
<DockPanel Classes="Margin8">
|
||||
<DockPanel Margin="{StaticResource Margin8}">
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
Margin="{StaticResource Margin4}"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
<Menu>
|
||||
|
||||
@@ -84,7 +84,10 @@ namespace v2rayN.Desktop.Views
|
||||
|
||||
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.ThemeSettingView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -20,52 +20,48 @@
|
||||
</UserControl.Styles>
|
||||
|
||||
<Button
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="10,0"
|
||||
Width="{StaticResource IconButtonWidth}"
|
||||
Height="{StaticResource IconButtonHeight}"
|
||||
Margin="{StaticResource MarginLr8}"
|
||||
Theme="{DynamicResource BorderlessButton}">
|
||||
<Button.Content>
|
||||
<PathIcon
|
||||
Width="20"
|
||||
Height="20"
|
||||
Data="{StaticResource building_more}"
|
||||
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
<PathIcon Data="{StaticResource building_more}" Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel Margin="0,12">
|
||||
<StackPanel Margin="{StaticResource MarginTb8}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsTheme}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentTheme"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsFontSize}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentFontSize"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLanguage}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentLanguage"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin8" />
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectCapability Include="Avalonia" />
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
<ProjectReference Include="..\GlobalHotKeys\src\GlobalHotKeys\GlobalHotKeys.csproj" />
|
||||
<ProjectReference Include="..\ServiceLib\ServiceLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN.Desktop", "v2rayN.De
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AmazTool", "AmazTool\AmazTool.csproj", "{47D68B1C-601C-4C69-873B-FFF0DC13EC97}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GlobalHotKeys", "GlobalHotKeys\src\GlobalHotKeys\GlobalHotKeys.csproj", "{CB3DE54F-3A26-AE02-1299-311132C32156}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -33,6 +35,10 @@ Global
|
||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CB3DE54F-3A26-AE02-1299-311132C32156}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CB3DE54F-3A26-AE02-1299-311132C32156}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -11,15 +11,8 @@ namespace v2rayN.Handler
|
||||
{
|
||||
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||
public static HotkeyHandler Instance = _instance.Value;
|
||||
|
||||
private const int WmHotkey = 0x0312;
|
||||
|
||||
private Config _config
|
||||
{
|
||||
get => AppHandler.Instance.Config;
|
||||
}
|
||||
|
||||
private Dictionary<int, List<EGlobalHotkey>> _hotkeyTriggerDic;
|
||||
private readonly Dictionary<int, List<EGlobalHotkey>> _hotkeyTriggerDic = new();
|
||||
|
||||
public bool IsPause { get; set; } = false;
|
||||
|
||||
@@ -29,7 +22,6 @@ namespace v2rayN.Handler
|
||||
|
||||
public HotkeyHandler()
|
||||
{
|
||||
_hotkeyTriggerDic = new();
|
||||
ComponentDispatcher.ThreadPreprocessMessage += OnThreadPreProcessMessage;
|
||||
Init();
|
||||
}
|
||||
@@ -37,20 +29,27 @@ namespace v2rayN.Handler
|
||||
private void Init()
|
||||
{
|
||||
_hotkeyTriggerDic.Clear();
|
||||
if (_config.GlobalHotkeys == null)
|
||||
return;
|
||||
foreach (var item in _config.GlobalHotkeys)
|
||||
foreach (var item in AppHandler.Instance.Config.GlobalHotkeys)
|
||||
{
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
{
|
||||
int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||
KeyModifiers modifiers = KeyModifiers.None;
|
||||
var key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||
var modifiers = KeyModifiers.None;
|
||||
if (item.Control)
|
||||
{
|
||||
modifiers |= KeyModifiers.Ctrl;
|
||||
}
|
||||
|
||||
if (item.Shift)
|
||||
{
|
||||
modifiers |= KeyModifiers.Shift;
|
||||
}
|
||||
|
||||
if (item.Alt)
|
||||
{
|
||||
modifiers |= KeyModifiers.Alt;
|
||||
}
|
||||
|
||||
key = (key << 16) | (int)modifiers;
|
||||
if (!_hotkeyTriggerDic.ContainsKey(key))
|
||||
{
|
||||
@@ -59,7 +58,9 @@ namespace v2rayN.Handler
|
||||
else
|
||||
{
|
||||
if (!_hotkeyTriggerDic[key].Contains(item.EGlobalHotkey))
|
||||
{
|
||||
_hotkeyTriggerDic[key].Add(item.EGlobalHotkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,8 +71,8 @@ namespace v2rayN.Handler
|
||||
foreach (var _hotkeyCode in _hotkeyTriggerDic.Keys)
|
||||
{
|
||||
var hotkeyInfo = GetHotkeyInfo(_hotkeyCode);
|
||||
bool isSuccess = false;
|
||||
string msg;
|
||||
var isSuccess = false;
|
||||
var msg = string.Empty;
|
||||
|
||||
Application.Current?.Dispatcher.Invoke(() =>
|
||||
{
|
||||
@@ -106,29 +107,38 @@ namespace v2rayN.Handler
|
||||
Load();
|
||||
}
|
||||
|
||||
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeycode)
|
||||
private (int fsModifiers, int vKey, string hotkeyStr, List<string> Names) GetHotkeyInfo(int hotkeyCode)
|
||||
{
|
||||
var _fsModifiers = hotkeycode & 0xffff;
|
||||
var _vkey = (hotkeycode >> 16) & 0xffff;
|
||||
var _hotkeyStr = new StringBuilder();
|
||||
var _names = new List<string>();
|
||||
var fsModifiers = hotkeyCode & 0xffff;
|
||||
var vKey = (hotkeyCode >> 16) & 0xffff;
|
||||
var hotkeyStr = new StringBuilder();
|
||||
var names = new List<string>();
|
||||
|
||||
var mdif = (KeyModifiers)_fsModifiers;
|
||||
var key = KeyInterop.KeyFromVirtualKey(_vkey);
|
||||
if ((mdif & KeyModifiers.Ctrl) == KeyModifiers.Ctrl)
|
||||
_hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
|
||||
if ((mdif & KeyModifiers.Alt) == KeyModifiers.Alt)
|
||||
_hotkeyStr.Append($"{KeyModifiers.Alt}+");
|
||||
if ((mdif & KeyModifiers.Shift) == KeyModifiers.Shift)
|
||||
_hotkeyStr.Append($"{KeyModifiers.Shift}+");
|
||||
_hotkeyStr.Append(key.ToString());
|
||||
|
||||
foreach (var name in _hotkeyTriggerDic[hotkeycode])
|
||||
var modify = (KeyModifiers)fsModifiers;
|
||||
var key = KeyInterop.KeyFromVirtualKey(vKey);
|
||||
if ((modify & KeyModifiers.Ctrl) == KeyModifiers.Ctrl)
|
||||
{
|
||||
_names.Add(name.ToString());
|
||||
hotkeyStr.Append($"{KeyModifiers.Ctrl}+");
|
||||
}
|
||||
|
||||
return (_fsModifiers, _vkey, _hotkeyStr.ToString(), _names);
|
||||
if ((modify & KeyModifiers.Alt) == KeyModifiers.Alt)
|
||||
{
|
||||
hotkeyStr.Append($"{KeyModifiers.Alt}+");
|
||||
}
|
||||
|
||||
if ((modify & KeyModifiers.Shift) == KeyModifiers.Shift)
|
||||
{
|
||||
hotkeyStr.Append($"{KeyModifiers.Shift}+");
|
||||
}
|
||||
|
||||
hotkeyStr.Append(key.ToString());
|
||||
|
||||
foreach (var name in _hotkeyTriggerDic[hotkeyCode])
|
||||
{
|
||||
names.Add(name.ToString());
|
||||
}
|
||||
|
||||
return (fsModifiers, vKey, hotkeyStr.ToString(), names);
|
||||
}
|
||||
|
||||
private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled)
|
||||
@@ -138,21 +148,18 @@ namespace v2rayN.Handler
|
||||
return;
|
||||
}
|
||||
handled = true;
|
||||
var _hotKeyCode = (int)msg.lParam;
|
||||
var hotKeyCode = (int)msg.lParam;
|
||||
if (IsPause)
|
||||
{
|
||||
Application.Current?.Dispatcher.Invoke(() =>
|
||||
{
|
||||
UIElement? element = Keyboard.FocusedElement as UIElement;
|
||||
if (element != null)
|
||||
if (Keyboard.FocusedElement is UIElement element)
|
||||
{
|
||||
var _keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice,
|
||||
PresentationSource.FromVisual(element), 0,
|
||||
KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(_hotKeyCode).vKey))
|
||||
var keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromVisual(element), 0, KeyInterop.KeyFromVirtualKey(GetHotkeyInfo(hotKeyCode).vKey))
|
||||
{
|
||||
RoutedEvent = UIElement.KeyDownEvent
|
||||
};
|
||||
element.RaiseEvent(_keyEventArgs);
|
||||
element.RaiseEvent(keyEventArgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<reactiveui:ReactiveWindow
|
||||
<reactiveui:ReactiveWindow
|
||||
x:Class="v2rayN.Views.AddServer2Window"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -8,7 +8,7 @@
|
||||
xmlns:reactiveui="http://reactiveui.net"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="v2rayN"
|
||||
Title="{x:Static resx:ResUI.menuAddCustomServer}"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:TypeArguments="vms:AddServer2ViewModel"
|
||||
@@ -198,4 +198,4 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</reactiveui:ReactiveWindow>
|
||||
</reactiveui:ReactiveWindow>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<reactiveui:ReactiveWindow
|
||||
<reactiveui:ReactiveWindow
|
||||
x:Class="v2rayN.Views.AddServerWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -432,6 +432,7 @@
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
@@ -463,6 +464,29 @@
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbPorts7}" />
|
||||
<TextBox
|
||||
x:Name="txtPorts7"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Margin="{StaticResource Margin4}"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource DefTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Margin="{StaticResource Margin4}"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ToolbarTextBlock}"
|
||||
Text="{x:Static resx:ResUI.TbPorts7Tips}" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTuic"
|
||||
@@ -983,4 +1007,4 @@
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</reactiveui:ReactiveWindow>
|
||||
</reactiveui:ReactiveWindow>
|
||||
|
||||
@@ -172,6 +172,7 @@ namespace v2rayN.Views
|
||||
case EConfigType.Hysteria2:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.TUIC:
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
<reactiveui:ReactiveWindow
|
||||
x:Class="v2rayN.Views.GlobalHotkeySettingWindow"
|
||||
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"
|
||||
Title="{x:Static resx:ResUI.menuSetting}"
|
||||
Title="{x:Static resx:ResUI.menuGlobalHotkeySetting}"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:TypeArguments="vms:SubEditViewModel"
|
||||
KeyDown="GlobalHotkeySettingWindow_KeyDown"
|
||||
x:TypeArguments="vms:GlobalHotkeySettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
Style="{StaticResource WindowGlobal}"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
@@ -92,7 +91,6 @@
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
@@ -110,7 +108,6 @@
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
|
||||
<TextBlock
|
||||
@@ -128,7 +125,6 @@
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
@@ -145,7 +141,6 @@
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
@@ -162,7 +157,6 @@
|
||||
VerticalAlignment="Center"
|
||||
AcceptsReturn="True"
|
||||
IsReadOnly="True"
|
||||
PreviewKeyDown="TxtGlobalHotkey_PreviewKeyDown"
|
||||
Style="{StaticResource MyOutlinedTextBox}" />
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -1,140 +1,139 @@
|
||||
using System.Reactive.Disposables;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Handler;
|
||||
|
||||
namespace v2rayN.Views
|
||||
{
|
||||
public partial class GlobalHotkeySettingWindow
|
||||
{
|
||||
private static Config _config = default!;
|
||||
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
|
||||
private readonly List<object> _textBoxKeyEventItem = new();
|
||||
|
||||
public GlobalHotkeySettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Owner = Application.Current.MainWindow;
|
||||
_config = AppHandler.Instance.Config;
|
||||
_config.GlobalHotkeys ??= new List<KeyEventItem>();
|
||||
|
||||
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||
|
||||
btnReset.Click += btnReset_Click;
|
||||
btnSave.Click += btnSave_ClickAsync;
|
||||
|
||||
txtGlobalHotkey0.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
txtGlobalHotkey1.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
txtGlobalHotkey2.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
txtGlobalHotkey3.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
txtGlobalHotkey4.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
|
||||
HotkeyHandler.Instance.IsPause = true;
|
||||
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
WindowsUtils.SetDarkBorder(this, _config.UiItem.CurrentTheme);
|
||||
InitData();
|
||||
}
|
||||
|
||||
private void InitData()
|
||||
{
|
||||
_TextBoxKeyEventItem = new()
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
{ txtGlobalHotkey0,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.ShowForm) },
|
||||
{ txtGlobalHotkey1,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyClear) },
|
||||
{ txtGlobalHotkey2,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxySet) },
|
||||
{ txtGlobalHotkey3,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyUnchanged)},
|
||||
{ txtGlobalHotkey4,GetKeyEventItemByEGlobalHotkey(_config.GlobalHotkeys,EGlobalHotkey.SystemProxyPac)}
|
||||
};
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
WindowsUtils.SetDarkBorder(this, AppHandler.Instance.Config.UiItem.CurrentTheme);
|
||||
|
||||
Init();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
private void TxtGlobalHotkey_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.DialogResult = true;
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||
|
||||
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||
{
|
||||
var sender = _textBoxKeyEventItem[index];
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
txtBox.Tag = (EGlobalHotkey)index;
|
||||
txtBox.PreviewKeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
|
||||
Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
|
||||
_TextBoxKeyEventItem[sender].KeyCode = (int)(e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key));
|
||||
_TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
|
||||
_TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
|
||||
_TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||
(sender as TextBox)!.Text = KeyEventItemToString(_TextBoxKeyEventItem[sender]);
|
||||
}
|
||||
|
||||
private KeyEventItem GetKeyEventItemByEGlobalHotkey(List<KeyEventItem> KEList, EGlobalHotkey eg)
|
||||
{
|
||||
return JsonUtils.DeepCopy(KEList.Find((it) => it.EGlobalHotkey == eg) ?? new()
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
EGlobalHotkey = eg,
|
||||
Control = false,
|
||||
Alt = false,
|
||||
Shift = false,
|
||||
KeyCode = null
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private string KeyEventItemToString(KeyEventItem item)
|
||||
{
|
||||
var res = new StringBuilder();
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||
|
||||
if (item.Control)
|
||||
res.Append($"{ModifierKeys.Control}+");
|
||||
if (item.Shift)
|
||||
res.Append($"{ModifierKeys.Shift}+");
|
||||
if (item.Alt)
|
||||
res.Append($"{ModifierKeys.Alt}+");
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
res.Append($"{(Key)item.KeyCode}");
|
||||
item.KeyCode = (int)(e.Key == Key.System ? (modifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (modifierKeys.Contains(e.Key) ? Key.None : e.Key));
|
||||
item.Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
|
||||
item.Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
|
||||
item.Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||
|
||||
return res.ToString();
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
|
||||
private void BindingData()
|
||||
{
|
||||
foreach (var item in _TextBoxKeyEventItem)
|
||||
foreach (var sender in _textBoxKeyEventItem)
|
||||
{
|
||||
if (item.Value.KeyCode != null && (Key)item.Value.KeyCode != Key.None)
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
(item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
(item.Key as TextBox)!.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void btnSave_ClickAsync(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_config.GlobalHotkeys = _TextBoxKeyEventItem.Values.ToList();
|
||||
|
||||
if (await ConfigHandler.SaveConfig(_config) == 0)
|
||||
{
|
||||
HotkeyHandler.Instance.ReLoad();
|
||||
this.DialogResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UI.Show(ResUI.OperationFailed);
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
foreach (var k in _TextBoxKeyEventItem.Keys)
|
||||
{
|
||||
_TextBoxKeyEventItem[k].Alt = false;
|
||||
_TextBoxKeyEventItem[k].Control = false;
|
||||
_TextBoxKeyEventItem[k].Shift = false;
|
||||
_TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
|
||||
}
|
||||
ViewModel?.ResetKeyEventItem();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
private void GlobalHotkeySettingWindow_KeyDown(object sender, KeyEventArgs e)
|
||||
private string KeyEventItemToString(KeyEventItem? item)
|
||||
{
|
||||
if (e.Key == Key.Escape)
|
||||
if (item == null)
|
||||
{
|
||||
this.Close();
|
||||
return string.Empty;
|
||||
}
|
||||
var res = new StringBuilder();
|
||||
|
||||
if (item.Control)
|
||||
{
|
||||
res.Append($"{ModifierKeys.Control} +");
|
||||
}
|
||||
|
||||
if (item.Shift)
|
||||
{
|
||||
res.Append($"{ModifierKeys.Shift} +");
|
||||
}
|
||||
|
||||
if (item.Alt)
|
||||
{
|
||||
res.Append($"{ModifierKeys.Alt} +");
|
||||
}
|
||||
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
{
|
||||
res.Append($"{(Key)item.KeyCode}");
|
||||
}
|
||||
|
||||
return res.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,7 +764,7 @@
|
||||
x:Name="cmbcurrentFontFamily"
|
||||
Grid.Row="15"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Width="300"
|
||||
Margin="{StaticResource Margin8}"
|
||||
MaxDropDownHeight="1000"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
@@ -867,7 +867,7 @@
|
||||
x:Name="cmbMainGirdOrientation"
|
||||
Grid.Row="21"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Width="200"
|
||||
Margin="{StaticResource Margin8}"
|
||||
Style="{StaticResource DefComboBox}" />
|
||||
|
||||
|
||||
@@ -259,7 +259,10 @@ namespace v2rayN.Views
|
||||
|
||||
private void ClbdestOverride_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace v2rayN.Views
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Application.Current?.Dispatcher.Invoke((() =>
|
||||
{
|
||||
ViewModel?.RefreshServersBiz();
|
||||
_ = RefreshServersBiz();
|
||||
}), DispatcherPriority.Normal);
|
||||
break;
|
||||
}
|
||||
@@ -186,9 +186,25 @@ namespace v2rayN.Views
|
||||
await DialogHost.Show(dialog, "RootDialog");
|
||||
}
|
||||
|
||||
public async Task RefreshServersBiz()
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.RefreshServersBiz();
|
||||
}
|
||||
|
||||
if (lstProfiles.SelectedIndex > 0)
|
||||
{
|
||||
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||
@@ -353,9 +369,9 @@ namespace v2rayN.Views
|
||||
private void StorageUI(string? n = null)
|
||||
{
|
||||
List<ColumnItem> lvColumnItem = new();
|
||||
for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
||||
foreach (var t in lstProfiles.Columns)
|
||||
{
|
||||
var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
|
||||
var item2 = (MyDGTextColumn)t;
|
||||
lvColumnItem.Add(new()
|
||||
{
|
||||
Name = item2.ExName,
|
||||
|
||||
@@ -79,12 +79,18 @@ namespace v2rayN.Views
|
||||
|
||||
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClbInboundTag_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void linkRuleobjectDoc_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
@@ -162,7 +162,10 @@ namespace v2rayN.Views
|
||||
|
||||
private void lstRules_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRules_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
|
||||
@@ -113,7 +113,10 @@ namespace v2rayN.Views
|
||||
|
||||
private void lstRoutings_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRoutings_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
|
||||
@@ -94,7 +94,10 @@ namespace v2rayN.Views
|
||||
|
||||
private void LstSubscription_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void menuClose_Click(object sender, System.Windows.RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user