Creating a new desktop app with avaloniaui
31
v2rayN/v2rayN.Desktop/App.axaml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<Application
|
||||
x:Class="v2rayN.Desktop.App"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
RequestedThemeVariant="Default">
|
||||
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="Styles/GlobalStyles.axaml" />
|
||||
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
|
||||
<StyleInclude Source="avares://Semi.Avalonia.DataGrid/Index.axaml" />
|
||||
</Application.Styles>
|
||||
|
||||
<TrayIcon.Icons>
|
||||
<TrayIcons>
|
||||
<TrayIcon Clicked="TrayIcon_Clicked" Icon="/Assets/NotifyIcon1.ico">
|
||||
<TrayIcon.Menu>
|
||||
<NativeMenu>
|
||||
<NativeMenuItem Click="MenuAddServerViaClipboardClick" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||
<NativeMenuItem Header="{x:Static resx:ResUI.menuAddServerViaScan}" IsVisible="False" />
|
||||
<NativeMenuItem Click="MenuSubUpdate_Click" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||
<NativeMenuItem Click="MenuSubUpdateViaProxy_Click" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||
<NativeMenuItemSeparator />
|
||||
<NativeMenuItem Click="TrayIcon_Clicked" Header="{x:Static resx:ResUI.menuShowOrHideMainWindow}" />
|
||||
<NativeMenuItem Click="MenuExit_Click" Header="{x:Static resx:ResUI.menuExit}" />
|
||||
</NativeMenu>
|
||||
</TrayIcon.Menu>
|
||||
</TrayIcon>
|
||||
</TrayIcons>
|
||||
</TrayIcon.Icons>
|
||||
</Application>
|
121
v2rayN/v2rayN.Desktop/App.axaml.cs
Normal file
|
@ -0,0 +1,121 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Splat;
|
||||
using v2rayN.Desktop.Common;
|
||||
using v2rayN.Desktop.Views;
|
||||
|
||||
namespace v2rayN.Desktop;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public static EventWaitHandle ProgramStarted;
|
||||
private static Config _config;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
OnStartup(desktop.Args);
|
||||
|
||||
desktop.Exit += OnExit;
|
||||
desktop.MainWindow = new MainWindow();
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
private void OnStartup(string[]? Args)
|
||||
{
|
||||
var exePathKey = Utils.GetMD5(Utils.GetExePath());
|
||||
|
||||
var rebootas = (Args ?? new string[] { }).Any(t => t == Global.RebootAs);
|
||||
//ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out bool bCreatedNew);
|
||||
//if (!rebootas && !bCreatedNew)
|
||||
//{
|
||||
// ProgramStarted.Set();
|
||||
// Environment.Exit(0);
|
||||
// return;
|
||||
//}
|
||||
|
||||
Logging.Setup();
|
||||
Init();
|
||||
Logging.LoggingEnabled(_config.guiItem.enableLog);
|
||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
||||
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
||||
Logging.ClearLogs();
|
||||
|
||||
Thread.CurrentThread.CurrentUICulture = new(_config.uiItem.currentLanguage);
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
if (ConfigHandler.LoadConfig(ref _config) != 0)
|
||||
{
|
||||
Logging.SaveLog($"Loading GUI configuration file is abnormal,please restart the application{Environment.NewLine}加载GUI配置文件异常,请重启应用");
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
}
|
||||
LazyConfig.Instance.SetConfig(_config);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => new NoticeHandler(), typeof(NoticeHandler));
|
||||
|
||||
//Under Win10
|
||||
if (Utils.IsWindows() && Environment.OSVersion.Version.Major < 10)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private void TrayIcon_Clicked(object? sender, EventArgs e)
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
if (desktop.MainWindow.IsVisible)
|
||||
{
|
||||
desktop.MainWindow?.Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
desktop.MainWindow?.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuAddServerViaClipboardClick(object? sender, EventArgs e)
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var clipboardData = AvaUtils.GetClipboardData(desktop.MainWindow).Result;
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuSubUpdate_Click(object? sender, EventArgs e)
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.UpdateSubscriptionProcess("", false);
|
||||
}
|
||||
|
||||
private void MenuSubUpdateViaProxy_Click(object? sender, EventArgs e)
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.UpdateSubscriptionProcess("", true);
|
||||
}
|
||||
|
||||
private void MenuExit_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.MyAppExitAsync(false);
|
||||
|
||||
desktop.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
BIN
v2rayN/v2rayN.Desktop/Assets/NotifyIcon1.ico
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
v2rayN/v2rayN.Desktop/Assets/NotifyIcon2.ico
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
v2rayN/v2rayN.Desktop/Assets/NotifyIcon3.ico
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
v2rayN/v2rayN.Desktop/Assets/add.png
Normal file
After Width: | Height: | Size: 198 B |
BIN
v2rayN/v2rayN.Desktop/Assets/close.png
Normal file
After Width: | Height: | Size: 388 B |
BIN
v2rayN/v2rayN.Desktop/Assets/copy.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
v2rayN/v2rayN.Desktop/Assets/delete.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
v2rayN/v2rayN.Desktop/Assets/edit.png
Normal file
After Width: | Height: | Size: 329 B |
BIN
v2rayN/v2rayN.Desktop/Assets/fit.png
Normal file
After Width: | Height: | Size: 455 B |
BIN
v2rayN/v2rayN.Desktop/Assets/light.png
Normal file
After Width: | Height: | Size: 690 B |
BIN
v2rayN/v2rayN.Desktop/Assets/more.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
v2rayN/v2rayN.Desktop/Assets/refresh.png
Normal file
After Width: | Height: | Size: 701 B |
64
v2rayN/v2rayN.Desktop/Common/AvaUtils.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using System.Reflection;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
{
|
||||
internal class AvaUtils
|
||||
{
|
||||
public static async Task<string?> GetClipboardData(Window owner)
|
||||
{
|
||||
try
|
||||
{
|
||||
var clipboard = TopLevel.GetTopLevel(owner)?.Clipboard;
|
||||
if (clipboard == null) return null;
|
||||
return await clipboard.GetTextAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task SetClipboardData(Visual? visual, string strData)
|
||||
{
|
||||
try
|
||||
{
|
||||
var clipboard = TopLevel.GetTopLevel(visual)?.Clipboard;
|
||||
if (clipboard == null) return;
|
||||
var dataObject = new DataObject();
|
||||
dataObject.Set(DataFormats.Text, strData);
|
||||
await clipboard.SetDataObjectAsync(dataObject);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static WindowIcon GetAppIcon(ESysProxyType sysProxyType)
|
||||
{
|
||||
int index = 1;
|
||||
switch (sysProxyType)
|
||||
{
|
||||
case ESysProxyType.ForcedClear:
|
||||
index = 1;
|
||||
break;
|
||||
|
||||
case ESysProxyType.ForcedChange:
|
||||
case ESysProxyType.Pac:
|
||||
index = 2;
|
||||
break;
|
||||
|
||||
case ESysProxyType.Unchanged:
|
||||
index = 3;
|
||||
break;
|
||||
}
|
||||
var uri = new Uri($"avares://{Assembly.GetExecutingAssembly().GetName().Name}/Assets/NotifyIcon{index}.ico");
|
||||
using var bitmap = new Bitmap(AssetLoader.Open(uri));
|
||||
return new(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
50
v2rayN/v2rayN.Desktop/Common/UI.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Platform.Storage;
|
||||
using MsBox.Avalonia;
|
||||
using MsBox.Avalonia.Enums;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
{
|
||||
internal class UI
|
||||
{
|
||||
private static readonly string caption = Global.AppName;
|
||||
|
||||
public static async Task<ButtonResult> ShowYesNo(Window owner, string msg)
|
||||
{
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(caption, msg, ButtonEnum.YesNo);
|
||||
return await box.ShowWindowDialogAsync(owner);
|
||||
}
|
||||
|
||||
public static async Task<string?> OpenFileDialog(Window owner, FilePickerFileType? filter)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
if (topLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Start async operation to open the dialog.
|
||||
var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
FileTypeFilter = filter is null ? [FilePickerFileTypes.All, FilePickerFileTypes.ImagePng] : [filter]
|
||||
});
|
||||
|
||||
return files.FirstOrDefault()?.TryGetLocalPath();
|
||||
}
|
||||
|
||||
public static async Task<string?> SaveFileDialog(Window owner, string filter)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
if (topLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Start async operation to open the dialog.
|
||||
var files = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
});
|
||||
|
||||
return files?.TryGetLocalPath();
|
||||
}
|
||||
}
|
||||
}
|
26
v2rayN/v2rayN.Desktop/Converters/DelayColorConverter.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
using System.Globalization;
|
||||
|
||||
namespace v2rayN.Desktop.Converters
|
||||
{
|
||||
public class DelayColorConverter : IValueConverter
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
int.TryParse(value?.ToString(), out var delay);
|
||||
|
||||
if (delay <= 0)
|
||||
return new SolidColorBrush(Colors.Red);
|
||||
if (delay <= 500)
|
||||
return new SolidColorBrush(Colors.Green);
|
||||
else
|
||||
return new SolidColorBrush(Colors.IndianRed);
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
3
v2rayN/v2rayN.Desktop/FodyWeavers.xml
Normal file
|
@ -0,0 +1,3 @@
|
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<ReactiveUI />
|
||||
</Weavers>
|
8
v2rayN/v2rayN.Desktop/GlobalUsings.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
global using ServiceLib;
|
||||
global using ServiceLib.Base;
|
||||
global using ServiceLib.Common;
|
||||
global using ServiceLib.Enums;
|
||||
global using ServiceLib.Handler;
|
||||
global using ServiceLib.Models;
|
||||
global using ServiceLib.Resx;
|
||||
global using ServiceLib.ViewModels;
|
61
v2rayN/v2rayN.Desktop/Handler/SysProxyHandler.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
namespace v2rayN.Desktop.Handler
|
||||
{
|
||||
public static class SysProxyHandler
|
||||
{
|
||||
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
||||
{
|
||||
var type = config.systemProxyItem.sysProxyType;
|
||||
|
||||
if (forceDisable && type != ESysProxyType.Unchanged)
|
||||
{
|
||||
type = ESysProxyType.ForcedClear;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int port = LazyConfig.Instance.GetLocalPort(EInboundProtocol.http);
|
||||
if (port <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (type == ESysProxyType.ForcedChange)
|
||||
{
|
||||
var strProxy = $"{Global.Loopback}:{port}";
|
||||
await SetProxy(strProxy);
|
||||
}
|
||||
else if (type == ESysProxyType.ForcedClear)
|
||||
{
|
||||
await UnsetProxy();
|
||||
}
|
||||
else if (type == ESysProxyType.Unchanged)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog(ex.Message, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task SetProxy(string? strProxy)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var httpProxy = strProxy is null ? null : $"{Global.HttpProtocol}{strProxy}";
|
||||
var socksProxy = strProxy is null ? null : $"{Global.SocksProtocol}{strProxy}";
|
||||
var noProxy = $"localhost,127.0.0.0/8,::1";
|
||||
|
||||
Environment.SetEnvironmentVariable("http_proxy", httpProxy, EnvironmentVariableTarget.User);
|
||||
Environment.SetEnvironmentVariable("https_proxy", httpProxy, EnvironmentVariableTarget.User);
|
||||
Environment.SetEnvironmentVariable("all_proxy", socksProxy, EnvironmentVariableTarget.User);
|
||||
Environment.SetEnvironmentVariable("no_proxy", noProxy, EnvironmentVariableTarget.User);
|
||||
});
|
||||
}
|
||||
|
||||
private static async Task UnsetProxy()
|
||||
{
|
||||
await SetProxy(null);
|
||||
}
|
||||
}
|
||||
}
|
22
v2rayN/v2rayN.Desktop/Program.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||
// yet and stuff might break.
|
||||
[STAThread]
|
||||
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||
.StartWithClassicDesktopLifetime(args);
|
||||
|
||||
// Avalonia configuration, don't remove; also used by visual designer.
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.WithInterFont()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
}
|
39
v2rayN/v2rayN.Desktop/Styles/GlobalStyles.axaml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Design.PreviewWith>
|
||||
<Border Padding="20">
|
||||
<!-- Add Controls for Previewer Here -->
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
|
||||
<Style Selector="TextBlock.Margin4">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.Margin4">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="DockPanel.Margin4">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="WrapPanel.Margin4">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<Style Selector="Grid.Margin4">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBlock.Margin8">
|
||||
<Setter Property="Margin" Value="8" />
|
||||
</Style>
|
||||
<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>
|
||||
</Styles>
|
143
v2rayN/v2rayN.Desktop/ViewModels/ThemeSettingViewModel.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Splat;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace v2rayN.Desktop.ViewModels
|
||||
{
|
||||
public class ThemeSettingViewModel : MyReactiveObject
|
||||
{
|
||||
[Reactive]
|
||||
public bool ColorModeDark { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public int CurrentFontSize { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string CurrentLanguage { get; set; }
|
||||
|
||||
public ThemeSettingViewModel()
|
||||
{
|
||||
_config = LazyConfig.Instance.Config;
|
||||
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
|
||||
|
||||
BindingUI();
|
||||
RestoreUI();
|
||||
}
|
||||
|
||||
private void RestoreUI()
|
||||
{
|
||||
ModifyTheme(_config.uiItem.colorModeDark);
|
||||
}
|
||||
|
||||
private void BindingUI()
|
||||
{
|
||||
ColorModeDark = _config.uiItem.colorModeDark;
|
||||
CurrentFontSize = _config.uiItem.currentFontSize;
|
||||
CurrentLanguage = _config.uiItem.currentLanguage;
|
||||
|
||||
this.WhenAnyValue(x => x.ColorModeDark)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.uiItem.colorModeDark != ColorModeDark)
|
||||
{
|
||||
_config.uiItem.colorModeDark = ColorModeDark;
|
||||
ModifyTheme(ColorModeDark);
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.uiItem.currentFontSize = CurrentFontSize;
|
||||
double size = CurrentFontSize;
|
||||
ModifyFontSize(size);
|
||||
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (!Utils.IsNullOrEmpty(CurrentLanguage) && _config.uiItem.currentLanguage != CurrentLanguage)
|
||||
{
|
||||
_config.uiItem.currentLanguage = CurrentLanguage;
|
||||
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
_noticeHandler?.Enqueue(ResUI.NeedRebootTips);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ModifyTheme(bool isDarkTheme)
|
||||
{
|
||||
var app = Application.Current;
|
||||
if (app is not null)
|
||||
{
|
||||
app.RequestedThemeVariant = isDarkTheme ? ThemeVariant.Dark : ThemeVariant.Light;
|
||||
}
|
||||
}
|
||||
|
||||
private void ModifyFontSize(double size)
|
||||
{
|
||||
Style buttonStyle = new(x => x.OfType<Button>());
|
||||
buttonStyle.Add(new Setter()
|
||||
{
|
||||
Property = Button.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(buttonStyle);
|
||||
|
||||
Style textStyle = new(x => x.OfType<TextBox>());
|
||||
textStyle.Add(new Setter()
|
||||
{
|
||||
Property = TextBox.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(textStyle);
|
||||
|
||||
Style textBlockStyle = new(x => x.OfType<TextBlock>());
|
||||
textBlockStyle.Add(new Setter()
|
||||
{
|
||||
Property = TextBlock.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(textBlockStyle);
|
||||
|
||||
Style menuStyle = new(x => x.OfType<Menu>());
|
||||
menuStyle.Add(new Setter()
|
||||
{
|
||||
Property = Menu.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(menuStyle);
|
||||
|
||||
Style dataStyle = new(x => x.OfType<DataGridRow>());
|
||||
dataStyle.Add(new Setter()
|
||||
{
|
||||
Property = DataGridRow.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(dataStyle);
|
||||
|
||||
Style listStyle = new(x => x.OfType<ListBoxItem>());
|
||||
listStyle.Add(new Setter()
|
||||
{
|
||||
Property = ListBoxItem.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(listStyle);
|
||||
}
|
||||
}
|
||||
}
|
179
v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml
Normal file
|
@ -0,0 +1,179 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.AddServer2Window"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="v2rayN"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:DataType="vms:AddServer2ViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
IsReadOnly="True" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnBrowse"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
<Button
|
||||
x:Name="btnEdit"
|
||||
Margin="2,0"
|
||||
Content="{x:Static resx:ResUI.TbEdit}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbCoreType}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4"
|
||||
MaxDropDownHeight="1000" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbDisplayLog}" />
|
||||
<StackPanel
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
Orientation="Horizontal">
|
||||
<ToggleSwitch
|
||||
x:Name="togDisplayLog"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipDisplayLog}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbPreSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPreSocksPort"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
<StackPanel
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin4">
|
||||
<TextBlock
|
||||
Width="500"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipPreSocksPort}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
Width="500"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.CustomServerTips}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
72
v2rayN/v2rayN.Desktop/Views/AddServer2Window.axaml.cs
Normal file
|
@ -0,0 +1,72 @@
|
|||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||
{
|
||||
public AddServer2Window()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public AddServer2Window(ProfileItem profileItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
ViewModel = new AddServer2ViewModel(profileItem, UpdateViewHandler);
|
||||
|
||||
foreach (ECoreType it in Enum.GetValues(typeof(ECoreType)))
|
||||
{
|
||||
if (it == ECoreType.v2rayN)
|
||||
continue;
|
||||
cmbCoreType.Items.Add(it.ToString());
|
||||
}
|
||||
cmbCoreType.Items.Add(string.Empty);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.address, v => v.txtAddress.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.displayLog, v => v.togDisplayLog.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.preSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.BrowseServerCmd, v => v.btnBrowse).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
|
||||
case EViewAction.BrowseServer:
|
||||
var fileName = await UI.OpenFileDialog(this, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ViewModel?.BrowseServer(fileName);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
}
|
||||
}
|
842
v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
Normal file
|
@ -0,0 +1,842 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.AddServerWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuServers}"
|
||||
Width="900"
|
||||
Height="700"
|
||||
x:DataType="vms:AddServerViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Center"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.menuServers}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal">
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType"
|
||||
Width="100"
|
||||
Classes="Margin4"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TbCoreType}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbRemarks}" />
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtAddress"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPort}" />
|
||||
<TextBox
|
||||
x:Name="txtPort"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="1" Margin="0,2" />
|
||||
|
||||
<Grid
|
||||
x:Name="gridVMess"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId}" />
|
||||
<TextBox
|
||||
x:Name="txtId"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
<Button
|
||||
x:Name="btnGUID"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="4,0"
|
||||
Content="{x:Static resx:ResUI.TbGUID}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAlterId}" />
|
||||
<TextBox
|
||||
x:Name="txtAlterId"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSecurity}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSecurity"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridSs"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId3"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSecurity3}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSecurity3"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridSocks"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSecurity4}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity4"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId4}" />
|
||||
<TextBox
|
||||
x:Name="txtId4"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridVLESS"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId5}" />
|
||||
<TextBox
|
||||
x:Name="txtId5"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
<Button
|
||||
x:Name="btnGUID5"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="4,0"
|
||||
Content="{x:Static resx:ResUI.TbGUID}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFlow5}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFlow5"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSecurity5}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity5"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTrojan"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId6"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFlow5}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFlow6"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridHysteria2"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtId7"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPath7}" />
|
||||
<TextBox
|
||||
x:Name="txtPath7"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTuic"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId}" />
|
||||
<TextBox
|
||||
x:Name="txtId8"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbId3}" />
|
||||
<TextBox
|
||||
x:Name="txtSecurity8"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType8}" />
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType8"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridWireguard"
|
||||
Grid.Row="2"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPrivateKey}" />
|
||||
<TextBox
|
||||
x:Name="txtId9"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPublicKey}" />
|
||||
<TextBox
|
||||
x:Name="txtPublicKey9"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbReserved}" />
|
||||
<TextBox
|
||||
x:Name="txtPath9"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbLocalAddress}" />
|
||||
<TextBox
|
||||
x:Name="txtRequestHost9"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="Mtu" />
|
||||
<TextBox
|
||||
x:Name="txtShortId9"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
|
||||
<Separator
|
||||
x:Name="sepa2"
|
||||
Grid.Row="3"
|
||||
Margin="0,2" />
|
||||
|
||||
<Grid x:Name="gridTransport" Grid.Row="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.GbTransport}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbNetwork}" />
|
||||
<ComboBox
|
||||
x:Name="cmbNetwork"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TipNetwork}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="labHeaderType"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType}" />
|
||||
<ComboBox
|
||||
x:Name="cmbHeaderType"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
x:Name="tipHeaderType"
|
||||
Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbHeaderType}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbRequestHost}" />
|
||||
<TextBox
|
||||
x:Name="txtRequestHost"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
x:Name="tipRequestHost"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbRequestHost}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPath}" />
|
||||
<TextBox
|
||||
x:Name="txtPath"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
x:Name="tipPath"
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPath}" />
|
||||
</Grid>
|
||||
|
||||
<Separator Grid.Row="5" Margin="0,2" />
|
||||
|
||||
<Grid x:Name="gridTls" Grid.Row="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbStreamSecurity}" />
|
||||
<ComboBox
|
||||
x:Name="cmbStreamSecurity"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridTlsMore"
|
||||
Grid.Row="7"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSNI}" />
|
||||
<TextBox
|
||||
x:Name="txtSNI"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFingerprint"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAlpn}" />
|
||||
<ComboBox
|
||||
x:Name="cmbAlpn"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAllowInsecure}" />
|
||||
<ComboBox
|
||||
x:Name="cmbAllowInsecure"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin4" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="gridRealityMore"
|
||||
Grid.Row="7"
|
||||
IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSNI}" />
|
||||
<TextBox
|
||||
x:Name="txtSNI2"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbFingerprint2"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbPublicKey}" />
|
||||
<TextBox
|
||||
x:Name="txtPublicKey"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbShortId}" />
|
||||
<TextBox
|
||||
x:Name="txtShortId"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSpiderX}" />
|
||||
<TextBox
|
||||
x:Name="txtSpiderX"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="400"
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Separator Grid.Row="8" Margin="0,2" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
365
v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml.cs
Normal file
|
@ -0,0 +1,365 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||
{
|
||||
public AddServerWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public AddServerWindow(ProfileItem profileItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
cmbNetwork.SelectionChanged += CmbNetwork_SelectionChanged;
|
||||
cmbStreamSecurity.SelectionChanged += CmbStreamSecurity_SelectionChanged;
|
||||
btnGUID.Click += btnGUID_Click;
|
||||
btnGUID5.Click += btnGUID_Click;
|
||||
|
||||
ViewModel = new AddServerViewModel(profileItem, UpdateViewHandler);
|
||||
|
||||
if (profileItem.configType == EConfigType.VLESS)
|
||||
{
|
||||
Global.CoreTypes4VLESS.ForEach(it =>
|
||||
{
|
||||
cmbCoreType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.CoreTypes.ForEach(it =>
|
||||
{
|
||||
cmbCoreType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
cmbCoreType.Items.Add(string.Empty);
|
||||
|
||||
cmbStreamSecurity.Items.Add(string.Empty);
|
||||
cmbStreamSecurity.Items.Add(Global.StreamSecurity);
|
||||
|
||||
Global.Networks.ForEach(it =>
|
||||
{
|
||||
cmbNetwork.Items.Add(it);
|
||||
});
|
||||
Global.Fingerprints.ForEach(it =>
|
||||
{
|
||||
cmbFingerprint.Items.Add(it);
|
||||
cmbFingerprint2.Items.Add(it);
|
||||
});
|
||||
Global.AllowInsecure.ForEach(it =>
|
||||
{
|
||||
cmbAllowInsecure.Items.Add(it);
|
||||
});
|
||||
Global.Alpns.ForEach(it =>
|
||||
{
|
||||
cmbAlpn.Items.Add(it);
|
||||
});
|
||||
|
||||
switch (profileItem.configType)
|
||||
{
|
||||
case EConfigType.VMess:
|
||||
gridVMess.IsVisible = true;
|
||||
Global.VmessSecurities.ForEach(it =>
|
||||
{
|
||||
cmbSecurity.Items.Add(it);
|
||||
});
|
||||
if (profileItem.security.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.security = Global.DefaultSecurity;
|
||||
}
|
||||
break;
|
||||
|
||||
case EConfigType.Shadowsocks:
|
||||
gridSs.IsVisible = true;
|
||||
LazyConfig.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
|
||||
{
|
||||
cmbSecurity3.Items.Add(it);
|
||||
});
|
||||
break;
|
||||
|
||||
case EConfigType.Socks:
|
||||
case EConfigType.Http:
|
||||
gridSocks.IsVisible = true;
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
gridVLESS.IsVisible = true;
|
||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
||||
Global.Flows.ForEach(it =>
|
||||
{
|
||||
cmbFlow5.Items.Add(it);
|
||||
});
|
||||
if (profileItem.security.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.security = Global.None;
|
||||
}
|
||||
break;
|
||||
|
||||
case EConfigType.Trojan:
|
||||
gridTrojan.IsVisible = true;
|
||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
||||
Global.Flows.ForEach(it =>
|
||||
{
|
||||
cmbFlow6.Items.Add(it);
|
||||
});
|
||||
break;
|
||||
|
||||
case EConfigType.Hysteria2:
|
||||
gridHysteria2.IsVisible = true;
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
cmbFingerprint.IsEnabled = false;
|
||||
cmbFingerprint.SelectedValue = string.Empty;
|
||||
break;
|
||||
|
||||
case EConfigType.Tuic:
|
||||
gridTuic.IsVisible = true;
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
cmbFingerprint.IsEnabled = false;
|
||||
cmbFingerprint.SelectedValue = string.Empty;
|
||||
|
||||
Global.TuicCongestionControls.ForEach(it =>
|
||||
{
|
||||
cmbHeaderType8.Items.Add(it);
|
||||
});
|
||||
break;
|
||||
|
||||
case EConfigType.Wireguard:
|
||||
gridWireguard.IsVisible = true;
|
||||
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
gridTls.IsVisible = false;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
gridTlsMore.IsVisible = false;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.address, v => v.txtAddress.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||
|
||||
switch (profileItem.configType)
|
||||
{
|
||||
case EConfigType.VMess:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.alterId, v => v.txtAlterId.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity.SelectedValue).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Shadowsocks:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId3.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.cmbSecurity3.SelectedValue).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Socks:
|
||||
case EConfigType.Http:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId4.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity4.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.VLESS:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId5.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow5.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity5.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Trojan:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId6.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.flow, v => v.cmbFlow6.SelectedValue).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case EConfigType.Tuic:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.security, v => v.txtSecurity8.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.headerType, v => v.cmbHeaderType8.SelectedValue).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.Wireguard:
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.id, v => v.txtId9.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.publicKey, v => v.txtPublicKey9.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.path, v => v.txtPath9.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.requestHost, v => v.txtRequestHost9.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.shortId, v => v.txtShortId9.Text).DisposeWith(disposables);
|
||||
break;
|
||||
}
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.headerType, v => v.cmbHeaderType.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.requestHost, v => v.txtRequestHost.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.path, v => v.txtPath.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.streamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.sni, v => v.txtSNI.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.allowInsecure, v => v.cmbAllowInsecure.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.alpn, v => v.cmbAlpn.SelectedValue).DisposeWith(disposables);
|
||||
//reality
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.sni, v => v.txtSNI2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.fingerprint, v => v.cmbFingerprint2.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.publicKey, v => v.txtPublicKey.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.shortId, v => v.txtShortId.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.spiderX, v => v.txtSpiderX.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
this.Title = $"{profileItem.configType}";
|
||||
}
|
||||
|
||||
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 Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
|
||||
private void CmbNetwork_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
SetHeaderType();
|
||||
SetTips();
|
||||
}
|
||||
|
||||
private void CmbStreamSecurity_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var security = cmbStreamSecurity.SelectedItem.ToString();
|
||||
if (security == Global.StreamSecurityReality)
|
||||
{
|
||||
gridRealityMore.IsVisible = true;
|
||||
gridTlsMore.IsVisible = false;
|
||||
}
|
||||
else if (security == Global.StreamSecurity)
|
||||
{
|
||||
gridRealityMore.IsVisible = false;
|
||||
gridTlsMore.IsVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridRealityMore.IsVisible = false;
|
||||
gridTlsMore.IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnGUID_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtId.Text =
|
||||
txtId5.Text = Utils.GetGUID();
|
||||
}
|
||||
|
||||
private void SetHeaderType()
|
||||
{
|
||||
cmbHeaderType.Items.Clear();
|
||||
|
||||
var network = cmbNetwork.SelectedItem.ToString();
|
||||
if (Utils.IsNullOrEmpty(network))
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (network == nameof(ETransport.tcp))
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
cmbHeaderType.Items.Add(Global.TcpHeaderHttp);
|
||||
}
|
||||
else if (network is nameof(ETransport.kcp) or nameof(ETransport.quic))
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
Global.KcpHeaderTypes.ForEach(it =>
|
||||
{
|
||||
cmbHeaderType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
else if (network == nameof(ETransport.grpc))
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.GrpcGunMode);
|
||||
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
}
|
||||
cmbHeaderType.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void SetTips()
|
||||
{
|
||||
var network = cmbNetwork.SelectedItem.ToString();
|
||||
if (Utils.IsNullOrEmpty(network))
|
||||
{
|
||||
network = Global.DefaultNetwork;
|
||||
}
|
||||
labHeaderType.IsVisible = true;
|
||||
tipRequestHost.Text =
|
||||
tipPath.Text =
|
||||
tipHeaderType.Text = string.Empty;
|
||||
|
||||
switch (network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip1;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip5;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
case nameof(ETransport.splithttp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.h2):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
|
||||
tipPath.Text = ResUI.TransportPathTip2;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.quic):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip4;
|
||||
tipPath.Text = ResUI.TransportPathTip3;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.grpc):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip5;
|
||||
tipPath.Text = ResUI.TransportPathTip4;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
|
||||
labHeaderType.IsVisible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
109
v2rayN/v2rayN.Desktop/Views/ClashConnectionsView.axaml
Normal file
|
@ -0,0 +1,109 @@
|
|||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.ClashConnectionsView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:ClashConnectionsViewModel"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSorting"
|
||||
Width="100"
|
||||
Margin="8,0">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpSpeed}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownSpeed}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingTime}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingHost}" />
|
||||
</ComboBox>
|
||||
|
||||
<Button
|
||||
x:Name="btnConnectionCloseAll"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuConnectionCloseAll}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="/Assets/delete.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left" />
|
||||
</WrapPanel>
|
||||
|
||||
<DataGrid
|
||||
x:Name="lstConnections"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding ConnectionItems}">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuConnectionClose" Header="{x:Static resx:ResUI.menuConnectionClose}" />
|
||||
<MenuItem x:Name="menuConnectionCloseAll" Header="{x:Static resx:ResUI.menuConnectionCloseAll}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="240"
|
||||
Binding="{Binding host}"
|
||||
Header="{x:Static resx:ResUI.TbSortingHost}" />
|
||||
<DataGridTextColumn
|
||||
Width="160"
|
||||
Binding="{Binding chain}"
|
||||
Header="{x:Static resx:ResUI.TbSortingChain}" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding network}"
|
||||
Header="{x:Static resx:ResUI.TbSortingNetwork}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding type}"
|
||||
Header="{x:Static resx:ResUI.TbSortingType}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding uploadTraffic}"
|
||||
Header="{x:Static resx:ResUI.TbSortingUpTraffic}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding downloadTraffic}"
|
||||
Header="{x:Static resx:ResUI.TbSortingDownTraffic}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding elapsed}"
|
||||
Header="{x:Static resx:ResUI.TbSortingTime}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</UserControl>
|
50
v2rayN/v2rayN.Desktop/Views/ClashConnectionsView.axaml.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class ClashConnectionsView : ReactiveUserControl<ClashConnectionsViewModel>
|
||||
{
|
||||
public ClashConnectionsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.ConnectionItems, v => v.lstConnections.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstConnections.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherRefreshConnections:
|
||||
if (obj is null) return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshConnections((List<ConnectionItem>?)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void btnClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ClashConnectionClose(false);
|
||||
}
|
||||
}
|
||||
}
|
179
v2rayN/v2rayN.Desktop/Views/ClashProxiesView.axaml
Normal file
|
@ -0,0 +1,179 @@
|
|||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.ClashProxiesView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:conv="using:v2rayN.Desktop.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:ClashProxiesViewModel"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.menuRulemode}" />
|
||||
<ComboBox
|
||||
x:Name="cmbRulemode"
|
||||
Width="80"
|
||||
Margin="8,0">
|
||||
<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"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSorting}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSorting"
|
||||
Width="60"
|
||||
Margin="8,0">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDelay}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingName}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.TbSortingDefault}" />
|
||||
</ComboBox>
|
||||
|
||||
<Button
|
||||
x:Name="menuProxiesReload"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesReload}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="/Assets/refresh.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="menuProxiesDelaytest"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProxiesDelaytest}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="/Assets/light.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left" />
|
||||
</WrapPanel>
|
||||
<DockPanel>
|
||||
<ListBox
|
||||
x:Name="lstProxyGroups"
|
||||
Margin="0,0,5,0"
|
||||
DockPanel.Dock="Left"
|
||||
ItemsSource="{Binding ProxyGroups}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Vertical" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Margin="4,0"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
<Grid Grid.Column="0" Classes="Margin4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel Grid.Row="0">
|
||||
<TextBlock DockPanel.Dock="Right" Text="{Binding type}" />
|
||||
<TextBlock Text="{Binding name}" />
|
||||
</DockPanel>
|
||||
<TextBlock Grid.Row="1" Text="{Binding now}" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<ListBox x:Name="lstProxyDetails" ItemsSource="{Binding ProxyDetails}">
|
||||
<ItemsControl.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuProxiesDelaytestPart" Header="{x:Static resx:ResUI.menuProxiesDelaytestPart}" />
|
||||
<MenuItem x:Name="menuProxiesSelectActivity" Header="{x:Static resx:ResUI.menuProxiesSelectActivity}" />
|
||||
</ContextMenu>
|
||||
</ItemsControl.ContextMenu>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
Width="160"
|
||||
Padding="0"
|
||||
Theme="{StaticResource CardBorder}">
|
||||
<DockPanel>
|
||||
<Border
|
||||
Width="5"
|
||||
Height="30"
|
||||
Margin="0,1"
|
||||
Background="YellowGreen"
|
||||
CornerRadius="4"
|
||||
DockPanel.Dock="Left"
|
||||
IsVisible="{Binding isActive}" />
|
||||
<Grid Classes="Margin4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Text="{Binding name}"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
<DockPanel Grid.Row="1">
|
||||
<TextBlock
|
||||
DockPanel.Dock="Right"
|
||||
Foreground="{Binding Path=delay, Converter={StaticResource DelayColorConverter}}"
|
||||
Text="{Binding delayName}" />
|
||||
<TextBlock Text="{Binding type}" />
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</DockPanel>
|
||||
</UserControl>
|
81
v2rayN/v2rayN.Desktop/Views/ClashProxiesView.axaml.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using Avalonia.Input;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class ClashProxiesView : ReactiveUserControl<ClashProxiesViewModel>
|
||||
{
|
||||
public ClashProxiesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel));
|
||||
lstProxyDetails.DoubleTapped += LstProxyDetails_DoubleTapped;
|
||||
this.KeyDown += ClashProxiesView_KeyDown;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.ProxyGroups, v => v.lstProxyGroups.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedGroup, v => v.lstProxyGroups.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, vm => vm.ProxyDetails, v => v.lstProxyDetails.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedDetail, v => v.lstProxyDetails.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.ProxiesReloadCmd, v => v.menuProxiesReload).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ProxiesDelaytestCmd, v => v.menuProxiesDelaytest).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.ProxiesDelaytestPartCmd, v => v.menuProxiesDelaytestPart).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ProxiesSelectActivityCmd, v => v.menuProxiesSelectActivity).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.RuleModeSelected, v => v.cmbRulemode.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SortingSelected, v => v.cmbSorting.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherRefreshProxyGroups:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshProxyGroups(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherProxiesDelayTest:
|
||||
if (obj is null) return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.ProxiesDelayTestResult((SpeedTestResult)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void ClashProxiesView_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.F5:
|
||||
ViewModel?.ProxiesReload();
|
||||
break;
|
||||
|
||||
case Key.Enter:
|
||||
ViewModel?.SetActiveProxy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProxyDetails_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.SetActiveProxy();
|
||||
}
|
||||
}
|
||||
}
|
174
v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml
Normal file
|
@ -0,0 +1,174 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.DNSSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuDNSSetting}"
|
||||
Width="1000"
|
||||
Height="700"
|
||||
x:DataType="vms:DNSSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<TabControl HorizontalContentAlignment="Left">
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDns}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsRemoteDNS}" />
|
||||
|
||||
<TextBlock VerticalAlignment="Center" Classes="Margin8">
|
||||
<Button Click="linkDnsObjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsObjectDoc}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4V2ray"
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUseSystemHosts}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togUseSystemHosts"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Freedom}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Freedom"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainDNSAddress"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<TextBox
|
||||
x:Name="txtnormalDNS"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="Http/Socks" />
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreDnsSingbox}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
|
||||
<TextBlock VerticalAlignment="Center" Classes="Margin8">
|
||||
<Button Click="linkDnsSingboxObjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbDnsSingboxObjectDoc}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
<Button
|
||||
x:Name="btnImportDefConfig4Singbox"
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.TbSettingDnsImportDefConfig}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<WrapPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainStrategy4Out}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Out"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDomainDNSAddress}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainDNSAddress2"
|
||||
Width="150"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
</WrapPanel>
|
||||
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox
|
||||
x:Name="txtnormalDNS2"
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="Http/Socks" />
|
||||
|
||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txttunDNS2"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.TbSettingsTunMode}" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
76
v2rayN/v2rayN.Desktop/Views/DNSSettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||
{
|
||||
private static Config _config;
|
||||
|
||||
public DNSSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_config = LazyConfig.Instance.Config;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||
|
||||
Global.DomainStrategy4Freedoms.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
||||
});
|
||||
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy4Out.Items.Add(it);
|
||||
});
|
||||
Global.DomainDNSAddress.ForEach(it =>
|
||||
{
|
||||
cmbdomainDNSAddress.Items.Add(it);
|
||||
});
|
||||
Global.SingboxDomainDNSAddress.ForEach(it =>
|
||||
{
|
||||
cmbdomainDNSAddress2.Items.Add(it);
|
||||
});
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.useSystemHosts, v => v.togUseSystemHosts.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom, v => v.cmbdomainStrategy4Freedom.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.domainDNSAddress, v => v.cmbdomainDNSAddress.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.normalDNS, v => v.txtnormalDNS.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.domainStrategy4Freedom2, v => v.cmbdomainStrategy4Out.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.domainDNSAddress2, v => v.cmbdomainDNSAddress2.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.normalDNS2, v => v.txtnormalDNS2.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.tunDNS2, v => v.txttunDNS2.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4V2rayCmd, v => v.btnImportDefConfig4V2ray).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportDefConfig4SingboxCmd, v => v.btnImportDefConfig4Singbox).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
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 linkDnsObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject");
|
||||
}
|
||||
|
||||
private void linkDnsSingboxObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
}
|
||||
}
|
||||
}
|
144
v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml
Normal file
|
@ -0,0 +1,144 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.GlobalHotkeySettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuSetting}"
|
||||
Width="700"
|
||||
Height="500"
|
||||
x:DataType="vms:SubEditViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
Classes="Margin4"
|
||||
HorizontalAlignment="Center"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnReset"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbReset}" />
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid x:Name="gridText" Grid.Row="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="400" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbGlobalHotkeySetting}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbDisplayGUI}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbClearSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey1"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSetSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey2"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True" />
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbNotChangeSystemProxy}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey3"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True" />
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbSystemProxyPac}" />
|
||||
<TextBox
|
||||
x:Name="txtGlobalHotkey4"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True" />
|
||||
</Grid>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Classes="Margin4"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbGlobalHotkeySettingTip}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
129
v2rayN/v2rayN.Desktop/Views/GlobalHotkeySettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class GlobalHotkeySettingWindow : Window
|
||||
{
|
||||
private static Config _config = default!;
|
||||
private Dictionary<object, KeyEventItem> _TextBoxKeyEventItem = default!;
|
||||
|
||||
public GlobalHotkeySettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = LazyConfig.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;
|
||||
|
||||
//HotkeyHandler.Instance.IsPause = true;
|
||||
//this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
//InitData();
|
||||
}
|
||||
|
||||
//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 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()
|
||||
// {
|
||||
// eGlobalHotkey = eg,
|
||||
// Control = false,
|
||||
// Alt = false,
|
||||
// Shift = false,
|
||||
// KeyCode = null
|
||||
// });
|
||||
//}
|
||||
|
||||
//private string KeyEventItemToString(KeyEventItem item)
|
||||
//{
|
||||
// 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();
|
||||
//}
|
||||
|
||||
//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;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void btnSave_Click(object? sender, RoutedEventArgs e)
|
||||
//{
|
||||
// _config.globalHotkeys = _TextBoxKeyEventItem.Values.ToList();
|
||||
|
||||
// if (ConfigHandler.SaveConfig(_config, false) == 0)
|
||||
// {
|
||||
// HotkeyHandler.Instance.ReLoad();
|
||||
// this.Close();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// UI.Show(ResUI.OperationFailed);
|
||||
// }
|
||||
//}
|
||||
|
||||
//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 GlobalHotkeySettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
//{
|
||||
// if (e.Key == Key.Escape)
|
||||
// {
|
||||
// this.Close();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
292
v2rayN/v2rayN.Desktop/Views/MainWindow.axaml
Normal file
|
@ -0,0 +1,292 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.MainWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="v2rayN"
|
||||
Width="900"
|
||||
Height="700"
|
||||
MinWidth="900"
|
||||
x:DataType="vms:MainWindowViewModel"
|
||||
Icon="/Assets/NotifyIcon1.ico"
|
||||
ShowInTaskbar="True"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<DockPanel>
|
||||
<DockPanel Classes="Margin8" DockPanel.Dock="Top">
|
||||
<ContentControl x:Name="conTheme" DockPanel.Dock="Right" />
|
||||
<Menu Margin="0,1">
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuServers}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
<MenuItem x:Name="menuAddServerViaClipboard" Header="{x:Static resx:ResUI.menuAddServerViaClipboard}" />
|
||||
<MenuItem
|
||||
x:Name="menuAddServerViaScan"
|
||||
Header="{x:Static resx:ResUI.menuAddServerViaScan}"
|
||||
IsVisible="False" />
|
||||
<MenuItem x:Name="menuAddCustomServer" Header="{x:Static resx:ResUI.menuAddCustomServer}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuAddVmessServer" Header="{x:Static resx:ResUI.menuAddVmessServer}" />
|
||||
<MenuItem x:Name="menuAddVlessServer" Header="{x:Static resx:ResUI.menuAddVlessServer}" />
|
||||
<MenuItem x:Name="menuAddShadowsocksServer" Header="{x:Static resx:ResUI.menuAddShadowsocksServer}" />
|
||||
<MenuItem x:Name="menuAddSocksServer" Header="{x:Static resx:ResUI.menuAddSocksServer}" />
|
||||
<MenuItem x:Name="menuAddHttpServer" Header="{x:Static resx:ResUI.menuAddHttpServer}" />
|
||||
<MenuItem x:Name="menuAddTrojanServer" Header="{x:Static resx:ResUI.menuAddTrojanServer}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuAddHysteria2Server" Header="{x:Static resx:ResUI.menuAddHysteria2Server}" />
|
||||
<MenuItem x:Name="menuAddTuicServer" Header="{x:Static resx:ResUI.menuAddTuicServer}" />
|
||||
<MenuItem x:Name="menuAddWireguardServer" Header="{x:Static resx:ResUI.menuAddWireguardServer}" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSubscription}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
<MenuItem x:Name="menuSubSetting" Header="{x:Static resx:ResUI.menuSubSetting}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuSubUpdate" Header="{x:Static resx:ResUI.menuSubUpdate}" />
|
||||
<MenuItem x:Name="menuSubUpdateViaProxy" Header="{x:Static resx:ResUI.menuSubUpdateViaProxy}" />
|
||||
<MenuItem x:Name="menuSubGroupUpdate" Header="{x:Static resx:ResUI.menuSubGroupUpdate}" />
|
||||
<MenuItem x:Name="menuSubGroupUpdateViaProxy" Header="{x:Static resx:ResUI.menuSubGroupUpdateViaProxy}" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuSetting}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
<MenuItem x:Name="menuOptionSetting" Header="{x:Static resx:ResUI.menuOptionSetting}" />
|
||||
<MenuItem x:Name="menuRoutingSetting" Header="{x:Static resx:ResUI.menuRoutingSetting}" />
|
||||
<MenuItem x:Name="menuDNSSetting" Header="{x:Static resx:ResUI.menuDNSSetting}" />
|
||||
<MenuItem x:Name="menuGlobalHotkeySetting" Header="{x:Static resx:ResUI.menuGlobalHotkeySetting}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuRebootAsAdmin" Header="{x:Static resx:ResUI.menuRebootAsAdmin}" />
|
||||
<MenuItem x:Name="menuSettingsSetUWP" Header="{x:Static resx:ResUI.TbSettingsSetUWP}" />
|
||||
<MenuItem x:Name="menuClearServerStatistics" Header="{x:Static resx:ResUI.menuClearServerStatistics}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuOpenTheFileLocation" Header="{x:Static resx:ResUI.menuOpenTheFileLocation}" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem x:Name="menuReload" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuReload}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuCheckUpdate}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
<MenuItem x:Name="menuCheckUpdateN" Header="V2rayN" />
|
||||
<MenuItem x:Name="menuCheckUpdateXrayCore" Header="Xray Core" />
|
||||
<MenuItem x:Name="menuCheckUpdateMihomoCore" Header="Mihomo Core" />
|
||||
<MenuItem x:Name="menuCheckUpdateSingBoxCore" Header="Sing-box Core" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuCheckUpdateGeo" Header="Geo files" />
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem x:Name="menuHelp" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuHelp}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem x:Name="menuPromotion" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuPromotion}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem x:Name="menuClose" Padding="8,0">
|
||||
<MenuItem.Header>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{x:Static resx:ResUI.menuClose}" />
|
||||
</StackPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</DockPanel>
|
||||
|
||||
<StackPanel Height="50" DockPanel.Dock="Bottom">
|
||||
<DockPanel>
|
||||
<StackPanel
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Right">
|
||||
<TextBlock x:Name="txtSpeedProxyDisplay" />
|
||||
<Border Margin="2" />
|
||||
<TextBlock x:Name="txtSpeedDirectDisplay" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Width="240"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left">
|
||||
<TextBlock x:Name="txtInboundDisplay" />
|
||||
<Border Margin="2" />
|
||||
<TextBlock x:Name="txtInboundLanDisplay" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
x:Name="spEnableTun"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbEnableTunAs}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableTun"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Orientation="Horizontal">
|
||||
<ComboBox
|
||||
x:Name="cmbSystemProxy"
|
||||
Width="120"
|
||||
Margin="8,0"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSystemproxy}">
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyClear}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxySet}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyNothing}" />
|
||||
<ComboBoxItem Content="{x:Static resx:ResUI.menuSystemProxyPac}" />
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox
|
||||
x:Name="cmbRoutings2"
|
||||
Width="150"
|
||||
Margin="8,0"
|
||||
DisplayMemberBinding="{Binding remarks}"
|
||||
ItemsSource="{Binding RoutingItems}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuRouting}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="8,0" VerticalAlignment="Center">
|
||||
<TextBlock x:Name="txtRunningServerDisplay" Tapped="TxtRunningServerDisplay_Tapped" />
|
||||
<Border Margin="2" />
|
||||
<TextBlock x:Name="txtRunningInfoDisplay" Tapped="TxtRunningServerDisplay_Tapped" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Grid>
|
||||
<Grid x:Name="gridMain" IsVisible="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl x:Name="tabProfiles" Grid.Column="0" />
|
||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||
<TabControl
|
||||
x:Name="tabMain"
|
||||
Grid.Column="2"
|
||||
HorizontalContentAlignment="Left">
|
||||
<TabItem x:Name="tabMsgView" Header="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
<TabItem x:Name="tabClashProxies" Header="{x:Static resx:ResUI.TbProxies}" />
|
||||
<TabItem x:Name="tabClashConnections" Header="{x:Static resx:ResUI.TbConnections}" />
|
||||
</TabControl>
|
||||
</Grid>
|
||||
<Grid x:Name="gridMain1" IsVisible="False">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1*" />
|
||||
<RowDefinition Height="10" />
|
||||
<RowDefinition Height="1*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ContentControl x:Name="tabProfiles1" Grid.Row="0" />
|
||||
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" />
|
||||
<TabControl
|
||||
x:Name="tabMain1"
|
||||
Grid.Row="2"
|
||||
TabStripPlacement="Left">
|
||||
<TabItem x:Name="tabMsgView1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashProxies1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbProxies}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashConnections1">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbConnections}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
<Grid x:Name="gridMain2" IsVisible="False">
|
||||
<TabControl x:Name="tabMain2" TabStripPlacement="Left">
|
||||
<TabItem x:Name="tabProfiles2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.menuServers}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabMsgView2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.MsgInformationTitle}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashProxies2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbProxies}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
<TabItem x:Name="tabClashConnections2">
|
||||
<TabItem.Header>
|
||||
<StackPanel>
|
||||
|
||||
<TextBlock HorizontalAlignment="Center" Text="{x:Static resx:ResUI.TbConnections}" />
|
||||
</StackPanel>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</DockPanel>
|
||||
|
||||
</Window>
|
474
v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs
Normal file
|
@ -0,0 +1,474 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Controls.Notifications;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
{
|
||||
private static Config _config;
|
||||
private WindowNotificationManager? _manager;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_config = LazyConfig.Instance.Config;
|
||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
||||
|
||||
//ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||
|
||||
this.Closing += MainWindow_Closing;
|
||||
this.KeyDown += MainWindow_KeyDown;
|
||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||
menuPromotion.Click += menuPromotion_Click;
|
||||
menuClose.Click += menuClose_Click;
|
||||
|
||||
MessageBus.Current.Listen<string>(Global.CommandSendSnackMsg).Subscribe(x => DelegateSnackMsg(x));
|
||||
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
||||
|
||||
//WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
//servers
|
||||
this.BindCommand(ViewModel, vm => vm.AddVmessServerCmd, v => v.menuAddVmessServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddVlessServerCmd, v => v.menuAddVlessServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddShadowsocksServerCmd, v => v.menuAddShadowsocksServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddSocksServerCmd, v => v.menuAddSocksServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddHttpServerCmd, v => v.menuAddHttpServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddTrojanServerCmd, v => v.menuAddTrojanServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddHysteria2ServerCmd, v => v.menuAddHysteria2Server).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddTuicServerCmd, v => v.menuAddTuicServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddWireguardServerCmd, v => v.menuAddWireguardServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan).DisposeWith(disposables);
|
||||
|
||||
//sub
|
||||
this.BindCommand(ViewModel, vm => vm.SubSettingCmd, v => v.menuSubSetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubGroupUpdateCmd, v => v.menuSubGroupUpdate).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubGroupUpdateViaProxyCmd, v => v.menuSubGroupUpdateViaProxy).DisposeWith(disposables);
|
||||
|
||||
//setting
|
||||
this.BindCommand(ViewModel, vm => vm.OptionSettingCmd, v => v.menuOptionSetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingSettingCmd, v => v.menuRoutingSetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.DNSSettingCmd, v => v.menuDNSSetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.GlobalHotkeySettingCmd, v => v.menuGlobalHotkeySetting).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RebootAsAdminCmd, v => v.menuRebootAsAdmin).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ClearServerStatisticsCmd, v => v.menuClearServerStatistics).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.OpenTheFileLocationCmd, v => v.menuOpenTheFileLocation).DisposeWith(disposables);
|
||||
|
||||
//check update
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateNCmd, v => v.menuCheckUpdateN).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateMihomoCore).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateSingBoxCoreCmd, v => v.menuCheckUpdateSingBoxCore).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables);
|
||||
|
||||
//status bar
|
||||
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables);
|
||||
//this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||
{
|
||||
gridMain.IsVisible = true;
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies.IsVisible).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections.IsVisible).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain.SelectedIndex).DisposeWith(disposables);
|
||||
}
|
||||
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||
{
|
||||
gridMain1.IsVisible = true;
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies1.IsVisible).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections1.IsVisible).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain1.SelectedIndex).DisposeWith(disposables);
|
||||
}
|
||||
else
|
||||
{
|
||||
gridMain2.IsVisible = true;
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashProxies2.IsVisible).DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabClashConnections2.IsVisible).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TabMainSelectedIndex, v => v.tabMain2.SelectedIndex).DisposeWith(disposables);
|
||||
}
|
||||
});
|
||||
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
var IsAdministrator = false;//WindowsUtils.IsAdministrator();
|
||||
ViewModel.IsAdministrator = IsAdministrator;
|
||||
this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
|
||||
if (_config.tunModeItem.enableTun)
|
||||
{
|
||||
if (IsAdministrator)
|
||||
{
|
||||
ViewModel.EnableTun = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_config.tunModeItem.enableTun = ViewModel.EnableTun = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel.IsAdministrator = true;
|
||||
this.Title = $"{Utils.GetVersion()}";
|
||||
menuRebootAsAdmin.IsVisible = false;
|
||||
menuSettingsSetUWP.IsVisible = false;
|
||||
menuGlobalHotkeySetting.IsVisible = false;
|
||||
menuOpenTheFileLocation.IsVisible = false;
|
||||
cmbSystemProxy.IsVisible = false;
|
||||
if (_config.tunModeItem.enableTun)
|
||||
{
|
||||
ViewModel.EnableTun = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||
{
|
||||
tabProfiles.Content ??= new ProfilesView(this);
|
||||
tabMsgView.Content ??= new MsgView();
|
||||
tabClashProxies.Content ??= new ClashProxiesView();
|
||||
tabClashConnections.Content ??= new ClashConnectionsView();
|
||||
}
|
||||
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||
{
|
||||
tabProfiles1.Content ??= new ProfilesView(this);
|
||||
tabMsgView1.Content ??= new MsgView();
|
||||
tabClashProxies1.Content ??= new ClashProxiesView();
|
||||
tabClashConnections1.Content ??= new ClashConnectionsView();
|
||||
}
|
||||
else
|
||||
{
|
||||
tabProfiles2.Content ??= new ProfilesView(this);
|
||||
tabMsgView2.Content ??= new MsgView();
|
||||
tabClashProxies2.Content ??= new ClashProxiesView();
|
||||
tabClashConnections2.Content ??= new ClashConnectionsView();
|
||||
}
|
||||
conTheme.Content ??= new ThemeSettingView();
|
||||
|
||||
RestoreUI();
|
||||
AddHelpMenuItem();
|
||||
}
|
||||
|
||||
#region Event
|
||||
|
||||
private void OnProgramStarted(object state, bool timeout)
|
||||
{
|
||||
ShowHideWindow(true);
|
||||
}
|
||||
|
||||
private void DelegateSnackMsg(string content)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
_manager?.Show(new Notification(null, content, NotificationType.Information)),
|
||||
DispatcherPriority.Normal);
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.AddServerWindow:
|
||||
if (obj is null) return false;
|
||||
return await new AddServerWindow((ProfileItem)obj).ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.AddServer2Window:
|
||||
if (obj is null) return false;
|
||||
return await new AddServer2Window((ProfileItem)obj).ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.DNSSettingWindow:
|
||||
return await new DNSSettingWindow().ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.RoutingSettingWindow:
|
||||
return await new RoutingSettingWindow().ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.OptionSettingWindow:
|
||||
return await new OptionSettingWindow().ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.GlobalHotkeySettingWindow:
|
||||
return await new GlobalHotkeySettingWindow().ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.SubSettingWindow:
|
||||
return await new SubSettingWindow().ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.ShowHideWindow:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ShowHideWindow((bool?)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherStatistics:
|
||||
if (obj is null) return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.SetStatisticsResult((ServerSpeedItem)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherServerAvailability:
|
||||
if (obj is null) return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.TestServerAvailabilityResult((string)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherReload:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.ReloadResult(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshServersBiz(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshIcon:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
this.Icon = AvaUtils.GetAppIcon(_config.systemProxyItem.sysProxyType);
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.Shutdown:
|
||||
StorageUI();
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.Shutdown();
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.ScanScreenTask:
|
||||
ScanScreenTaskAsync().ContinueWith(_ => { });
|
||||
break;
|
||||
|
||||
case EViewAction.UpdateSysProxy:
|
||||
if (obj is null) return false;
|
||||
// await SysProxyHandler.UpdateSysProxy(_config, (bool)obj);
|
||||
break;
|
||||
|
||||
case EViewAction.AddServerViaClipboard:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void OnHotkeyHandler(EGlobalHotkey e)
|
||||
{
|
||||
switch (e)
|
||||
{
|
||||
case EGlobalHotkey.ShowForm:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private void MainWindow_Closing(object? sender, CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
ShowHideWindow(false);
|
||||
}
|
||||
|
||||
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.V:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
ViewModel?.AddServerViaClipboardAsync(clipboardData);
|
||||
break;
|
||||
|
||||
case Key.S:
|
||||
ScanScreenTaskAsync().ContinueWith(_ => { });
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Key == Key.F5)
|
||||
{
|
||||
ViewModel?.Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
StorageUI();
|
||||
ShowHideWindow(false);
|
||||
}
|
||||
|
||||
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
|
||||
}
|
||||
|
||||
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.TestServerAvailability();
|
||||
}
|
||||
|
||||
private void menuSettingsSetUWP_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||
}
|
||||
|
||||
public async Task ScanScreenTaskAsync()
|
||||
{
|
||||
ShowHideWindow(false);
|
||||
|
||||
//var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow);
|
||||
//string result = await Task.Run(() =>
|
||||
//{
|
||||
// return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2);
|
||||
//});
|
||||
|
||||
ShowHideWindow(true);
|
||||
|
||||
//ViewModel?.ScanScreenTaskAsync(result);
|
||||
}
|
||||
|
||||
#endregion Event
|
||||
|
||||
#region UI
|
||||
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow ?? !_config.uiItem.showInTaskbar;
|
||||
if (bl)
|
||||
{
|
||||
this.Show();
|
||||
if (this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
this.WindowState = WindowState.Normal;
|
||||
}
|
||||
this.Activate();
|
||||
this.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Hide();
|
||||
}
|
||||
_config.uiItem.showInTaskbar = bl;
|
||||
}
|
||||
|
||||
private void RestoreUI()
|
||||
{
|
||||
if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0)
|
||||
{
|
||||
Width = _config.uiItem.mainWidth;
|
||||
Height = _config.uiItem.mainHeight;
|
||||
}
|
||||
|
||||
if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0)
|
||||
{
|
||||
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||
{
|
||||
gridMain.ColumnDefinitions[0].Width = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
||||
gridMain.ColumnDefinitions[2].Width = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
||||
}
|
||||
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||
{
|
||||
gridMain1.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star);
|
||||
gridMain1.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StorageUI()
|
||||
{
|
||||
_config.uiItem.mainWidth = Utils.ToInt(this.Width);
|
||||
_config.uiItem.mainHeight = Utils.ToInt(this.Height);
|
||||
|
||||
if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal)
|
||||
{
|
||||
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.ColumnDefinitions[0].ActualWidth + 0.1);
|
||||
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.ColumnDefinitions[2].ActualWidth + 0.1);
|
||||
}
|
||||
else if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Vertical)
|
||||
{
|
||||
_config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||
_config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||
}
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
|
||||
private void AddHelpMenuItem()
|
||||
{
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||
foreach (var it in coreInfo
|
||||
.Where(t => t.coreType != ECoreType.v2fly
|
||||
&& t.coreType != ECoreType.clash
|
||||
&& t.coreType != ECoreType.clash_meta
|
||||
&& t.coreType != ECoreType.hysteria))
|
||||
{
|
||||
var item = new MenuItem()
|
||||
{
|
||||
Tag = it.coreUrl.Replace(@"/releases", ""),
|
||||
Header = string.Format(ResUI.menuWebsiteItem, it.coreType.ToString().Replace("_", " ")).UpperFirstChar()
|
||||
};
|
||||
item.Click += MenuItem_Click;
|
||||
menuHelp.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuItem_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem item)
|
||||
{
|
||||
Utils.ProcessStart(item.Tag.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion UI
|
||||
}
|
||||
}
|
107
v2rayN/v2rayN.Desktop/Views/MsgView.axaml
Normal file
|
@ -0,0 +1,107 @@
|
|||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.MsgView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Margin="2">
|
||||
<WrapPanel
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBox
|
||||
x:Name="cmbMsgFilter"
|
||||
Width="200"
|
||||
Margin="8,0"
|
||||
VerticalContentAlignment="Center"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.MsgFilterTitle}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnCopy"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Click="menuMsgViewCopyAll_Click"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewCopyAll}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="/Assets/copy.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="btnClear"
|
||||
Width="24"
|
||||
Height="24"
|
||||
Margin="8,0"
|
||||
Classes="Success"
|
||||
Click="menuMsgViewClear_Click"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuMsgViewClear}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="16"
|
||||
Height="16"
|
||||
Source="/Assets/delete.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbAutoRefresh}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRefresh"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True" />
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="False"
|
||||
Text="{x:Static resx:ResUI.TbAutoScrollToEnd}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togScrollToEnd"
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Left"
|
||||
IsChecked="True"
|
||||
IsVisible="False" />
|
||||
</WrapPanel>
|
||||
<TextBox
|
||||
Name="txtMsg"
|
||||
BorderThickness="0"
|
||||
Classes="TextArea"
|
||||
IsReadOnly="True"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap">
|
||||
<TextBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem
|
||||
x:Name="menuMsgViewSelectAll"
|
||||
Click="menuMsgViewSelectAll_Click"
|
||||
Header="{x:Static resx:ResUI.menuMsgViewSelectAll}" />
|
||||
<MenuItem
|
||||
x:Name="menuMsgViewCopy"
|
||||
Click="menuMsgViewCopy_Click"
|
||||
Header="{x:Static resx:ResUI.menuMsgViewCopy}" />
|
||||
<MenuItem
|
||||
x:Name="menuMsgViewCopyAll"
|
||||
Click="menuMsgViewCopyAll_Click"
|
||||
Header="{x:Static resx:ResUI.menuMsgViewCopyAll}" />
|
||||
<MenuItem
|
||||
x:Name="menuMsgViewClear"
|
||||
Click="menuMsgViewClear_Click"
|
||||
Header="{x:Static resx:ResUI.menuMsgViewClear}" />
|
||||
</ContextMenu>
|
||||
</TextBox.ContextMenu>
|
||||
</TextBox>
|
||||
</DockPanel>
|
||||
</UserControl>
|
127
v2rayN/v2rayN.Desktop/Views/MsgView.axaml.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text.RegularExpressions;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class MsgView : UserControl
|
||||
{
|
||||
private static Config? _config;
|
||||
|
||||
private string lastMsgFilter = string.Empty;
|
||||
private bool lastMsgFilterNotAvailable;
|
||||
private ConcurrentBag<string> _lstMsg = [];
|
||||
|
||||
public MsgView()
|
||||
{
|
||||
InitializeComponent();
|
||||
_config = LazyConfig.Instance.Config;
|
||||
MessageBus.Current.Listen<string>(Global.CommandSendMsgView).Subscribe(x => DelegateAppendText(x));
|
||||
//Global.PresetMsgFilters.ForEach(it =>
|
||||
//{
|
||||
// cmbMsgFilter.Items.Add(it);
|
||||
//});
|
||||
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
|
||||
{
|
||||
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter;
|
||||
}
|
||||
cmbMsgFilter.TextChanged += (s, e) =>
|
||||
{
|
||||
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text?.ToString();
|
||||
};
|
||||
}
|
||||
|
||||
private void DelegateAppendText(string msg)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => AppendText(msg), DispatcherPriority.ApplicationIdle);
|
||||
}
|
||||
|
||||
public void AppendText(string msg)
|
||||
{
|
||||
if (msg == Global.CommandClearMsg)
|
||||
{
|
||||
ClearMsg();
|
||||
return;
|
||||
}
|
||||
if (togAutoRefresh.IsChecked == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var MsgFilter = cmbMsgFilter.Text?.ToString();
|
||||
if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
|
||||
if (!Utils.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Regex.IsMatch(msg, MsgFilter))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
lastMsgFilterNotAvailable = true;
|
||||
}
|
||||
}
|
||||
lastMsgFilter = MsgFilter;
|
||||
|
||||
ShowMsg(msg);
|
||||
|
||||
if (togScrollToEnd.IsChecked ?? true)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowMsg(string msg)
|
||||
{
|
||||
if (_lstMsg.Count > 999)
|
||||
{
|
||||
ClearMsg();
|
||||
}
|
||||
if (!msg.EndsWith(Environment.NewLine))
|
||||
{
|
||||
_lstMsg.Add(Environment.NewLine);
|
||||
}
|
||||
_lstMsg.Add(msg);
|
||||
// if (!msg.EndsWith(Environment.NewLine))
|
||||
// {
|
||||
// _lstMsg.Add(Environment.NewLine);
|
||||
// }
|
||||
this.txtMsg.Text = string.Join("", _lstMsg);
|
||||
}
|
||||
|
||||
public void ClearMsg()
|
||||
{
|
||||
_lstMsg.Clear();
|
||||
txtMsg.Clear();
|
||||
}
|
||||
|
||||
private void menuMsgViewSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtMsg.Focus();
|
||||
txtMsg.SelectAll();
|
||||
}
|
||||
|
||||
private async void menuMsgViewCopy_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var data = txtMsg.SelectedText.TrimEx();
|
||||
await AvaUtils.SetClipboardData(this, data);
|
||||
}
|
||||
|
||||
private async void menuMsgViewCopyAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var data = txtMsg.Text.TrimEx();
|
||||
await AvaUtils.SetClipboardData(this, data);
|
||||
}
|
||||
|
||||
private void menuMsgViewClear_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ClearMsg();
|
||||
}
|
||||
}
|
||||
}
|
857
v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml
Normal file
|
@ -0,0 +1,857 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.OptionSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuSetting}"
|
||||
Width="1000"
|
||||
Height="700"
|
||||
x:DataType="vms:OptionSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<TabControl HorizontalContentAlignment="Left">
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCore}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSocksPort}" />
|
||||
<TextBox
|
||||
x:Name="txtlocalPort"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSocksPortTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUdpEnabled}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togudpEnabled"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSniffingEnabled}" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Orientation="Horizontal">
|
||||
<ToggleSwitch
|
||||
x:Name="togsniffingEnabled"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<ListBox
|
||||
x:Name="clbdestOverride"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsRouteOnly}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togrouteOnly"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAllowLAN}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAllowLANConn"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsNewPort4LAN}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togNewPort4LAN"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsUser}" />
|
||||
<TextBox
|
||||
x:Name="txtuser"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsPass}" />
|
||||
<TextBox
|
||||
x:Name="txtpass"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsMuxEnabled}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togmuxEnabled"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogEnabledToFile}" />
|
||||
<ToggleSwitch
|
||||
x:Name="toglogEnabled"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLogLevel}" />
|
||||
<ComboBox
|
||||
x:Name="cmbloglevel"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="Level" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefAllowInsecure}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togdefAllowInsecure"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="12"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefFingerprint}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdefFingerprint"
|
||||
Grid.Row="12"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="13"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefUserAgent}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdefUserAgent"
|
||||
Grid.Row="13"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="13"
|
||||
Grid.Column="3"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDefUserAgentTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="14"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsMux4SboxProtocol}" />
|
||||
<ComboBox
|
||||
x:Name="cmbmux4SboxProtocol"
|
||||
Grid.Row="14"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="15"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableCacheFile4Sbox}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togenableCacheFile4Sbox"
|
||||
Grid.Row="15"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="16"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsHysteriaBandwidth}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="16"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBox
|
||||
x:Name="txtUpMbps"
|
||||
Width="90"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="Up" />
|
||||
<TextBox
|
||||
x:Name="txtDownMbps"
|
||||
Width="90"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="Down" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="17"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableFragment}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togenableFragment"
|
||||
Grid.Row="17"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="17"
|
||||
Grid.Column="3"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableFragmentTips}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsN}">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Visible">
|
||||
<Grid Grid.Row="2" Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsStartBoot}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoRun"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsStartBootTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsStatistics}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableStatistics"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsKeepOlderDedupl}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togKeepOlderDedupl"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsIgnoreGeoUpdateCore}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togIgnoreGeoUpdateCore"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableAutoAdjustMainLvColWidth}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableAutoAdjustMainLvColWidth"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableUpdateSubOnlyRemarksExist}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableUpdateSubOnlyRemarksExist"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsTLS13}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableSecurityProtocolTls13"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAutoHideStartup}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togAutoHideStartup"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableCheckPreReleaseUpdate}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableCheckPreReleaseUpdate"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableDragDropSort}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableDragDropSort"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsDoubleClick2Activate}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togDoubleClick2Activate"
|
||||
Grid.Row="11"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="14"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAutoUpdateInterval}" />
|
||||
<TextBox
|
||||
x:Name="txtautoUpdateInterval"
|
||||
Grid.Row="14"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="16"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsVisible="False"
|
||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamily}" />
|
||||
<ComboBox
|
||||
x:Name="cmbcurrentFontFamily"
|
||||
Grid.Row="16"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8"
|
||||
IsVisible="False"
|
||||
MaxDropDownHeight="1000" />
|
||||
<TextBlock
|
||||
Grid.Row="16"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
IsVisible="False"
|
||||
Text="{x:Static resx:ResUI.TbSettingsCurrentFontFamilyTip}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="17"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestTimeout}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSpeedTestTimeout"
|
||||
Grid.Row="17"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="18"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSpeedTestUrl}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSpeedTestUrl"
|
||||
Grid.Row="18"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="19"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSpeedPingTestUrl}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSpeedPingTestUrl"
|
||||
Grid.Row="19"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="20"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsSubConvert}" />
|
||||
<ComboBox
|
||||
x:Name="cmbSubConvertUrl"
|
||||
Grid.Row="20"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="Convert Url" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="21"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsMainGirdOrientation}" />
|
||||
<ComboBox
|
||||
x:Name="cmbMainGirdOrientation"
|
||||
Grid.Row="21"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
Classes="Margin8" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Name="tabSystemproxy" Header="{x:Static resx:ResUI.TbSettingsSystemproxy}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsNotProxyLocalAddress}" />
|
||||
<ToggleSwitch
|
||||
x:Name="tognotProxyLocalAddress"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsAdvancedProtocol}" />
|
||||
<ComboBox
|
||||
x:Name="cmbsystemProxyAdvancedProtocol"
|
||||
MinWidth="400"
|
||||
Classes="Margin8"
|
||||
ToolTip.Tip="Protocol" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Text="{x:Static resx:ResUI.TbSettingsExceptionTip}" />
|
||||
<TextBox
|
||||
x:Name="txtsystemProxyExceptions"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderThickness="1"
|
||||
Classes="TextArea Margin8"
|
||||
TextWrapping="Wrap" />
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsTunMode}">
|
||||
<DockPanel Classes="Margin8">
|
||||
<Grid Classes="Margin8" DockPanel.Dock="Top">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Strict Route" />
|
||||
<ToggleSwitch
|
||||
x:Name="togStrictRoute"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Stack" />
|
||||
<ComboBox
|
||||
x:Name="cmbStack"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Mtu" />
|
||||
<ComboBox
|
||||
x:Name="cmbMtu"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableExInbound}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableExInbound"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsEnableIPv6Address}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnableIPv6Address"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin8" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static resx:ResUI.TbSettingsCoreType}">
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="VMess" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType1"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Custom" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType2"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Shadowsocks" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType3"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Socks" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType4"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="VLESS" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType5"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="Trojan" />
|
||||
<ComboBox
|
||||
x:Name="cmbCoreType6"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin8" />
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
232
v2rayN/v2rayN.Desktop/Views/OptionSettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,232 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
||||
{
|
||||
private static Config _config;
|
||||
|
||||
public OptionSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = LazyConfig.Instance.Config;
|
||||
// var lstFonts = GetFonts(Utils.GetFontsPath());
|
||||
|
||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||
|
||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||
Global.destOverrideProtocols.ForEach(it =>
|
||||
{
|
||||
clbdestOverride.Items.Add(it);
|
||||
});
|
||||
_config.inbound[0].destOverride?.ForEach(it =>
|
||||
{
|
||||
clbdestOverride.SelectedItems.Add(it);
|
||||
});
|
||||
Global.IEProxyProtocols.ForEach(it =>
|
||||
{
|
||||
cmbsystemProxyAdvancedProtocol.Items.Add(it);
|
||||
});
|
||||
Global.LogLevels.ForEach(it =>
|
||||
{
|
||||
cmbloglevel.Items.Add(it);
|
||||
});
|
||||
Global.Fingerprints.ForEach(it =>
|
||||
{
|
||||
cmbdefFingerprint.Items.Add(it);
|
||||
});
|
||||
Global.UserAgent.ForEach(it =>
|
||||
{
|
||||
cmbdefUserAgent.Items.Add(it);
|
||||
});
|
||||
Global.SingboxMuxs.ForEach(it =>
|
||||
{
|
||||
cmbmux4SboxProtocol.Items.Add(it);
|
||||
});
|
||||
|
||||
Global.TunMtus.ForEach(it =>
|
||||
{
|
||||
cmbMtu.Items.Add(it);
|
||||
});
|
||||
Global.TunStacks.ForEach(it =>
|
||||
{
|
||||
cmbStack.Items.Add(it);
|
||||
});
|
||||
Global.CoreTypes.ForEach(it =>
|
||||
{
|
||||
cmbCoreType1.Items.Add(it);
|
||||
cmbCoreType2.Items.Add(it);
|
||||
cmbCoreType3.Items.Add(it);
|
||||
cmbCoreType4.Items.Add(it);
|
||||
cmbCoreType5.Items.Add(it);
|
||||
cmbCoreType6.Items.Add(it);
|
||||
});
|
||||
|
||||
for (int i = 2; i <= 6; i++)
|
||||
{
|
||||
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);
|
||||
});
|
||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||
{
|
||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||
}
|
||||
|
||||
//lstFonts.ForEach(it => { cmbcurrentFontFamily.Items.Add(it); });
|
||||
//cmbcurrentFontFamily.Items.Add(string.Empty);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.udpEnabled, v => v.togudpEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.sniffingEnabled, v => v.togsniffingEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.routeOnly, v => v.togrouteOnly.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.allowLANConn, v => v.togAllowLANConn.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.newPort4LAN, v => v.togNewPort4LAN.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.newPort4LAN, v => v.txtuser.IsEnabled).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.newPort4LAN, v => v.txtpass.IsEnabled).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.user, v => v.txtuser.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.pass, v => v.txtpass.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.muxEnabled, v => v.togmuxEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.logEnabled, v => v.toglogEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.loglevel, v => v.cmbloglevel.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defAllowInsecure, v => v.togdefAllowInsecure.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defFingerprint, v => v.cmbdefFingerprint.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.defUserAgent, v => v.cmbdefUserAgent.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.mux4SboxProtocol, v => v.cmbmux4SboxProtocol.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.enableCacheFile4Sbox, v => v.togenableCacheFile4Sbox.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.hyUpMbps, v => v.txtUpMbps.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.hyDownMbps, v => v.txtDownMbps.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.enableFragment, v => v.togenableFragment.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.AutoRun, v => v.togAutoRun.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableStatistics, v => v.togEnableStatistics.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.KeepOlderDedupl, v => v.togKeepOlderDedupl.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.IgnoreGeoUpdateCore, v => v.togIgnoreGeoUpdateCore.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableAutoAdjustMainLvColWidth, v => v.togEnableAutoAdjustMainLvColWidth.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableUpdateSubOnlyRemarksExist, v => v.togEnableUpdateSubOnlyRemarksExist.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableSecurityProtocolTls13, v => v.togEnableSecurityProtocolTls13.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoHideStartup, v => v.togAutoHideStartup.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.EnableDragDropSort, v => v.togEnableDragDropSort.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.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.SubConvertUrl, v => v.cmbSubConvertUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.notProxyLocalAddress, v => v.tognotProxyLocalAddress.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.systemProxyAdvancedProtocol, v => v.cmbsystemProxyAdvancedProtocol.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.systemProxyExceptions, v => v.txtsystemProxyExceptions.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.TunStrictRoute, v => v.togStrictRoute.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunStack, v => v.cmbStack.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunMtu, v => v.cmbMtu.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableExInbound, v => v.togEnableExInbound.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.TunEnableIPv6Address, v => v.togEnableIPv6Address.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType3, v => v.cmbCoreType3.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType4, v => v.cmbCoreType4.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType5, v => v.cmbCoreType5.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType6, v => v.cmbCoreType6.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
//if (Utils.IsWindows())
|
||||
//{
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
tabSystemproxy.IsVisible = false;
|
||||
//}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
// WindowsUtils.SetAutoRun(Global.AutoRunRegPath, Global.AutoRunName, togAutoRun.IsChecked ?? false);
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
//private List<string> GetFonts(string path)
|
||||
//{
|
||||
// var lstFonts = new List<string>();
|
||||
// try
|
||||
// {
|
||||
// string[] searchPatterns = { "*.ttf", "*.ttc" };
|
||||
// var files = new List<string>();
|
||||
// foreach (var pattern in searchPatterns)
|
||||
// {
|
||||
// files.AddRange(Directory.GetFiles(path, pattern));
|
||||
// }
|
||||
// var culture = _config.uiItem.currentLanguage == Global.Languages[0] ? "zh-cn" : "en-us";
|
||||
// var culture2 = "en-us";
|
||||
// foreach (var ttf in files)
|
||||
// {
|
||||
// var families = Fonts.GetFontFamilies(Utils.GetFontsPath(ttf));
|
||||
// foreach (FontFamily family in families)
|
||||
// {
|
||||
// var typefaces = family.GetTypefaces();
|
||||
// foreach (Typeface typeface in typefaces)
|
||||
// {
|
||||
// typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
|
||||
// //var fontFace = glyph.Win32FaceNames[new CultureInfo("en-us")];
|
||||
// //if (!fontFace.Equals("Regular") && !fontFace.Equals("Normal"))
|
||||
// //{
|
||||
// // continue;
|
||||
// //}
|
||||
// var fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture)];
|
||||
// if (Utils.IsNullOrEmpty(fontFamily))
|
||||
// {
|
||||
// fontFamily = glyph.Win32FamilyNames[new CultureInfo(culture2)];
|
||||
// if (Utils.IsNullOrEmpty(fontFamily))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
// lstFonts.Add(fontFamily);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Logging.SaveLog("fill fonts error", ex);
|
||||
// }
|
||||
// return lstFonts;
|
||||
//}
|
||||
|
||||
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
214
v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml
Normal file
|
@ -0,0 +1,214 @@
|
|||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.ProfilesView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:conv="using:v2rayN.Desktop.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:ProfilesViewModel"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<conv:DelayColorConverter x:Key="DelayColorConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<DockPanel>
|
||||
<WrapPanel Margin="2" DockPanel.Dock="Top">
|
||||
<ListBox
|
||||
x:Name="lstGroup"
|
||||
MaxHeight="200"
|
||||
DisplayMemberBinding="{Binding remarks}"
|
||||
ItemsSource="{Binding SubItems}"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
|
||||
<Button
|
||||
x:Name="btnEditSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubEdit}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
Source="/Assets/edit.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="btnAddSub"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="4,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubAdd}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
Source="/Assets/add.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="btnAutofitColumnWidth"
|
||||
Width="30"
|
||||
Height="30"
|
||||
Margin="20,0"
|
||||
Classes="Success"
|
||||
Theme="{DynamicResource SolidButton}"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
Source="/Assets/fit.png" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<TextBox
|
||||
x:Name="txtServerFilter"
|
||||
Width="200"
|
||||
Margin="4,0"
|
||||
VerticalContentAlignment="Center"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.MsgServerTitle}" />
|
||||
</WrapPanel>
|
||||
<DataGrid
|
||||
x:Name="lstProfiles"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserSortColumns="False"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding ProfileItems}">
|
||||
<DataGrid.KeyBindings>
|
||||
<KeyBinding Command="{Binding Export2ShareUrlCmd}" Gesture="Ctrl+C" />
|
||||
<KeyBinding Command="{Binding SetDefaultServerCmd}" Gesture="Enter" />
|
||||
</DataGrid.KeyBindings>
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuEditServer" Header="{x:Static resx:ResUI.menuEditServer}" />
|
||||
<MenuItem x:Name="menuSetDefaultServer" Header="{x:Static resx:ResUI.menuSetDefaultServer}" />
|
||||
<MenuItem x:Name="menuRemoveServer" Header="{x:Static resx:ResUI.menuRemoveServer}" />
|
||||
<MenuItem x:Name="menuRemoveDuplicateServer" Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
|
||||
<MenuItem x:Name="menuCopyServer" Header="{x:Static resx:ResUI.menuCopyServer}" />
|
||||
<MenuItem x:Name="menuShareServer" Header="{x:Static resx:ResUI.menuShareServer}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuSetDefaultMultipleServer" Header="{x:Static resx:ResUI.menuSetDefaultMultipleServer}" />
|
||||
|
||||
<MenuItem x:Name="menuSetDefaultLoadBalanceServer" Header="{x:Static resx:ResUI.menuSetDefaultLoadBalanceServer}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuMixedTestServer" Header="{x:Static resx:ResUI.menuMixedTestServer}" />
|
||||
<MenuItem x:Name="menuTcpingServer" Header="{x:Static resx:ResUI.menuTcpingServer}" />
|
||||
<MenuItem x:Name="menuRealPingServer" Header="{x:Static resx:ResUI.menuRealPingServer}" />
|
||||
<MenuItem x:Name="menuSpeedServer" Header="{x:Static resx:ResUI.menuSpeedServer}" />
|
||||
<MenuItem x:Name="menuSortServerResult" Header="{x:Static resx:ResUI.menuSortServerResult}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuMoveToGroup" Header="{x:Static resx:ResUI.menuMoveToGroup}">
|
||||
<MenuItem>
|
||||
<MenuItem.Header>
|
||||
<DockPanel>
|
||||
<ComboBox
|
||||
x:Name="cmbMoveToGroup"
|
||||
Width="200"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.menuSubscription}" />
|
||||
</DockPanel>
|
||||
</MenuItem.Header>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
|
||||
<MenuItem x:Name="menuMoveTop" Header="{x:Static resx:ResUI.menuMoveTop}" />
|
||||
<MenuItem x:Name="menuMoveUp" Header="{x:Static resx:ResUI.menuMoveUp}" />
|
||||
<MenuItem x:Name="menuMoveDown" Header="{x:Static resx:ResUI.menuMoveDown}" />
|
||||
<MenuItem x:Name="menuMoveBottom" Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
||||
</MenuItem>
|
||||
<MenuItem x:Name="menuSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuExport2ClientConfig}">
|
||||
<MenuItem x:Name="menuExport2ClientConfig" Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
|
||||
<MenuItem x:Name="menuExport2ClientConfigClipboard" Header="{x:Static resx:ResUI.menuExport2ClientConfigClipboard}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{x:Static resx:ResUI.menuExport2ShareUrl}">
|
||||
<MenuItem x:Name="menuExport2ShareUrl" Header="{x:Static resx:ResUI.menuExport2ShareUrl}" />
|
||||
<MenuItem x:Name="menuExport2ShareUrlBase64" Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
|
||||
</MenuItem>
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Width="40" Binding="{Binding isActive}" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding configType}"
|
||||
Header="{x:Static resx:ResUI.LvServiceType}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Binding="{Binding remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Binding="{Binding address}"
|
||||
Header="{x:Static resx:ResUI.LvAddress}" />
|
||||
<DataGridTextColumn
|
||||
Width="60"
|
||||
Binding="{Binding port}"
|
||||
Header="{x:Static resx:ResUI.LvPort}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding network}"
|
||||
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding streamSecurity}"
|
||||
Header="{x:Static resx:ResUI.LvTLS}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding subRemarks}"
|
||||
Header="{x:Static resx:ResUI.LvSubscription}" />
|
||||
<DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{x:Static resx:ResUI.LvTestDelay}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
Margin="8,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{Binding delay, Converter={StaticResource DelayColorConverter}}"
|
||||
Text="{Binding Path=delayVal, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding speedVal}"
|
||||
Header="{x:Static resx:ResUI.LvTestSpeed}" />
|
||||
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding todayUp}"
|
||||
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding todayDown}"
|
||||
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding totalUp}"
|
||||
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding totalDown}"
|
||||
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
468
v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs
Normal file
|
@ -0,0 +1,468 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
{
|
||||
private static Config _config;
|
||||
private Window _window;
|
||||
|
||||
public ProfilesView(Window window)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_config = LazyConfig.Instance.Config;
|
||||
_window = window;
|
||||
|
||||
menuSelectAll.Click += menuSelectAll_Click;
|
||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||
txtServerFilter.KeyDown += TxtServerFilter_KeyDown;
|
||||
lstProfiles.KeyDown += LstProfiles_KeyDown;
|
||||
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
|
||||
lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
|
||||
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
|
||||
//if (_config.uiItem.enableDragDropSort)
|
||||
//{
|
||||
// lstProfiles.AllowDrop = true;
|
||||
// lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown;
|
||||
// lstProfiles.MouseMove += LstProfiles_MouseMove;
|
||||
// lstProfiles.DragEnter += LstProfiles_DragEnter;
|
||||
// lstProfiles.Drop += LstProfiles_Drop;
|
||||
//}
|
||||
|
||||
ViewModel = new ProfilesViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ProfilesViewModel));
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
// this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstGroup.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.AddSubCmd, v => v.btnAddSub).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.EditSubCmd, v => v.btnEditSub).DisposeWith(disposables);
|
||||
|
||||
//servers delete
|
||||
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.menuEditServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveServerCmd, v => v.menuRemoveServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveDuplicateServerCmd, v => v.menuRemoveDuplicateServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CopyServerCmd, v => v.menuCopyServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultServerCmd, v => v.menuSetDefaultServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ShareServerCmd, v => v.menuShareServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerCmd, v => v.menuSetDefaultMultipleServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultLoadBalanceServerCmd, v => v.menuSetDefaultLoadBalanceServer).DisposeWith(disposables);
|
||||
|
||||
//servers move
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||
|
||||
//servers ping
|
||||
this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).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);
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ShareUrlBase64Cmd, v => v.menuExport2ShareUrlBase64).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
//RestoreUI();
|
||||
ViewModel?.RefreshServers();
|
||||
}
|
||||
|
||||
//#region Event
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.SetClipboardData:
|
||||
if (obj is null) return false;
|
||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||
break;
|
||||
|
||||
case EViewAction.AdjustMainLvColWidth:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
AutofitColumnWidth(),
|
||||
DispatcherPriority.Default);
|
||||
|
||||
break;
|
||||
|
||||
case EViewAction.ProfilesFocus:
|
||||
lstProfiles.Focus();
|
||||
break;
|
||||
|
||||
case EViewAction.ShowYesNo:
|
||||
if (await UI.ShowYesNo(_window, ResUI.RemoveServer) == ButtonResult.No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.SaveFileDialog:
|
||||
if (obj is null) return false;
|
||||
var fileName = await UI.SaveFileDialog(_window, "");
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ViewModel?.Export2ClientConfigResult(fileName, (ProfileItem)obj);
|
||||
break;
|
||||
|
||||
case EViewAction.AddServerWindow:
|
||||
if (obj is null) return false;
|
||||
return await new AddServerWindow((ProfileItem)obj).ShowDialog<bool>(_window);
|
||||
|
||||
case EViewAction.AddServer2Window:
|
||||
if (obj is null) return false;
|
||||
return await new AddServer2Window((ProfileItem)obj).ShowDialog<bool>(_window);
|
||||
|
||||
case EViewAction.ShareServer:
|
||||
if (obj is null) return false;
|
||||
await ShareServer((string)obj);
|
||||
break;
|
||||
|
||||
case EViewAction.SubEditWindow:
|
||||
if (obj is null) return false;
|
||||
return await new SubEditWindow((SubItem)obj).ShowDialog<bool>(_window);
|
||||
|
||||
case EViewAction.DispatcherSpeedTest:
|
||||
if (obj is null) return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.SetSpeedTestResult((SpeedTestResult)obj),
|
||||
DispatcherPriority.Default);
|
||||
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshServersBiz(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
public async Task ShareServer(string url)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var dialog = new QrcodeView(url);
|
||||
await dialog.ShowDialog(_window);
|
||||
}
|
||||
|
||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
List<ProfileItemModel> lst = [];
|
||||
foreach (var item in lstProfiles.SelectedItems)
|
||||
{
|
||||
lst.Add((ProfileItemModel)item);
|
||||
}
|
||||
ViewModel.SelectedProfiles = lst;
|
||||
}
|
||||
|
||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
if (_config.uiItem.doubleClick2Activate)
|
||||
{
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||
{
|
||||
e.Row.Header = $" {e.Row.GetIndex() + 1}";
|
||||
}
|
||||
|
||||
//private void LstProfiles_ColumnHeader_Click(object? sender, RoutedEventArgs e)
|
||||
//{
|
||||
// var colHeader = sender as DataGridColumnHeader;
|
||||
// if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var colName = ((MyDGTextColumn)colHeader.Column).ExName;
|
||||
// ViewModel?.SortServer(colName);
|
||||
//}
|
||||
|
||||
private void menuSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
lstProfiles.SelectAll();
|
||||
}
|
||||
|
||||
private void LstProfiles_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.A:
|
||||
menuSelectAll_Click(null, null);
|
||||
break;
|
||||
|
||||
case Key.C:
|
||||
ViewModel?.Export2ShareUrlAsync(false);
|
||||
break;
|
||||
|
||||
case Key.D:
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
break;
|
||||
|
||||
case Key.F:
|
||||
ViewModel?.ShareServerAsync();
|
||||
break;
|
||||
|
||||
case Key.O:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping);
|
||||
break;
|
||||
|
||||
case Key.R:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Realping);
|
||||
break;
|
||||
|
||||
case Key.T:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest);
|
||||
break;
|
||||
|
||||
case Key.E:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Key is Key.Enter or Key.Return)
|
||||
{
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
ViewModel?.RemoveServerAsync();
|
||||
}
|
||||
else if (e.Key == Key.T)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Top);
|
||||
}
|
||||
else if (e.Key == Key.U)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Up);
|
||||
}
|
||||
else if (e.Key == Key.D)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Down);
|
||||
}
|
||||
else if (e.Key == Key.B)
|
||||
{
|
||||
ViewModel?.MoveServer(EMove.Bottom);
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
ViewModel?.ServerSpeedtestStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
}
|
||||
|
||||
private void AutofitColumnWidth()
|
||||
{
|
||||
foreach (var it in lstProfiles.Columns)
|
||||
{
|
||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtServerFilter_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key is Key.Enter or Key.Return)
|
||||
{
|
||||
ViewModel?.RefreshServers();
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion Event
|
||||
|
||||
//#region UI
|
||||
|
||||
//private void RestoreUI()
|
||||
//{
|
||||
// var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList();
|
||||
// var displayIndex = 0;
|
||||
// foreach (var item in lvColumnItem)
|
||||
// {
|
||||
// foreach (MyDGTextColumn item2 in lstProfiles.Columns)
|
||||
// {
|
||||
// if (item2.ExName == item.Name)
|
||||
// {
|
||||
// if (item.Width < 0)
|
||||
// {
|
||||
// item2.IsVisible = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// item2.Width = item.Width;
|
||||
// item2.DisplayIndex = displayIndex++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!_config.guiItem.enableStatistics)
|
||||
// {
|
||||
// colTodayUp.IsVisible =
|
||||
// colTodayDown.IsVisible =
|
||||
// colTotalUp.IsVisible =
|
||||
// colTotalDown.IsVisible = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// colTodayUp.IsVisible =
|
||||
// colTodayDown.IsVisible =
|
||||
// colTotalUp.IsVisible =
|
||||
// colTotalDown.IsVisible = true;
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void StorageUI()
|
||||
//{
|
||||
// List<ColumnItem> lvColumnItem = new();
|
||||
// for (int k = 0; k < lstProfiles.Columns.Count; k++)
|
||||
// {
|
||||
// var item2 = (MyDGTextColumn)lstProfiles.Columns[k];
|
||||
// lvColumnItem.Add(new()
|
||||
// {
|
||||
// Name = item2.ExName,
|
||||
// Width = item2.IsVisible == true ? Utils.ToInt(item2.ActualWidth) : -1,
|
||||
// Index = item2.DisplayIndex
|
||||
// });
|
||||
// }
|
||||
// _config.uiItem.mainColumnItem = lvColumnItem;
|
||||
// ConfigHandler.SaveConfig(_config);
|
||||
//}
|
||||
|
||||
//#endregion UI
|
||||
|
||||
//#region Drag and Drop
|
||||
|
||||
//private Point startPoint = new();
|
||||
//private int startIndex = -1;
|
||||
//private string formatData = "ProfileItemModel";
|
||||
|
||||
///// <summary>
|
||||
///// Helper to search up the VisualTree
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="current"></param>
|
||||
///// <returns></returns>
|
||||
//private static T? FindAncestor<T>(DependencyObject current) where T : DependencyObject
|
||||
//{
|
||||
// do
|
||||
// {
|
||||
// if (current is T)
|
||||
// {
|
||||
// return (T)current;
|
||||
// }
|
||||
// current = VisualTreeHelper.GetParent(current);
|
||||
// }
|
||||
// while (current != null);
|
||||
// return null;
|
||||
//}
|
||||
|
||||
//private void LstProfiles_PreviewMouseLeftButtonDown(object? sender, MouseButtonEventArgs e)
|
||||
//{
|
||||
// // Get current mouse position
|
||||
// startPoint = e.GetPosition(null);
|
||||
//}
|
||||
|
||||
//private void LstProfiles_MouseMove(object? sender, MouseEventArgs e)
|
||||
//{
|
||||
// // Get the current mouse position
|
||||
// Point mousePos = e.GetPosition(null);
|
||||
// Vector diff = startPoint - mousePos;
|
||||
|
||||
// if (e.LeftButton == MouseButtonState.Pressed &&
|
||||
// (Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
|
||||
// Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
|
||||
// {
|
||||
// // Get the dragged Item
|
||||
// if (sender is not DataGrid listView) return;
|
||||
// var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||
// if (listViewItem == null) return; // Abort
|
||||
// // Find the data behind the ListViewItem
|
||||
// ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||
// if (item == null) return; // Abort
|
||||
// // Initialize the drag & drop operation
|
||||
// startIndex = lstProfiles.SelectedIndex;
|
||||
// DataObject dragData = new(formatData, item);
|
||||
// DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void LstProfiles_DragEnter(object? sender, DragEventArgs e)
|
||||
//{
|
||||
// if (!e.Data.GetDataPresent(formatData) || sender != e.Source)
|
||||
// {
|
||||
// e.Effects = DragDropEffects.None;
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void LstProfiles_Drop(object? sender, DragEventArgs e)
|
||||
//{
|
||||
// if (e.Data.GetDataPresent(formatData) && sender == e.Source)
|
||||
// {
|
||||
// // Get the drop Item destination
|
||||
// if (sender is not DataGrid listView) return;
|
||||
// var listViewItem = FindAncestor<DataGridRow>((DependencyObject)e.OriginalSource);
|
||||
// if (listViewItem == null)
|
||||
// {
|
||||
// // Abort
|
||||
// e.Effects = DragDropEffects.None;
|
||||
// return;
|
||||
// }
|
||||
// // Find the data behind the Item
|
||||
// ProfileItemModel item = (ProfileItemModel)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
|
||||
// if (item == null) return;
|
||||
// // Move item into observable collection
|
||||
// // (this will be automatically reflected to lstView.ItemsSource)
|
||||
// e.Effects = DragDropEffects.Move;
|
||||
|
||||
// ViewModel?.MoveServerTo(startIndex, item);
|
||||
|
||||
// startIndex = -1;
|
||||
// }
|
||||
//}
|
||||
|
||||
//#endregion Drag and Drop
|
||||
}
|
||||
}
|
48
v2rayN/v2rayN.Desktop/Views/QrcodeView.axaml
Normal file
|
@ -0,0 +1,48 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.QrcodeView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
Title=""
|
||||
Width="400"
|
||||
Height="480"
|
||||
d:DesignHeight="480"
|
||||
d:DesignWidth="400"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d">
|
||||
<Grid Margin="30">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="60" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Image
|
||||
Name="imgQrcode"
|
||||
Width="300"
|
||||
Height="300"
|
||||
Source="/Assets/close.png" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtContent"
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Margin="0,8"
|
||||
VerticalAlignment="Center"
|
||||
IsReadOnly="True"
|
||||
MaxLines="1" />
|
||||
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Grid.Row="2"
|
||||
Width="100"
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}" />
|
||||
</Grid>
|
||||
</Window>
|
26
v2rayN/v2rayN.Desktop/Views/QrcodeView.axaml.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Media.Imaging;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class QrcodeView : Window
|
||||
{
|
||||
public QrcodeView(string? url)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
txtContent.Text = url;
|
||||
imgQrcode.Source = GetQRCode(url);
|
||||
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
}
|
||||
|
||||
private Bitmap? GetQRCode(string? url)
|
||||
{
|
||||
var qrCodeImage = QRCodeHelper.GenQRCode(url);
|
||||
if (qrCodeImage is null) return null;
|
||||
var ms = new MemoryStream(qrCodeImage);
|
||||
return new Bitmap(ms);
|
||||
}
|
||||
}
|
||||
}
|
197
v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml
Normal file
|
@ -0,0 +1,197 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuRoutingRuleDetailsSetting}"
|
||||
Width="900"
|
||||
Height="700"
|
||||
x:DataType="vms:RoutingRuleDetailsViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<Grid Classes="Margin8" DockPanel.Dock="Top">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="outboundTag" />
|
||||
<ComboBox
|
||||
x:Name="cmbOutboundTag"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4"
|
||||
MaxDropDownHeight="1000" />
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="port" />
|
||||
<TextBox
|
||||
x:Name="txtPort"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4">
|
||||
<Button Click="linkRuleobjectDoc_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="protocol" />
|
||||
<ListBox
|
||||
x:Name="clbProtocol"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="inboundTag" />
|
||||
<ListBox
|
||||
x:Name="clbInboundTag"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4"
|
||||
SelectionMode="Multiple"
|
||||
Theme="{DynamicResource PureCardRadioGroupListBox}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="network" />
|
||||
<ComboBox
|
||||
x:Name="cmbNetwork"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Classes="Margin4"
|
||||
MaxDropDownHeight="1000" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="enabled" />
|
||||
<ToggleSwitch
|
||||
x:Name="togEnabled"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||
</Grid>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<StackPanel
|
||||
Width="600"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<CheckBox x:Name="chkAutoSort">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbAutoSort}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Classes="Margin8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<HeaderedContentControl Grid.Column="0" Header="{x:Static resx:ResUI.TbRoutingRuleDomain}">
|
||||
<TextBox
|
||||
Name="txtDomain"
|
||||
Classes="TextArea"
|
||||
MinLines="10"
|
||||
TextWrapping="Wrap" />
|
||||
</HeaderedContentControl>
|
||||
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
|
||||
<HeaderedContentControl Grid.Column="2" Header="{x:Static resx:ResUI.TbRoutingRuleIP}">
|
||||
<TextBox
|
||||
Name="txtIP"
|
||||
Classes="TextArea"
|
||||
MinLines="10"
|
||||
TextWrapping="Wrap" />
|
||||
</HeaderedContentControl>
|
||||
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" />
|
||||
<HeaderedContentControl Grid.Column="4" Header="{x:Static resx:ResUI.TbRoutingRuleProcess}">
|
||||
<TextBox
|
||||
Name="txtProcess"
|
||||
Classes="TextArea"
|
||||
MinLines="10"
|
||||
TextWrapping="Wrap" />
|
||||
</HeaderedContentControl>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
100
v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml.cs
Normal file
|
@ -0,0 +1,100 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
||||
{
|
||||
public RoutingRuleDetailsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public RoutingRuleDetailsWindow(RulesItem rulesItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
clbProtocol.SelectionChanged += ClbProtocol_SelectionChanged;
|
||||
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
|
||||
|
||||
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
|
||||
cmbOutboundTag.Items.Add(Global.ProxyTag);
|
||||
cmbOutboundTag.Items.Add(Global.DirectTag);
|
||||
cmbOutboundTag.Items.Add(Global.BlockTag);
|
||||
Global.RuleProtocols.ForEach(it =>
|
||||
{
|
||||
clbProtocol.Items.Add(it);
|
||||
});
|
||||
Global.InboundTags.ForEach(it =>
|
||||
{
|
||||
clbInboundTag.Items.Add(it);
|
||||
});
|
||||
Global.RuleNetworks.ForEach(it =>
|
||||
{
|
||||
cmbNetwork.Items.Add(it);
|
||||
});
|
||||
|
||||
if (!rulesItem.id.IsNullOrEmpty())
|
||||
{
|
||||
rulesItem.protocol?.ForEach(it =>
|
||||
{
|
||||
clbProtocol.SelectedItems.Add(it);
|
||||
});
|
||||
rulesItem.inboundTag?.ForEach(it =>
|
||||
{
|
||||
clbInboundTag.SelectedItems.Add(it);
|
||||
});
|
||||
}
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.outboundTag, v => v.cmbOutboundTag.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.port, v => v.txtPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Domain, v => v.txtDomain.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.IP, v => v.txtIP.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.Process, v => v.txtProcess.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoSort, v => v.chkAutoSort.IsChecked).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
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 Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
cmbOutboundTag.Focus();
|
||||
}
|
||||
|
||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
|
||||
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
|
||||
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://xtls.github.io/config/routing.html#ruleobject");
|
||||
}
|
||||
}
|
||||
}
|
245
v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml
Normal file
|
@ -0,0 +1,245 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingRuleSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuRoutingRuleSetting}"
|
||||
Width="960"
|
||||
Height="700"
|
||||
x:DataType="vms:RoutingRuleSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel>
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
<Menu>
|
||||
<MenuItem x:Name="menuRuleAdd" Header="{x:Static resx:ResUI.menuRuleAdd}" />
|
||||
<MenuItem x:Name="menuImportRulesFromFile" Header="{x:Static resx:ResUI.menuImportRulesFromFile}" />
|
||||
<MenuItem x:Name="menuImportRulesFromClipboard" Header="{x:Static resx:ResUI.menuImportRulesFromClipboard}" />
|
||||
<MenuItem x:Name="menuImportRulesFromUrl" Header="{x:Static resx:ResUI.menuImportRulesFromUrl}" />
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Classes="Margin8" DockPanel.Dock="Top">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Width="300"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Singbox"
|
||||
Width="200"
|
||||
Classes="Margin4" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtUrl"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||
<TextBox
|
||||
x:Name="txtCustomIcon"
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowseCustomIcon"
|
||||
Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4">
|
||||
<Button Click="linkCustomRulesetPath4Singbox">
|
||||
<TextBlock Text="{x:Static resx:ResUI.LvCustomRulesetPath4Singbox}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
<TextBox
|
||||
x:Name="txtCustomRulesetPath4Singbox"
|
||||
Grid.Row="4"
|
||||
Grid.Column="1"
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap" />
|
||||
<Button
|
||||
x:Name="btnBrowseCustomRulesetPath4Singbox"
|
||||
Grid.Row="4"
|
||||
Grid.Column="2"
|
||||
Classes="Margin4"
|
||||
Content="{x:Static resx:ResUI.TbBrowse}" />
|
||||
</Grid>
|
||||
|
||||
<TabControl x:Name="tabAdvanced">
|
||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.menuRuleList}">
|
||||
<DataGrid
|
||||
x:Name="lstRules"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding RulesItems}">
|
||||
<DataGrid.KeyBindings>
|
||||
<KeyBinding Command="{Binding RuleExportSelectedCmd}" Gesture="Ctrl+C" />
|
||||
</DataGrid.KeyBindings>
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuRuleAdd2" Header="{x:Static resx:ResUI.menuRuleAdd}" />
|
||||
<MenuItem x:Name="menuRuleRemove" Header="{x:Static resx:ResUI.menuRuleRemove}" />
|
||||
<MenuItem x:Name="menuRuleSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||
<MenuItem x:Name="menuRuleExportSelected" Header="{x:Static resx:ResUI.menuRuleExportSelected}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuMoveTop" Header="{x:Static resx:ResUI.menuMoveTop}" />
|
||||
<MenuItem x:Name="menuMoveUp" Header="{x:Static resx:ResUI.menuMoveUp}" />
|
||||
<MenuItem x:Name="menuMoveDown" Header="{x:Static resx:ResUI.menuMoveDown}" />
|
||||
<MenuItem x:Name="menuMoveBottom" Header="{x:Static resx:ResUI.menuMoveBottom}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="110"
|
||||
Binding="{Binding outboundTag}"
|
||||
Header="outboundTag" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding port}"
|
||||
Header="port" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding protocols}"
|
||||
Header="protocol" />
|
||||
<DataGridTextColumn
|
||||
Width="110"
|
||||
Binding="{Binding inboundTags}"
|
||||
Header="inboundTag" />
|
||||
<DataGridTextColumn
|
||||
Width="90"
|
||||
Binding="{Binding network}"
|
||||
Header="network" />
|
||||
<DataGridTextColumn
|
||||
Width="190"
|
||||
Binding="{Binding domains}"
|
||||
Header="domain" />
|
||||
<DataGridTextColumn
|
||||
Width="190"
|
||||
Binding="{Binding ips}"
|
||||
Header="ip" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding enabled}"
|
||||
Header="enabled" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Window>
|
214
v2rayN/v2rayN.Desktop/Views/RoutingRuleSettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,214 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.ReactiveUI;
|
||||
using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
||||
{
|
||||
public RoutingRuleSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public RoutingRuleSettingWindow(RoutingItem routingItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
this.KeyDown += RoutingRuleSettingWindow_KeyDown;
|
||||
lstRules.SelectionChanged += lstRules_SelectionChanged;
|
||||
lstRules.DoubleTapped += LstRules_DoubleTapped;
|
||||
menuRuleSelectAll.Click += menuRuleSelectAll_Click;
|
||||
btnBrowseCustomIcon.Click += btnBrowseCustomIcon_Click;
|
||||
btnBrowseCustomRulesetPath4Singbox.Click += btnBrowseCustomRulesetPath4Singbox_ClickAsync;
|
||||
|
||||
ViewModel = new RoutingRuleSettingViewModel(routingItem, UpdateViewHandler);
|
||||
Global.DomainStrategies.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy.Items.Add(it);
|
||||
});
|
||||
cmbdomainStrategy.Items.Add(string.Empty);
|
||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
||||
});
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.RulesItems, v => v.lstRules.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRules.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.domainStrategy, v => v.cmbdomainStrategy.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.domainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.url, v => v.txtUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.customIcon, v => v.txtCustomIcon.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.customRulesetPath4Singbox, v => v.txtCustomRulesetPath4Singbox.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting.sort, v => v.txtSort.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RuleAddCmd, v => v.menuRuleAdd).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportRulesFromFileCmd, v => v.menuImportRulesFromFile).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportRulesFromClipboardCmd, v => v.menuImportRulesFromClipboard).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ImportRulesFromUrlCmd, v => v.menuImportRulesFromUrl).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RuleAddCmd, v => v.menuRuleAdd2).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RuleRemoveCmd, v => v.menuRuleRemove).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RuleExportSelectedCmd, v => v.menuRuleExportSelected).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
|
||||
case EViewAction.ShowYesNo:
|
||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.AddBatchRoutingRulesYesNo:
|
||||
if (await UI.ShowYesNo(this, ResUI.AddBatchRoutingRulesYesNo) == ButtonResult.No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.RoutingRuleDetailsWindow:
|
||||
if (obj is null) return false;
|
||||
return await new RoutingRuleDetailsWindow((RulesItem)obj).ShowDialog<bool>(this);
|
||||
|
||||
case EViewAction.ImportRulesFromFile:
|
||||
var fileName = await UI.OpenFileDialog(this, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ViewModel?.ImportRulesFromFileAsync(fileName);
|
||||
break;
|
||||
|
||||
case EViewAction.SetClipboardData:
|
||||
if (obj is null) return false;
|
||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||
break;
|
||||
|
||||
case EViewAction.ImportRulesFromClipboard:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
|
||||
private void RoutingRuleSettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
{
|
||||
if (e.Key == Key.A)
|
||||
{
|
||||
lstRules.SelectAll();
|
||||
}
|
||||
else if (e.Key == Key.C)
|
||||
{
|
||||
ViewModel?.RuleExportSelectedAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Key == Key.T)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Top);
|
||||
}
|
||||
else if (e.Key == Key.U)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Up);
|
||||
}
|
||||
else if (e.Key == Key.D)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Down);
|
||||
}
|
||||
else if (e.Key == Key.B)
|
||||
{
|
||||
ViewModel?.MoveRule(EMove.Bottom);
|
||||
}
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
ViewModel?.RuleRemoveAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
List<RulesItemModel> lst = [];
|
||||
foreach (var item in lstRules.SelectedItems)
|
||||
{
|
||||
lst.Add((RulesItemModel)item);
|
||||
}
|
||||
ViewModel.SelectedSources = lst;
|
||||
}
|
||||
|
||||
private void LstRules_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.RuleEditAsync(false);
|
||||
}
|
||||
|
||||
private void menuRuleSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
lstRules.SelectAll();
|
||||
}
|
||||
|
||||
private async void btnBrowseCustomIcon_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(this, FilePickerFileTypes.ImagePng);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
txtCustomIcon.Text = fileName;
|
||||
}
|
||||
|
||||
private async void btnBrowseCustomRulesetPath4Singbox_ClickAsync(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(this, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
txtCustomRulesetPath4Singbox.Text = fileName;
|
||||
}
|
||||
|
||||
private void linkCustomRulesetPath4Singbox(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://github.com/2dust/v2rayCustomRoutingList/blob/master/singbox_custom_ruleset_example.json");
|
||||
}
|
||||
}
|
||||
}
|
136
v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml
Normal file
|
@ -0,0 +1,136 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.RoutingSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuRoutingSetting}"
|
||||
Width="990"
|
||||
Height="700"
|
||||
x:DataType="vms:RoutingSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<DockPanel>
|
||||
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
<Menu>
|
||||
<MenuItem x:Name="menuRoutingAdvancedAdd2" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||
<MenuItem x:Name="menuRoutingAdvancedImportRules2" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||
</Menu>
|
||||
|
||||
<TextBlock Margin="8,0,0,0" VerticalAlignment="Center">
|
||||
<Button Click="linkdomainStrategy_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy"
|
||||
Width="110"
|
||||
Margin="8,0,0,0" />
|
||||
<Separator />
|
||||
<TextBlock
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Static resx:ResUI.TbdomainMatcher}" />
|
||||
<ComboBox
|
||||
x:Name="cmbdomainMatcher"
|
||||
Width="60"
|
||||
Margin="8,0,0,0" />
|
||||
<Separator />
|
||||
<TextBlock Margin="8,0,0,0" VerticalAlignment="Center">
|
||||
<Button Click="linkdomainStrategy4Singbox_Click">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbdomainStrategy4Singbox}" />
|
||||
</Button>
|
||||
</TextBlock>
|
||||
<ComboBox
|
||||
x:Name="cmbdomainStrategy4Singbox"
|
||||
Width="100"
|
||||
Margin="8,0,0,0" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<StackPanel
|
||||
Width="600"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center">
|
||||
<TextBlock Text="{x:Static resx:ResUI.TbRoutingTips}" />
|
||||
</StackPanel>
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
|
||||
<DockPanel>
|
||||
<TabControl x:Name="tabAdvanced">
|
||||
<TabItem HorizontalAlignment="Left" Header="{x:Static resx:ResUI.TbRoutingTabRuleList}">
|
||||
<DataGrid
|
||||
x:Name="lstRoutings"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding RoutingItems}">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem x:Name="menuRoutingAdvancedAdd" Header="{x:Static resx:ResUI.menuRoutingAdvancedAdd}" />
|
||||
<MenuItem x:Name="menuRoutingAdvancedRemove" Header="{x:Static resx:ResUI.menuRoutingAdvancedRemove}" />
|
||||
<MenuItem x:Name="menuRoutingAdvancedSelectAll" Header="{x:Static resx:ResUI.menuSelectAll}" />
|
||||
<MenuItem x:Name="menuRoutingAdvancedSetDefault" Header="{x:Static resx:ResUI.menuRoutingAdvancedSetDefault}" />
|
||||
<Separator />
|
||||
<MenuItem x:Name="menuRoutingAdvancedImportRules" Header="{x:Static resx:ResUI.menuRoutingAdvancedImportRules}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
|
||||
<DataGrid.Columns>
|
||||
<DataGridCheckBoxColumn Width="40" Binding="{Binding isActive}" />
|
||||
<DataGridTextColumn
|
||||
Width="250"
|
||||
Binding="{Binding remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="60"
|
||||
Binding="{Binding ruleNum}"
|
||||
Header="{x:Static resx:ResUI.LvCount}" />
|
||||
<DataGridTextColumn
|
||||
Width="60"
|
||||
Binding="{Binding sort}"
|
||||
Header="{x:Static resx:ResUI.LvSort}" />
|
||||
<DataGridTextColumn
|
||||
Width="300"
|
||||
Binding="{Binding url}"
|
||||
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||
<DataGridTextColumn
|
||||
Width="300"
|
||||
Binding="{Binding customIcon}"
|
||||
Header="{x:Static resx:ResUI.LvCustomIcon}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
|
||||
</DockPanel>
|
||||
|
||||
</DockPanel>
|
||||
</Window>
|
155
v2rayN/v2rayN.Desktop/Views/RoutingSettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,155 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
||||
{
|
||||
private bool _manualClose = false;
|
||||
|
||||
public RoutingSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Closing += RoutingSettingWindow_Closing;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
this.KeyDown += RoutingSettingWindow_KeyDown;
|
||||
lstRoutings.SelectionChanged += lstRoutings_SelectionChanged;
|
||||
lstRoutings.DoubleTapped += LstRoutings_DoubleTapped;
|
||||
menuRoutingAdvancedSelectAll.Click += menuRoutingAdvancedSelectAll_Click;
|
||||
|
||||
ViewModel = new RoutingSettingViewModel(UpdateViewHandler);
|
||||
|
||||
Global.DomainStrategies.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy.Items.Add(it);
|
||||
});
|
||||
Global.DomainMatchers.ForEach(it =>
|
||||
{
|
||||
cmbdomainMatcher.Items.Add(it);
|
||||
});
|
||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
||||
{
|
||||
cmbdomainStrategy4Singbox.Items.Add(it);
|
||||
});
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.lstRoutings.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstRoutings.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.domainStrategy, v => v.cmbdomainStrategy.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.domainMatcher, v => v.cmbdomainMatcher.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.domainStrategy4Singbox, v => v.cmbdomainStrategy4Singbox.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedAddCmd, v => v.menuRoutingAdvancedAdd2).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedRemoveCmd, v => v.menuRoutingAdvancedRemove).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedSetDefaultCmd, v => v.menuRoutingAdvancedSetDefault).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedImportRulesCmd, v => v.menuRoutingAdvancedImportRules).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RoutingAdvancedImportRulesCmd, v => v.menuRoutingAdvancedImportRules2).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
|
||||
case EViewAction.ShowYesNo:
|
||||
if (await UI.ShowYesNo(this, ResUI.RemoveRules) == ButtonResult.No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.RoutingRuleSettingWindow:
|
||||
if (obj is null) return false;
|
||||
return await new RoutingRuleSettingWindow((RoutingItem)obj).ShowDialog<bool>(this);
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void RoutingSettingWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (ViewModel?.enableRoutingBasic ?? false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.KeyModifiers == KeyModifiers.Control)
|
||||
{
|
||||
if (e.Key == Key.A)
|
||||
{
|
||||
lstRoutings.SelectAll();
|
||||
}
|
||||
}
|
||||
else if (e.Key is Key.Enter or Key.Return)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedSetDefault();
|
||||
}
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedRemoveAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void menuRoutingAdvancedSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
lstRoutings.SelectAll();
|
||||
}
|
||||
|
||||
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
List<RoutingItemModel> lst = [];
|
||||
foreach (var item in lstRoutings.SelectedItems)
|
||||
{
|
||||
lst.Add((RoutingItemModel)item);
|
||||
}
|
||||
ViewModel.SelectedSources = lst;
|
||||
}
|
||||
|
||||
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedEditAsync(false);
|
||||
}
|
||||
|
||||
private void linkdomainStrategy_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://xtls.github.io/config/routing.html");
|
||||
}
|
||||
|
||||
private void linkdomainStrategy4Singbox_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Utils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/shared/listen/#domain_strategy");
|
||||
}
|
||||
|
||||
private void btnCancel_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_manualClose = true;
|
||||
this.Close(ViewModel?.IsModified);
|
||||
}
|
||||
|
||||
private void RoutingSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
||||
{
|
||||
if (ViewModel?.IsModified == true)
|
||||
{
|
||||
if (!_manualClose)
|
||||
{
|
||||
btnCancel_Click(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
234
v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml
Normal file
|
@ -0,0 +1,234 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.SubEditWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuSubSetting}"
|
||||
Width="700"
|
||||
Height="600"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="800"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Bottom"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnSave"
|
||||
Width="100"
|
||||
Content="{x:Static resx:ResUI.TbConfirm}"
|
||||
Cursor="Hand" />
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
Width="100"
|
||||
Margin="8,0"
|
||||
Content="{x:Static resx:ResUI.TbCancel}"
|
||||
Cursor="Hand" />
|
||||
</StackPanel>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="400" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.menuSubscription}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvRemarks}" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtRemarks"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtUrl"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="3"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvEnabled}" />
|
||||
|
||||
<DockPanel
|
||||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Classes="Margin4">
|
||||
<ToggleSwitch
|
||||
x:Name="togEnable"
|
||||
HorizontalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Left" />
|
||||
|
||||
<TextBox
|
||||
x:Name="txtAutoUpdateInterval"
|
||||
Width="200"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
DockPanel.Dock="Right"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
|
||||
</DockPanel>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvFilter}" />
|
||||
<TextBox
|
||||
x:Name="txtFilter"
|
||||
Grid.Row="5"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="6"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvConvertTarget}" />
|
||||
<ComboBox
|
||||
x:Name="cmbConvertTarget"
|
||||
Grid.Row="6"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
VerticalAlignment=" "
|
||||
Classes="Margin4"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.LvConvertTargetTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="7"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvUserAgent}" />
|
||||
<TextBox
|
||||
x:Name="txtUserAgent"
|
||||
Grid.Row="7"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="8"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvSort}" />
|
||||
<TextBox
|
||||
x:Name="txtSort"
|
||||
Grid.Row="8"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
HorizontalAlignment="Left"
|
||||
Classes="Margin4" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="9"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvPrevProfile}" />
|
||||
<TextBox
|
||||
x:Name="txtPrevProfile"
|
||||
Grid.Row="9"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.LvPrevProfileTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="10"
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvNextProfile}" />
|
||||
<TextBox
|
||||
x:Name="txtNextProfile"
|
||||
Grid.Row="10"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.LvPrevProfileTip}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="11"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin4"
|
||||
Text="{x:Static resx:ResUI.LvMoreUrl}" />
|
||||
<TextBox
|
||||
x:Name="txtMoreUrl"
|
||||
Grid.Row="12"
|
||||
Grid.Column="1"
|
||||
MinHeight="100"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Classes="TextArea Margin4"
|
||||
MinLines="4"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip.Tip="{x:Static resx:ResUI.SubUrlTips}" />
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
64
v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml.cs
Normal file
|
@ -0,0 +1,64 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||
{
|
||||
public SubEditWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public SubEditWindow(SubItem subItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
|
||||
ViewModel = new SubEditViewModel(subItem, UpdateViewHandler);
|
||||
|
||||
Global.SubConvertTargets.ForEach(it =>
|
||||
{
|
||||
cmbConvertTarget.Items.Add(it);
|
||||
});
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.url, v => v.txtUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.moreUrl, v => v.txtMoreUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.enabled, v => v.togEnable.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.autoUpdateInterval, v => v.txtAutoUpdateInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.userAgent, v => v.txtUserAgent.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.sort, v => v.txtSort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.filter, v => v.txtFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.convertTarget, v => v.cmbConvertTarget.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.prevProfile, v => v.txtPrevProfile.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.nextProfile, v => v.txtNextProfile.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
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 Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
}
|
||||
}
|
71
v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<Window
|
||||
x:Class="v2rayN.Desktop.Views.SubSettingWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
|
||||
Title="{x:Static resx:ResUI.menuSubSetting}"
|
||||
Width="800"
|
||||
Height="600"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:SubSettingViewModel"
|
||||
ShowInTaskbar="False"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<DockPanel Classes="Margin8">
|
||||
<StackPanel
|
||||
Classes="Margin8"
|
||||
DockPanel.Dock="Top"
|
||||
Orientation="Horizontal">
|
||||
<Menu>
|
||||
<MenuItem x:Name="menuSubAdd" Header="{x:Static resx:ResUI.menuSubAdd}" />
|
||||
<MenuItem x:Name="menuSubDelete" Header="{x:Static resx:ResUI.menuSubDelete}" />
|
||||
<MenuItem x:Name="menuSubEdit" Header="{x:Static resx:ResUI.menuSubEdit}" />
|
||||
<MenuItem x:Name="menuSubShare" Header="{x:Static resx:ResUI.menuSubShare}" />
|
||||
<MenuItem x:Name="menuClose" Header="{x:Static resx:ResUI.menuClose}" />
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid
|
||||
x:Name="lstSubscription"
|
||||
AutoGenerateColumns="False"
|
||||
BorderThickness="1"
|
||||
GridLinesVisibility="All"
|
||||
HeadersVisibility="Column"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding SubItems}">
|
||||
<DataGrid.KeyBindings>
|
||||
<KeyBinding Command="{Binding SubDeleteCmd}" Gesture="Delete" />
|
||||
</DataGrid.KeyBindings>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="120"
|
||||
Binding="{Binding remarks}"
|
||||
Header="{x:Static resx:ResUI.LvRemarks}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Binding="{Binding url}"
|
||||
Header="{x:Static resx:ResUI.LvUrl}" />
|
||||
<DataGridTextColumn
|
||||
Width="100"
|
||||
Binding="{Binding enabled}"
|
||||
Header="{x:Static resx:ResUI.LvEnabled}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Binding="{Binding autoUpdateInterval}"
|
||||
Header="{x:Static resx:ResUI.LvAutoUpdateInterval}" />
|
||||
<DataGridTextColumn
|
||||
Width="150"
|
||||
Binding="{Binding userAgent}"
|
||||
Header="{x:Static resx:ResUI.LvUserAgent}" />
|
||||
<DataGridTextColumn
|
||||
Width="80"
|
||||
Binding="{Binding sort}"
|
||||
Header="{x:Static resx:ResUI.LvSort}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</DockPanel>
|
||||
</Window>
|
109
v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using DynamicData;
|
||||
using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
||||
{
|
||||
private bool _manualClose = false;
|
||||
|
||||
public SubSettingWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
menuClose.Click += menuClose_Click;
|
||||
this.Closing += SubSettingWindow_Closing;
|
||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstSubscription.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstSubscription.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close();
|
||||
break;
|
||||
|
||||
case EViewAction.ShowYesNo:
|
||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.SubEditWindow:
|
||||
if (obj is null) return false;
|
||||
var window = new SubEditWindow((SubItem)obj);
|
||||
await window.ShowDialog(this);
|
||||
break;
|
||||
|
||||
case EViewAction.ShareSub:
|
||||
if (obj is null) return false;
|
||||
await ShareSub((string)obj);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task ShareSub(string url)
|
||||
{
|
||||
if (Utils.IsNullOrEmpty(url))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var dialog = new QrcodeView(url);
|
||||
await dialog.ShowDialog(this);
|
||||
}
|
||||
|
||||
private void LstSubscription_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.EditSubAsync(false);
|
||||
}
|
||||
|
||||
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
List<SubItem> lst = [];
|
||||
foreach (var item in lstSubscription.SelectedItems)
|
||||
{
|
||||
lst.Add((SubItem)item);
|
||||
}
|
||||
ViewModel.SelectedSources = lst;
|
||||
}
|
||||
|
||||
private void menuClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_manualClose = true;
|
||||
this.Close(ViewModel?.IsModified);
|
||||
}
|
||||
|
||||
private void SubSettingWindow_Closing(object? sender, WindowClosingEventArgs e)
|
||||
{
|
||||
if (ViewModel?.IsModified == true)
|
||||
{
|
||||
if (!_manualClose)
|
||||
{
|
||||
menuClose_Click(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
v2rayN/v2rayN.Desktop/Views/ThemeSettingView.axaml
Normal file
|
@ -0,0 +1,72 @@
|
|||
<UserControl
|
||||
x:Class="v2rayN.Desktop.Views.ThemeSettingView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
|
||||
xmlns:vms="clr-namespace:v2rayN.Desktop.ViewModels"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:DataType="vms:ThemeSettingViewModel"
|
||||
mc:Ignorable="d">
|
||||
<Button Width="30" Height="30">
|
||||
<Button.Content>
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
Source="/Assets/more.png" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<Flyout>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsColorMode}" />
|
||||
<ToggleSwitch
|
||||
x:Name="togDarkMode"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsFontSize}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentFontSize"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Classes="Margin8"
|
||||
Text="{x:Static resx:ResUI.TbSettingsLanguage}" />
|
||||
<ComboBox
|
||||
x:Name="cmbCurrentLanguage"
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Width="100"
|
||||
Classes="Margin8" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Flyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</UserControl>
|
37
v2rayN/v2rayN.Desktop/Views/ThemeSettingView.axaml.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using v2rayN.Desktop.ViewModels;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ThemeSettingView.xaml
|
||||
/// </summary>
|
||||
public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewModel>
|
||||
{
|
||||
public ThemeSettingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ThemeSettingViewModel();
|
||||
|
||||
for (int i = Global.MinFontSize; i <= Global.MinFontSize + 10; i++)
|
||||
{
|
||||
cmbCurrentFontSize.Items.Add(i);
|
||||
}
|
||||
|
||||
Global.Languages.ForEach(it =>
|
||||
{
|
||||
cmbCurrentLanguage.Items.Add(it);
|
||||
});
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.SelectedValue).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
39
v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj
Normal file
|
@ -0,0 +1,39 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<FileVersion>6.55</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectCapability Include="Avalonia" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.1.3" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.3" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.1.3" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.3" />
|
||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.3" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.1.3" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="3.1.6" />
|
||||
<PackageReference Include="Semi.Avalonia" Version="11.1.0.2" />
|
||||
<PackageReference Include="Semi.Avalonia.DataGrid" Version="11.1.0.2" />
|
||||
<PackageReference Include="ReactiveUI" Version="20.1.1" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ServiceLib\ServiceLib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
|
@ -9,9 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtosLib", "ProtosLib\Prot
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PacLib", "PacLib\PacLib.csproj", "{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayUpgrade", "v2rayUpgrade\v2rayUpgrade.csproj", "{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceLib", "ServiceLib\ServiceLib.csproj", "{1B6456C4-FFAA-4298-80F6-7B689A6E9243}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceLib", "ServiceLib\ServiceLib.csproj", "{1B6456C4-FFAA-4298-80F6-7B689A6E9243}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayN.Desktop", "v2rayN.Desktop\v2rayN.Desktop.csproj", "{5D16541A-F971-4C17-9315-BB8955E3F984}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "v2rayUpgrade", "v2rayUpgrade\v2rayUpgrade.csproj", "{47D68B1C-601C-4C69-873B-FFF0DC13EC97}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -31,14 +33,18 @@ Global
|
|||
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE4E6CD8-8353-446B-8F29-A841A02AE5EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3CD0B9E8-331B-42C6-A395-4DA0FD4BC8EB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1B6456C4-FFAA-4298-80F6-7B689A6E9243}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5D16541A-F971-4C17-9315-BB8955E3F984}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5D16541A-F971-4C17-9315-BB8955E3F984}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5D16541A-F971-4C17-9315-BB8955E3F984}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47D68B1C-601C-4C69-873B-FFF0DC13EC97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|