csharp_style_namespace_declarations = file_scoped
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
namespace v2rayN.Desktop.Common;
|
||||
|
||||
public static class AppBuilderExtension
|
||||
{
|
||||
public static class AppBuilderExtension
|
||||
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
|
||||
{
|
||||
public static AppBuilder WithFontByDefault(this AppBuilder appBuilder)
|
||||
var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC");
|
||||
return appBuilder.With(new FontManagerOptions()
|
||||
{
|
||||
var uri = Path.Combine(Global.AvaAssets, "Fonts#Noto Sans SC");
|
||||
return appBuilder.With(new FontManagerOptions()
|
||||
{
|
||||
//DefaultFamilyName = uri,
|
||||
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } }
|
||||
});
|
||||
}
|
||||
//DefaultFamilyName = uri,
|
||||
FontFallbacks = new[] { new FontFallback { FontFamily = new FontFamily(uri) } }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,56 +4,55 @@ using Avalonia.Input;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
|
||||
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;
|
||||
}
|
||||
namespace v2rayN.Desktop.Common;
|
||||
|
||||
return await clipboard.GetTextAsync();
|
||||
}
|
||||
catch
|
||||
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();
|
||||
}
|
||||
|
||||
public static async Task SetClipboardData(Visual? visual, string strData)
|
||||
catch
|
||||
{
|
||||
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)
|
||||
{
|
||||
var index = (int)sysProxyType + 1;
|
||||
var fileName = Utils.GetPath($"NotifyIcon{index}.ico");
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
return new(fileName);
|
||||
}
|
||||
|
||||
var uri = new Uri(Path.Combine(Global.AvaAssets, $"NotifyIcon{index}.ico"));
|
||||
using var bitmap = new Bitmap(AssetLoader.Open(uri));
|
||||
return new(bitmap);
|
||||
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)
|
||||
{
|
||||
var index = (int)sysProxyType + 1;
|
||||
var fileName = Utils.GetPath($"NotifyIcon{index}.ico");
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
return new(fileName);
|
||||
}
|
||||
|
||||
var uri = new Uri(Path.Combine(Global.AvaAssets, $"NotifyIcon{index}.ico"));
|
||||
using var bitmap = new Bitmap(AssetLoader.Open(uri));
|
||||
return new(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,56 +3,55 @@ using Avalonia.Platform.Storage;
|
||||
using MsBox.Avalonia;
|
||||
using MsBox.Avalonia.Enums;
|
||||
|
||||
namespace v2rayN.Desktop.Common
|
||||
namespace v2rayN.Desktop.Common;
|
||||
|
||||
internal class UI
|
||||
{
|
||||
internal class UI
|
||||
private static readonly string caption = Global.AppName;
|
||||
|
||||
public static async Task<ButtonResult> ShowYesNo(Window owner, string msg)
|
||||
{
|
||||
private static readonly string caption = Global.AppName;
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(caption, msg, ButtonEnum.YesNo);
|
||||
return await box.ShowWindowDialogAsync(owner);
|
||||
}
|
||||
|
||||
public static async Task<ButtonResult> ShowYesNo(Window owner, string msg)
|
||||
public static async Task<string?> OpenFileDialog(Window owner, FilePickerFileType? filter)
|
||||
{
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null)
|
||||
{
|
||||
var box = MessageBoxManager.GetMessageBoxStandard(caption, msg, ButtonEnum.YesNo);
|
||||
return await box.ShowWindowDialogAsync(owner);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<string?> OpenFileDialog(Window owner, FilePickerFileType? filter)
|
||||
// Start async operation to open the dialog.
|
||||
var files = await sp.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
AllowMultiple = false,
|
||||
FileTypeFilter = filter is null ? [FilePickerFileTypes.All, FilePickerFileTypes.ImagePng] : [filter]
|
||||
});
|
||||
|
||||
// Start async operation to open the dialog.
|
||||
var files = await sp.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
FileTypeFilter = filter is null ? [FilePickerFileTypes.All, FilePickerFileTypes.ImagePng] : [filter]
|
||||
});
|
||||
return files.FirstOrDefault()?.TryGetLocalPath();
|
||||
}
|
||||
|
||||
return files.FirstOrDefault()?.TryGetLocalPath();
|
||||
public static async Task<string?> SaveFileDialog(Window owner, string filter)
|
||||
{
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<string?> SaveFileDialog(Window owner, string filter)
|
||||
// Start async operation to open the dialog.
|
||||
var files = await sp.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
var sp = GetStorageProvider(owner);
|
||||
if (sp is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Start async operation to open the dialog.
|
||||
var files = await sp.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||
{
|
||||
});
|
||||
return files?.TryGetLocalPath();
|
||||
}
|
||||
|
||||
return files?.TryGetLocalPath();
|
||||
}
|
||||
|
||||
private static IStorageProvider? GetStorageProvider(Window owner)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
return topLevel?.StorageProvider;
|
||||
}
|
||||
private static IStorageProvider? GetStorageProvider(Window owner)
|
||||
{
|
||||
var topLevel = TopLevel.GetTopLevel(owner);
|
||||
return topLevel?.StorageProvider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,24 @@ using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace v2rayN.Desktop.Converters
|
||||
namespace v2rayN.Desktop.Converters;
|
||||
|
||||
public class DelayColorConverter : IValueConverter
|
||||
{
|
||||
public class DelayColorConverter : IValueConverter
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
_ = int.TryParse(value?.ToString(), out var delay);
|
||||
_ = int.TryParse(value?.ToString(), out var delay);
|
||||
|
||||
return delay switch
|
||||
{
|
||||
<= 0 => new SolidColorBrush(Colors.Red),
|
||||
<= 500 => new SolidColorBrush(Colors.Green),
|
||||
_ => new SolidColorBrush(Colors.IndianRed)
|
||||
};
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
return delay switch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
<= 0 => new SolidColorBrush(Colors.Red),
|
||||
<= 500 => new SolidColorBrush(Colors.Green),
|
||||
_ => new SolidColorBrush(Colors.IndianRed)
|
||||
};
|
||||
}
|
||||
|
||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,88 +4,87 @@ using Avalonia.ReactiveUI;
|
||||
using Avalonia.Win32.Input;
|
||||
using GlobalHotKeys;
|
||||
|
||||
namespace v2rayN.Desktop.Handler
|
||||
namespace v2rayN.Desktop.Handler;
|
||||
|
||||
public sealed class HotkeyHandler
|
||||
{
|
||||
public sealed class HotkeyHandler
|
||||
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||
public static HotkeyHandler Instance = _instance.Value;
|
||||
private readonly Dictionary<int, EGlobalHotkey> _hotkeyTriggerDic = new();
|
||||
private HotKeyManager? _hotKeyManager;
|
||||
|
||||
private Config? _config;
|
||||
|
||||
private event Action<EGlobalHotkey>? _updateFunc;
|
||||
|
||||
public bool IsPause { get; set; } = false;
|
||||
|
||||
public void Init(Config config, Action<EGlobalHotkey> updateFunc)
|
||||
{
|
||||
private static readonly Lazy<HotkeyHandler> _instance = new(() => new());
|
||||
public static HotkeyHandler Instance = _instance.Value;
|
||||
private readonly Dictionary<int, EGlobalHotkey> _hotkeyTriggerDic = new();
|
||||
private HotKeyManager? _hotKeyManager;
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
|
||||
private Config? _config;
|
||||
Register();
|
||||
}
|
||||
|
||||
private event Action<EGlobalHotkey>? _updateFunc;
|
||||
public void Dispose()
|
||||
{
|
||||
_hotKeyManager?.Dispose();
|
||||
}
|
||||
|
||||
public bool IsPause { get; set; } = false;
|
||||
|
||||
public void Init(Config config, Action<EGlobalHotkey> updateFunc)
|
||||
private void Register()
|
||||
{
|
||||
if (_config.GlobalHotkeys.Any(t => t.KeyCode > 0) == false)
|
||||
{
|
||||
_config = config;
|
||||
_updateFunc = updateFunc;
|
||||
return;
|
||||
}
|
||||
_hotKeyManager ??= new GlobalHotKeys.HotKeyManager();
|
||||
_hotkeyTriggerDic.Clear();
|
||||
|
||||
Register();
|
||||
foreach (var item in _config.GlobalHotkeys)
|
||||
{
|
||||
if (item.KeyCode is null or 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||
var modifiers = Modifiers.None;
|
||||
if (item.Control)
|
||||
{
|
||||
modifiers |= Modifiers.Control;
|
||||
}
|
||||
if (item.Shift)
|
||||
{
|
||||
modifiers |= Modifiers.Shift;
|
||||
}
|
||||
if (item.Alt)
|
||||
{
|
||||
modifiers |= Modifiers.Alt;
|
||||
}
|
||||
|
||||
var result = _hotKeyManager?.Register((VirtualKeyCode)vKey, modifiers);
|
||||
if (result?.IsSuccessful == true)
|
||||
{
|
||||
_hotkeyTriggerDic.Add(result.Id, item.EGlobalHotkey);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
_hotKeyManager?.HotKeyPressed
|
||||
.ObserveOn(AvaloniaScheduler.Instance)
|
||||
.Subscribe(OnNext);
|
||||
}
|
||||
|
||||
private void OnNext(HotKey key)
|
||||
{
|
||||
if (_updateFunc == null || IsPause)
|
||||
{
|
||||
_hotKeyManager?.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
private void Register()
|
||||
if (_hotkeyTriggerDic.TryGetValue(key.Id, out var value))
|
||||
{
|
||||
if (_config.GlobalHotkeys.Any(t => t.KeyCode > 0) == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_hotKeyManager ??= new GlobalHotKeys.HotKeyManager();
|
||||
_hotkeyTriggerDic.Clear();
|
||||
|
||||
foreach (var item in _config.GlobalHotkeys)
|
||||
{
|
||||
if (item.KeyCode is null or 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
|
||||
var modifiers = Modifiers.None;
|
||||
if (item.Control)
|
||||
{
|
||||
modifiers |= Modifiers.Control;
|
||||
}
|
||||
if (item.Shift)
|
||||
{
|
||||
modifiers |= Modifiers.Shift;
|
||||
}
|
||||
if (item.Alt)
|
||||
{
|
||||
modifiers |= Modifiers.Alt;
|
||||
}
|
||||
|
||||
var result = _hotKeyManager?.Register((VirtualKeyCode)vKey, modifiers);
|
||||
if (result?.IsSuccessful == true)
|
||||
{
|
||||
_hotkeyTriggerDic.Add(result.Id, item.EGlobalHotkey);
|
||||
}
|
||||
}
|
||||
|
||||
_hotKeyManager?.HotKeyPressed
|
||||
.ObserveOn(AvaloniaScheduler.Instance)
|
||||
.Subscribe(OnNext);
|
||||
}
|
||||
|
||||
private void OnNext(HotKey key)
|
||||
{
|
||||
if (_updateFunc == null || IsPause)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hotkeyTriggerDic.TryGetValue(key.Id, out var value))
|
||||
{
|
||||
_updateFunc?.Invoke(value);
|
||||
}
|
||||
_updateFunc?.Invoke(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,100 +9,139 @@ using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
using Semi.Avalonia;
|
||||
|
||||
namespace v2rayN.Desktop.ViewModels
|
||||
namespace v2rayN.Desktop.ViewModels;
|
||||
|
||||
public class ThemeSettingViewModel : MyReactiveObject
|
||||
{
|
||||
public class ThemeSettingViewModel : MyReactiveObject
|
||||
[Reactive] public string CurrentTheme { get; set; }
|
||||
|
||||
[Reactive] public int CurrentFontSize { get; set; }
|
||||
|
||||
[Reactive] public string CurrentLanguage { get; set; }
|
||||
|
||||
public ThemeSettingViewModel()
|
||||
{
|
||||
[Reactive] public string CurrentTheme { get; set; }
|
||||
_config = AppHandler.Instance.Config;
|
||||
|
||||
[Reactive] public int CurrentFontSize { get; set; }
|
||||
BindingUI();
|
||||
RestoreUI();
|
||||
}
|
||||
|
||||
[Reactive] public string CurrentLanguage { get; set; }
|
||||
private void RestoreUI()
|
||||
{
|
||||
ModifyTheme();
|
||||
ModifyFontFamily();
|
||||
ModifyFontSize();
|
||||
}
|
||||
|
||||
public ThemeSettingViewModel()
|
||||
{
|
||||
_config = AppHandler.Instance.Config;
|
||||
private void BindingUI()
|
||||
{
|
||||
CurrentTheme = _config.UiItem.CurrentTheme;
|
||||
CurrentFontSize = _config.UiItem.CurrentFontSize;
|
||||
CurrentLanguage = _config.UiItem.CurrentLanguage;
|
||||
|
||||
BindingUI();
|
||||
RestoreUI();
|
||||
}
|
||||
|
||||
private void RestoreUI()
|
||||
{
|
||||
ModifyTheme();
|
||||
ModifyFontFamily();
|
||||
ModifyFontSize();
|
||||
}
|
||||
|
||||
private void BindingUI()
|
||||
{
|
||||
CurrentTheme = _config.UiItem.CurrentTheme;
|
||||
CurrentFontSize = _config.UiItem.CurrentFontSize;
|
||||
CurrentLanguage = _config.UiItem.CurrentLanguage;
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentTheme)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.UiItem.CurrentTheme != CurrentTheme)
|
||||
{
|
||||
_config.UiItem.CurrentTheme = CurrentTheme;
|
||||
ModifyTheme();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.UiItem.CurrentFontSize != CurrentFontSize && CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.UiItem.CurrentFontSize = CurrentFontSize;
|
||||
ModifyFontSize();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (CurrentLanguage.IsNotEmpty() && _config.UiItem.CurrentLanguage != CurrentLanguage)
|
||||
{
|
||||
_config.UiItem.CurrentLanguage = CurrentLanguage;
|
||||
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
NoticeHandler.Instance.Enqueue(ResUI.NeedRebootTips);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ModifyTheme()
|
||||
{
|
||||
var app = Application.Current;
|
||||
if (app is not null)
|
||||
this.WhenAnyValue(x => x.CurrentTheme)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
app.RequestedThemeVariant = CurrentTheme switch
|
||||
if (_config.UiItem.CurrentTheme != CurrentTheme)
|
||||
{
|
||||
nameof(ETheme.Dark) => ThemeVariant.Dark,
|
||||
nameof(ETheme.Light) => ThemeVariant.Light,
|
||||
nameof(ETheme.Aquatic) => SemiTheme.Aquatic,
|
||||
nameof(ETheme.Desert) => SemiTheme.Desert,
|
||||
nameof(ETheme.Dusk) => SemiTheme.Dusk,
|
||||
nameof(ETheme.NightSky) => SemiTheme.NightSky,
|
||||
_ => ThemeVariant.Default,
|
||||
};
|
||||
}
|
||||
_config.UiItem.CurrentTheme = CurrentTheme;
|
||||
ModifyTheme();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentFontSize,
|
||||
y => y > 0)
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (_config.UiItem.CurrentFontSize != CurrentFontSize && CurrentFontSize >= Global.MinFontSize)
|
||||
{
|
||||
_config.UiItem.CurrentFontSize = CurrentFontSize;
|
||||
ModifyFontSize();
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
}
|
||||
});
|
||||
|
||||
this.WhenAnyValue(
|
||||
x => x.CurrentLanguage,
|
||||
y => y != null && !y.IsNullOrEmpty())
|
||||
.Subscribe(c =>
|
||||
{
|
||||
if (CurrentLanguage.IsNotEmpty() && _config.UiItem.CurrentLanguage != CurrentLanguage)
|
||||
{
|
||||
_config.UiItem.CurrentLanguage = CurrentLanguage;
|
||||
Thread.CurrentThread.CurrentUICulture = new(CurrentLanguage);
|
||||
ConfigHandler.SaveConfig(_config);
|
||||
NoticeHandler.Instance.Enqueue(ResUI.NeedRebootTips);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ModifyTheme()
|
||||
{
|
||||
var app = Application.Current;
|
||||
if (app is not null)
|
||||
{
|
||||
app.RequestedThemeVariant = CurrentTheme switch
|
||||
{
|
||||
nameof(ETheme.Dark) => ThemeVariant.Dark,
|
||||
nameof(ETheme.Light) => ThemeVariant.Light,
|
||||
nameof(ETheme.Aquatic) => SemiTheme.Aquatic,
|
||||
nameof(ETheme.Desert) => SemiTheme.Desert,
|
||||
nameof(ETheme.Dusk) => SemiTheme.Dusk,
|
||||
nameof(ETheme.NightSky) => SemiTheme.NightSky,
|
||||
_ => ThemeVariant.Default,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void ModifyFontSize()
|
||||
{
|
||||
double size = CurrentFontSize;
|
||||
if (size < Global.MinFontSize)
|
||||
return;
|
||||
|
||||
Style style = new(x => Selectors.Or(
|
||||
x.OfType<Button>(),
|
||||
x.OfType<TextBox>(),
|
||||
x.OfType<TextBlock>(),
|
||||
x.OfType<Menu>(),
|
||||
x.OfType<ContextMenu>(),
|
||||
x.OfType<DataGridRow>(),
|
||||
x.OfType<ListBoxItem>(),
|
||||
x.OfType<HeaderedContentControl>()
|
||||
));
|
||||
style.Add(new Setter()
|
||||
{
|
||||
Property = TemplatedControl.FontSizeProperty,
|
||||
Value = size,
|
||||
});
|
||||
Application.Current?.Styles.Add(style);
|
||||
|
||||
ModifyFontSizeEx(size);
|
||||
}
|
||||
|
||||
private void ModifyFontSizeEx(double size)
|
||||
{
|
||||
//DataGrid
|
||||
var rowHeight = 20 + (size / 2);
|
||||
var style = new Style(x => x.OfType<DataGrid>());
|
||||
style.Add(new Setter(DataGrid.RowHeightProperty, rowHeight));
|
||||
Application.Current?.Styles.Add(style);
|
||||
}
|
||||
|
||||
private void ModifyFontFamily()
|
||||
{
|
||||
var currentFontFamily = _config.UiItem.CurrentFontFamily;
|
||||
if (currentFontFamily.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void ModifyFontSize()
|
||||
try
|
||||
{
|
||||
double size = CurrentFontSize;
|
||||
if (size < Global.MinFontSize)
|
||||
return;
|
||||
|
||||
Style style = new(x => Selectors.Or(
|
||||
x.OfType<Button>(),
|
||||
x.OfType<TextBox>(),
|
||||
@@ -111,59 +150,19 @@ namespace v2rayN.Desktop.ViewModels
|
||||
x.OfType<ContextMenu>(),
|
||||
x.OfType<DataGridRow>(),
|
||||
x.OfType<ListBoxItem>(),
|
||||
x.OfType<HeaderedContentControl>()
|
||||
x.OfType<HeaderedContentControl>(),
|
||||
x.OfType<WindowNotificationManager>()
|
||||
));
|
||||
style.Add(new Setter()
|
||||
{
|
||||
Property = TemplatedControl.FontSizeProperty,
|
||||
Value = size,
|
||||
Property = TemplatedControl.FontFamilyProperty,
|
||||
Value = new FontFamily(currentFontFamily),
|
||||
});
|
||||
Application.Current?.Styles.Add(style);
|
||||
|
||||
ModifyFontSizeEx(size);
|
||||
}
|
||||
|
||||
private void ModifyFontSizeEx(double size)
|
||||
catch (Exception ex)
|
||||
{
|
||||
//DataGrid
|
||||
var rowHeight = 20 + (size / 2);
|
||||
var style = new Style(x => x.OfType<DataGrid>());
|
||||
style.Add(new Setter(DataGrid.RowHeightProperty, rowHeight));
|
||||
Application.Current?.Styles.Add(style);
|
||||
}
|
||||
|
||||
private void ModifyFontFamily()
|
||||
{
|
||||
var currentFontFamily = _config.UiItem.CurrentFontFamily;
|
||||
if (currentFontFamily.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Style style = new(x => Selectors.Or(
|
||||
x.OfType<Button>(),
|
||||
x.OfType<TextBox>(),
|
||||
x.OfType<TextBlock>(),
|
||||
x.OfType<Menu>(),
|
||||
x.OfType<ContextMenu>(),
|
||||
x.OfType<DataGridRow>(),
|
||||
x.OfType<ListBoxItem>(),
|
||||
x.OfType<HeaderedContentControl>(),
|
||||
x.OfType<WindowNotificationManager>()
|
||||
));
|
||||
style.Add(new Setter()
|
||||
{
|
||||
Property = TemplatedControl.FontFamilyProperty,
|
||||
Value = new FontFamily(currentFontFamily),
|
||||
});
|
||||
Application.Current?.Styles.Add(style);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("ModifyFontFamily", ex);
|
||||
}
|
||||
Logging.SaveLog("ModifyFontFamily", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,69 +4,68 @@ using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||
{
|
||||
public partial class AddServer2Window : ReactiveWindow<AddServer2ViewModel>
|
||||
public AddServer2Window()
|
||||
{
|
||||
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)))
|
||||
{
|
||||
InitializeComponent();
|
||||
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;
|
||||
}
|
||||
|
||||
public AddServer2Window(ProfileItem profileItem)
|
||||
{
|
||||
InitializeComponent();
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,369 +4,368 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||
{
|
||||
public partial class AddServerWindow : ReactiveWindow<AddServerViewModel>
|
||||
public AddServerWindow()
|
||||
{
|
||||
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);
|
||||
|
||||
Global.CoreTypes.ForEach(it =>
|
||||
{
|
||||
InitializeComponent();
|
||||
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;
|
||||
AppHandler.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;
|
||||
}
|
||||
|
||||
public AddServerWindow(ProfileItem profileItem)
|
||||
gridTlsMore.IsVisible = false;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
});
|
||||
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:
|
||||
gridVMess.IsVisible = true;
|
||||
Global.VmessSecurities.ForEach(it =>
|
||||
{
|
||||
cmbSecurity.Items.Add(it);
|
||||
});
|
||||
if (profileItem.Security.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.Security = Global.DefaultSecurity;
|
||||
}
|
||||
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:
|
||||
gridSs.IsVisible = true;
|
||||
AppHandler.Instance.GetShadowsocksSecurities(profileItem).ForEach(it =>
|
||||
{
|
||||
cmbSecurity3.Items.Add(it);
|
||||
});
|
||||
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:
|
||||
gridSocks.IsVisible = true;
|
||||
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:
|
||||
gridVLESS.IsVisible = true;
|
||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
||||
Global.Flows.ForEach(it =>
|
||||
{
|
||||
cmbFlow5.Items.Add(it);
|
||||
});
|
||||
if (profileItem.Security.IsNullOrEmpty())
|
||||
{
|
||||
profileItem.Security = Global.None;
|
||||
}
|
||||
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:
|
||||
gridTrojan.IsVisible = true;
|
||||
cmbStreamSecurity.Items.Add(Global.StreamSecurityReality);
|
||||
Global.Flows.ForEach(it =>
|
||||
{
|
||||
cmbFlow6.Items.Add(it);
|
||||
});
|
||||
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:
|
||||
gridHysteria2.IsVisible = true;
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
cmbFingerprint.IsEnabled = false;
|
||||
cmbFingerprint.SelectedValue = string.Empty;
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
|
||||
break;
|
||||
|
||||
case EConfigType.TUIC:
|
||||
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);
|
||||
});
|
||||
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:
|
||||
gridWireguard.IsVisible = true;
|
||||
|
||||
sepa2.IsVisible = false;
|
||||
gridTransport.IsVisible = false;
|
||||
gridTls.IsVisible = false;
|
||||
cmbCoreType.IsEnabled = false;
|
||||
|
||||
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.Extra, v => v.txtExtra.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;
|
||||
}
|
||||
}
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
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 (network.IsNullOrEmpty())
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
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);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.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.Extra, v => v.txtExtra.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);
|
||||
cmbHeaderType.Items.Add(it);
|
||||
});
|
||||
|
||||
this.Title = $"{profileItem.ConfigType}";
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
else if (network is nameof(ETransport.xhttp))
|
||||
{
|
||||
switch (action)
|
||||
Global.XhttpMode.ForEach(it =>
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
cmbHeaderType.Items.Add(it);
|
||||
});
|
||||
}
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
else if (network == nameof(ETransport.grpc))
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
cmbHeaderType.Items.Add(Global.GrpcGunMode);
|
||||
cmbHeaderType.Items.Add(Global.GrpcMultiMode);
|
||||
}
|
||||
|
||||
private void CmbNetwork_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
else
|
||||
{
|
||||
SetHeaderType();
|
||||
SetTips();
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
}
|
||||
cmbHeaderType.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void CmbStreamSecurity_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
private void SetTips()
|
||||
{
|
||||
var network = cmbNetwork.SelectedItem.ToString();
|
||||
if (network.IsNullOrEmpty())
|
||||
{
|
||||
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;
|
||||
}
|
||||
network = Global.DefaultNetwork;
|
||||
}
|
||||
labHeaderType.IsVisible = true;
|
||||
btnExtra.IsVisible = false;
|
||||
tipRequestHost.Text =
|
||||
tipPath.Text =
|
||||
tipHeaderType.Text = string.Empty;
|
||||
|
||||
private void btnGUID_Click(object? sender, RoutedEventArgs e)
|
||||
switch (network)
|
||||
{
|
||||
txtId.Text =
|
||||
txtId5.Text = Utils.GetGuid();
|
||||
}
|
||||
case nameof(ETransport.tcp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip1;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
|
||||
break;
|
||||
|
||||
private void SetHeaderType()
|
||||
{
|
||||
cmbHeaderType.Items.Clear();
|
||||
case nameof(ETransport.kcp):
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip5;
|
||||
break;
|
||||
|
||||
var network = cmbNetwork.SelectedItem.ToString();
|
||||
if (network.IsNullOrEmpty())
|
||||
{
|
||||
cmbHeaderType.Items.Add(Global.None);
|
||||
return;
|
||||
}
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
break;
|
||||
|
||||
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 is nameof(ETransport.xhttp))
|
||||
{
|
||||
Global.XhttpMode.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;
|
||||
}
|
||||
case nameof(ETransport.xhttp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
|
||||
labHeaderType.IsVisible = false;
|
||||
btnExtra.IsVisible = true;
|
||||
break;
|
||||
|
||||
private void SetTips()
|
||||
{
|
||||
var network = cmbNetwork.SelectedItem.ToString();
|
||||
if (network.IsNullOrEmpty())
|
||||
{
|
||||
network = Global.DefaultNetwork;
|
||||
}
|
||||
labHeaderType.IsVisible = true;
|
||||
btnExtra.IsVisible = false;
|
||||
tipRequestHost.Text =
|
||||
tipPath.Text =
|
||||
tipHeaderType.Text = string.Empty;
|
||||
case nameof(ETransport.h2):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip3;
|
||||
tipPath.Text = ResUI.TransportPathTip2;
|
||||
break;
|
||||
|
||||
switch (network)
|
||||
{
|
||||
case nameof(ETransport.tcp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip1;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip1;
|
||||
break;
|
||||
case nameof(ETransport.quic):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip4;
|
||||
tipPath.Text = ResUI.TransportPathTip3;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip3;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.kcp):
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip5;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.ws):
|
||||
case nameof(ETransport.httpupgrade):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
break;
|
||||
|
||||
case nameof(ETransport.xhttp):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip2;
|
||||
tipPath.Text = ResUI.TransportPathTip1;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip5;
|
||||
labHeaderType.IsVisible = false;
|
||||
btnExtra.IsVisible = true;
|
||||
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;
|
||||
}
|
||||
case nameof(ETransport.grpc):
|
||||
tipRequestHost.Text = ResUI.TransportRequestHostTip5;
|
||||
tipPath.Text = ResUI.TransportPathTip4;
|
||||
tipHeaderType.Text = ResUI.TransportHeaderTypeTip4;
|
||||
labHeaderType.IsVisible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,68 +5,67 @@ using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class BackupAndRestoreView : ReactiveUserControl<BackupAndRestoreViewModel>
|
||||
{
|
||||
public partial class BackupAndRestoreView : ReactiveUserControl<BackupAndRestoreViewModel>
|
||||
private Window? _window;
|
||||
|
||||
public BackupAndRestoreView()
|
||||
{
|
||||
private Window? _window;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public BackupAndRestoreView()
|
||||
public BackupAndRestoreView(Window window)
|
||||
{
|
||||
_window = window;
|
||||
|
||||
InitializeComponent();
|
||||
menuLocalBackup.Click += MenuLocalBackup_Click;
|
||||
menuLocalRestore.Click += MenuLocalRestore_Click;
|
||||
|
||||
ViewModel = new BackupAndRestoreViewModel(UpdateViewHandler);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Bind(ViewModel, vm => vm.OperationMsg, v => v.txtMsg.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Url, v => v.txtWebDavUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.UserName, v => v.txtWebDavUserName.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtWebDavPassword.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.DirName, v => v.txtWebDavDirName.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.WebDavCheckCmd, v => v.menuWebDavCheck).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RemoteBackupCmd, v => v.menuRemoteBackup).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoteRestoreCmd, v => v.menuRemoteRestore).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async void MenuLocalBackup_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.SaveFileDialog(_window, "Zip|*.zip");
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public BackupAndRestoreView(Window window)
|
||||
ViewModel?.LocalBackup(fileName);
|
||||
}
|
||||
|
||||
private async void MenuLocalRestore_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(_window, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
_window = window;
|
||||
|
||||
InitializeComponent();
|
||||
menuLocalBackup.Click += MenuLocalBackup_Click;
|
||||
menuLocalRestore.Click += MenuLocalRestore_Click;
|
||||
|
||||
ViewModel = new BackupAndRestoreViewModel(UpdateViewHandler);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.OperationMsg, v => v.txtMsg.Text).DisposeWith(disposables);
|
||||
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Url, v => v.txtWebDavUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.UserName, v => v.txtWebDavUserName.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Password, v => v.txtWebDavPassword.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.DirName, v => v.txtWebDavDirName.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.WebDavCheckCmd, v => v.menuWebDavCheck).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.RemoteBackupCmd, v => v.menuRemoteBackup).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoteRestoreCmd, v => v.menuRemoteRestore).DisposeWith(disposables);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
private async void MenuLocalBackup_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.SaveFileDialog(_window, "Zip|*.zip");
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
ViewModel?.LocalRestore(fileName);
|
||||
}
|
||||
|
||||
ViewModel?.LocalBackup(fileName);
|
||||
}
|
||||
|
||||
private async void MenuLocalRestore_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(_window, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel?.LocalRestore(fileName);
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,47 +3,46 @@ using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class CheckUpdateView : ReactiveUserControl<CheckUpdateViewModel>
|
||||
{
|
||||
public partial class CheckUpdateView : ReactiveUserControl<CheckUpdateViewModel>
|
||||
public CheckUpdateView()
|
||||
{
|
||||
public CheckUpdateView()
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel = new CheckUpdateViewModel(UpdateViewHandler);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
|
||||
|
||||
ViewModel = new CheckUpdateViewModel(UpdateViewHandler);
|
||||
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, vm => vm.CheckUpdateModels, v => v.lstCheckUpdates.ItemsSource).DisposeWith(disposables);
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherCheckUpdate:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.UpdateViewResult((CheckUpdateModel)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
this.Bind(ViewModel, vm => vm.EnableCheckPreReleaseUpdate, v => v.togEnableCheckPreReleaseUpdate.IsChecked).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.CheckUpdateCmd, v => v.btnCheckUpdate).DisposeWith(disposables);
|
||||
});
|
||||
case EViewAction.DispatcherCheckUpdateFinished:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.UpdateFinishedResult((bool)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherCheckUpdate:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.UpdateViewResult((CheckUpdateModel)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherCheckUpdateFinished:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.UpdateFinishedResult((bool)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,62 +5,61 @@ using Avalonia.ReactiveUI;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class ClashConnectionsView : ReactiveUserControl<ClashConnectionsViewModel>
|
||||
{
|
||||
public partial class ClashConnectionsView : ReactiveUserControl<ClashConnectionsViewModel>
|
||||
public ClashConnectionsView()
|
||||
{
|
||||
public ClashConnectionsView()
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
|
||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
|
||||
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
|
||||
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.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.BindCommand(ViewModel, vm => vm.ConnectionCloseCmd, v => v.menuConnectionClose).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.menuConnectionCloseAll).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.ConnectionCloseAllCmd, v => v.btnConnectionCloseAll).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
this.Bind(ViewModel, vm => vm.HostFilter, v => v.txtHostFilter.Text).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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
}
|
||||
|
||||
private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
|
||||
private void AutofitColumnWidth()
|
||||
{
|
||||
foreach (var it in lstConnections.Columns)
|
||||
{
|
||||
AutofitColumnWidth();
|
||||
}
|
||||
|
||||
private void AutofitColumnWidth()
|
||||
{
|
||||
foreach (var it in lstConnections.Columns)
|
||||
{
|
||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ClashConnectionClose(false);
|
||||
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ClashConnectionClose(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,77 +6,76 @@ using DynamicData;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class ClashProxiesView : ReactiveUserControl<ClashProxiesViewModel>
|
||||
{
|
||||
public partial class ClashProxiesView : ReactiveUserControl<ClashProxiesViewModel>
|
||||
public ClashProxiesView()
|
||||
{
|
||||
public ClashProxiesView()
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel));
|
||||
lstProxyDetails.DoubleTapped += LstProxyDetails_DoubleTapped;
|
||||
this.KeyDown += ClashProxiesView_KeyDown;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel));
|
||||
lstProxyDetails.DoubleTapped += LstProxyDetails_DoubleTapped;
|
||||
this.KeyDown += ClashProxiesView_KeyDown;
|
||||
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.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.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.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.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);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void ClashProxiesView_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherRefreshProxyGroups:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshProxyGroups(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
case Key.F5:
|
||||
ViewModel?.ProxiesReload();
|
||||
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();
|
||||
case Key.Enter:
|
||||
ViewModel?.SetActiveProxy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProxyDetails_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.SetActiveProxy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,74 +3,73 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||
{
|
||||
public partial class DNSSettingWindow : ReactiveWindow<DNSSettingViewModel>
|
||||
private static Config _config;
|
||||
|
||||
public DNSSettingWindow()
|
||||
{
|
||||
private static Config _config;
|
||||
InitializeComponent();
|
||||
|
||||
public DNSSettingWindow()
|
||||
_config = AppHandler.Instance.Config;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
ViewModel = new DNSSettingViewModel(UpdateViewHandler);
|
||||
|
||||
Global.DomainStrategy4Freedoms.ForEach(it =>
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_config = AppHandler.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)
|
||||
cmbdomainStrategy4Freedom.Items.Add(it);
|
||||
});
|
||||
Global.SingboxDomainStrategy4Out.ForEach(it =>
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void linkDnsObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
cmbdomainStrategy4Out.Items.Add(it);
|
||||
});
|
||||
Global.DomainDNSAddress.ForEach(it =>
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject");
|
||||
}
|
||||
|
||||
private void linkDnsSingboxObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
cmbdomainDNSAddress.Items.Add(it);
|
||||
});
|
||||
Global.SingboxDomainDNSAddress.ForEach(it =>
|
||||
{
|
||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
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)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/dns.html#dnsobject");
|
||||
}
|
||||
|
||||
private void linkDnsSingboxObjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://sing-box.sagernet.org/zh/configuration/dns/");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,132 +7,131 @@ using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Handler;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||
{
|
||||
public partial class GlobalHotkeySettingWindow : ReactiveWindow<GlobalHotkeySettingViewModel>
|
||||
private readonly List<object> _textBoxKeyEventItem = new();
|
||||
|
||||
public GlobalHotkeySettingWindow()
|
||||
{
|
||||
private readonly List<object> _textBoxKeyEventItem = new();
|
||||
InitializeComponent();
|
||||
|
||||
public GlobalHotkeySettingWindow()
|
||||
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||
|
||||
btnReset.Click += btnReset_Click;
|
||||
|
||||
HotkeyHandler.Instance.IsPause = true;
|
||||
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
ViewModel = new GlobalHotkeySettingViewModel(UpdateViewHandler);
|
||||
Init();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
btnReset.Click += btnReset_Click;
|
||||
|
||||
HotkeyHandler.Instance.IsPause = true;
|
||||
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
Init();
|
||||
BindingData();
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
private void Init()
|
||||
{
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||
|
||||
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey0);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey1);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey2);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey3);
|
||||
_textBoxKeyEventItem.Add(txtGlobalHotkey4);
|
||||
|
||||
for (var index = 0; index < _textBoxKeyEventItem.Count; index++)
|
||||
{
|
||||
var sender = _textBoxKeyEventItem[index];
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
txtBox.Tag = (EGlobalHotkey)index;
|
||||
txtBox.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
var sender = _textBoxKeyEventItem[index];
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
txtBox.Tag = (EGlobalHotkey)index;
|
||||
txtBox.KeyDown += TxtGlobalHotkey_PreviewKeyDown;
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtGlobalHotkey_PreviewKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||
|
||||
item.KeyCode = (int)(e.Key == Key.System ? modifierKeys.Contains(Key.System) ? Key.None : Key.System : modifierKeys.Contains(e.Key) ? Key.None : e.Key);
|
||||
item.Alt = (e.KeyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt;
|
||||
item.Control = (e.KeyModifiers & KeyModifiers.Control) == KeyModifiers.Control;
|
||||
item.Shift = (e.KeyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift;
|
||||
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
|
||||
private void BindingData()
|
||||
{
|
||||
foreach (var sender in _textBoxKeyEventItem)
|
||||
{
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
var modifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin };
|
||||
|
||||
item.KeyCode = (int)(e.Key == Key.System ? modifierKeys.Contains(Key.System) ? Key.None : Key.System : modifierKeys.Contains(e.Key) ? Key.None : e.Key);
|
||||
item.Alt = (e.KeyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt;
|
||||
item.Control = (e.KeyModifiers & KeyModifiers.Control) == KeyModifiers.Control;
|
||||
item.Shift = (e.KeyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift;
|
||||
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindingData()
|
||||
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel?.ResetKeyEventItem();
|
||||
BindingData();
|
||||
}
|
||||
|
||||
private string KeyEventItemToString(KeyEventItem? item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
foreach (var sender in _textBoxKeyEventItem)
|
||||
{
|
||||
if (sender is not TextBox txtBox)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
var res = new StringBuilder();
|
||||
|
||||
var item = ViewModel?.GetKeyEventItem((EGlobalHotkey)txtBox.Tag);
|
||||
txtBox.Text = KeyEventItemToString(item);
|
||||
}
|
||||
if (item.Control)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Control} +");
|
||||
}
|
||||
|
||||
private void btnReset_Click(object sender, RoutedEventArgs e)
|
||||
if (item.Shift)
|
||||
{
|
||||
ViewModel?.ResetKeyEventItem();
|
||||
BindingData();
|
||||
res.Append($"{KeyModifiers.Shift} +");
|
||||
}
|
||||
|
||||
private string KeyEventItemToString(KeyEventItem? item)
|
||||
if (item.Alt)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
var res = new StringBuilder();
|
||||
|
||||
if (item.Control)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Control} +");
|
||||
}
|
||||
|
||||
if (item.Shift)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Shift} +");
|
||||
}
|
||||
|
||||
if (item.Alt)
|
||||
{
|
||||
res.Append($"{KeyModifiers.Alt} +");
|
||||
}
|
||||
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
{
|
||||
res.Append($"{(Key)item.KeyCode}");
|
||||
}
|
||||
|
||||
return res.ToString();
|
||||
res.Append($"{KeyModifiers.Alt} +");
|
||||
}
|
||||
|
||||
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
|
||||
{
|
||||
res.Append($"{(Key)item.KeyCode}");
|
||||
}
|
||||
|
||||
return res.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,238 +14,306 @@ using Splat;
|
||||
using v2rayN.Desktop.Common;
|
||||
using v2rayN.Desktop.Handler;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
{
|
||||
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
private static Config _config;
|
||||
private WindowNotificationManager? _manager;
|
||||
private CheckUpdateView? _checkUpdateView;
|
||||
private BackupAndRestoreView? _backupAndRestoreView;
|
||||
private bool _blCloseByUser = false;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
private static Config _config;
|
||||
private WindowNotificationManager? _manager;
|
||||
private CheckUpdateView? _checkUpdateView;
|
||||
private BackupAndRestoreView? _backupAndRestoreView;
|
||||
private bool _blCloseByUser = false;
|
||||
InitializeComponent();
|
||||
|
||||
public MainWindow()
|
||||
_config = AppHandler.Instance.Config;
|
||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
||||
|
||||
this.KeyDown += MainWindow_KeyDown;
|
||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||
menuPromotion.Click += menuPromotion_Click;
|
||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
||||
menuClose.Click += MenuClose_Click;
|
||||
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.SendSnackMsg.ToString()).Subscribe(DelegateSnackMsg);
|
||||
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
||||
|
||||
switch (_config.UiItem.MainGirdOrientation)
|
||||
{
|
||||
InitializeComponent();
|
||||
case EGirdOrientation.Horizontal:
|
||||
tabProfiles.Content ??= new ProfilesView(this);
|
||||
tabMsgView.Content ??= new MsgView();
|
||||
tabClashProxies.Content ??= new ClashProxiesView();
|
||||
tabClashConnections.Content ??= new ClashConnectionsView();
|
||||
gridMain.IsVisible = true;
|
||||
break;
|
||||
|
||||
_config = AppHandler.Instance.Config;
|
||||
_manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.BottomRight };
|
||||
case EGirdOrientation.Vertical:
|
||||
tabProfiles1.Content ??= new ProfilesView(this);
|
||||
tabMsgView1.Content ??= new MsgView();
|
||||
tabClashProxies1.Content ??= new ClashProxiesView();
|
||||
tabClashConnections1.Content ??= new ClashConnectionsView();
|
||||
gridMain1.IsVisible = true;
|
||||
break;
|
||||
|
||||
this.KeyDown += MainWindow_KeyDown;
|
||||
menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
|
||||
menuPromotion.Click += menuPromotion_Click;
|
||||
menuCheckUpdate.Click += MenuCheckUpdate_Click;
|
||||
menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
|
||||
menuClose.Click += MenuClose_Click;
|
||||
case EGirdOrientation.Tab:
|
||||
default:
|
||||
tabProfiles2.Content ??= new ProfilesView(this);
|
||||
tabMsgView2.Content ??= new MsgView();
|
||||
tabClashProxies2.Content ??= new ClashProxiesView();
|
||||
tabClashConnections2.Content ??= new ClashConnectionsView();
|
||||
gridMain2.IsVisible = true;
|
||||
break;
|
||||
}
|
||||
conTheme.Content ??= new ThemeSettingView();
|
||||
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.SendSnackMsg.ToString()).Subscribe(DelegateSnackMsg);
|
||||
ViewModel = new MainWindowViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
|
||||
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);
|
||||
this.BindCommand(ViewModel, vm => vm.AddServerViaImageCmd, v => v.menuAddServerViaImage).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);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetDefaultCmd, v => v.menuRegionalPresetsDefault).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetRussiaCmd, v => v.menuRegionalPresetsRussia).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetIranCmd, v => v.menuRegionalPresetsIran).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);
|
||||
|
||||
switch (_config.UiItem.MainGirdOrientation)
|
||||
{
|
||||
case EGirdOrientation.Horizontal:
|
||||
tabProfiles.Content ??= new ProfilesView(this);
|
||||
tabMsgView.Content ??= new MsgView();
|
||||
tabClashProxies.Content ??= new ClashProxiesView();
|
||||
tabClashConnections.Content ??= new ClashConnectionsView();
|
||||
gridMain.IsVisible = true;
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView.IsVisible).DisposeWith(disposables);
|
||||
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);
|
||||
break;
|
||||
|
||||
case EGirdOrientation.Vertical:
|
||||
tabProfiles1.Content ??= new ProfilesView(this);
|
||||
tabMsgView1.Content ??= new MsgView();
|
||||
tabClashProxies1.Content ??= new ClashProxiesView();
|
||||
tabClashConnections1.Content ??= new ClashConnectionsView();
|
||||
gridMain1.IsVisible = true;
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView1.IsVisible).DisposeWith(disposables);
|
||||
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);
|
||||
break;
|
||||
|
||||
case EGirdOrientation.Tab:
|
||||
default:
|
||||
tabProfiles2.Content ??= new ProfilesView(this);
|
||||
tabMsgView2.Content ??= new MsgView();
|
||||
tabClashProxies2.Content ??= new ClashProxiesView();
|
||||
tabClashConnections2.Content ??= new ClashConnectionsView();
|
||||
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);
|
||||
break;
|
||||
}
|
||||
conTheme.Content ??= new ThemeSettingView();
|
||||
});
|
||||
|
||||
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);
|
||||
this.BindCommand(ViewModel, vm => vm.AddServerViaImageCmd, v => v.menuAddServerViaImage).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);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetDefaultCmd, v => v.menuRegionalPresetsDefault).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetRussiaCmd, v => v.menuRegionalPresetsRussia).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.RegionalPresetIranCmd, v => v.menuRegionalPresetsIran).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);
|
||||
|
||||
switch (_config.UiItem.MainGirdOrientation)
|
||||
{
|
||||
case EGirdOrientation.Horizontal:
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView.IsVisible).DisposeWith(disposables);
|
||||
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);
|
||||
break;
|
||||
|
||||
case EGirdOrientation.Vertical:
|
||||
this.OneWayBind(ViewModel, vm => vm.ShowClashUI, v => v.tabMsgView1.IsVisible).DisposeWith(disposables);
|
||||
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);
|
||||
break;
|
||||
|
||||
case EGirdOrientation.Tab:
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
this.Title = $"{Utils.GetVersion()}";
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppHandler.Instance.IsAdministrator)
|
||||
{
|
||||
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
||||
}
|
||||
menuRebootAsAdmin.IsVisible = false;
|
||||
menuSettingsSetUWP.IsVisible = false;
|
||||
menuGlobalHotkeySetting.IsVisible = false;
|
||||
}
|
||||
menuAddServerViaScan.IsVisible = false;
|
||||
|
||||
RestoreUI();
|
||||
AddHelpMenuItem();
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||
}
|
||||
|
||||
#region Event
|
||||
|
||||
private void OnProgramStarted(object state, bool timeout)
|
||||
this.Title = $"{Utils.GetVersion()}";
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ShowHideWindow(true),
|
||||
ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
|
||||
HotkeyHandler.Instance.Init(_config, OnHotkeyHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppHandler.Instance.IsAdministrator)
|
||||
{
|
||||
this.Title = $"{Utils.GetVersion()} - {ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp}";
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordNotSudoRunApp);
|
||||
}
|
||||
menuRebootAsAdmin.IsVisible = false;
|
||||
menuSettingsSetUWP.IsVisible = false;
|
||||
menuGlobalHotkeySetting.IsVisible = false;
|
||||
}
|
||||
menuAddServerViaScan.IsVisible = false;
|
||||
|
||||
RestoreUI();
|
||||
AddHelpMenuItem();
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||
}
|
||||
|
||||
#region Event
|
||||
|
||||
private void OnProgramStarted(object state, bool timeout)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ShowHideWindow(true),
|
||||
DispatcherPriority.Default);
|
||||
}
|
||||
|
||||
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.DispatcherReload:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.ReloadResult(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.Shutdown:
|
||||
if (obj != null && _blCloseByUser == false)
|
||||
{
|
||||
_blCloseByUser = (bool)obj;
|
||||
}
|
||||
StorageUI();
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
HotkeyHandler.Instance.Dispose();
|
||||
desktop.Shutdown();
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.ScanScreenTask:
|
||||
await ScanScreenTaskAsync();
|
||||
break;
|
||||
|
||||
case EViewAction.ScanImageTask:
|
||||
await ScanImageTaskAsync();
|
||||
break;
|
||||
|
||||
case EViewAction.AddServerViaClipboard:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
if (clipboardData.IsNotEmpty() && ViewModel != null)
|
||||
{
|
||||
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.AdjustMainLvColWidth:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.AutofitColumnWidthAsync(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
private void DelegateSnackMsg(string content)
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void OnHotkeyHandler(EGlobalHotkey e)
|
||||
{
|
||||
switch (e)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
_manager?.Show(new Notification(null, content, NotificationType.Information)),
|
||||
DispatcherPriority.Normal);
|
||||
case EGlobalHotkey.ShowForm:
|
||||
ShowHideWindow(null);
|
||||
break;
|
||||
|
||||
case EGlobalHotkey.SystemProxyClear:
|
||||
case EGlobalHotkey.SystemProxySet:
|
||||
case EGlobalHotkey.SystemProxyUnchanged:
|
||||
case EGlobalHotkey.SystemProxyPac:
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.SetListenerType((ESysProxyType)((int)e - 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnClosing(WindowClosingEventArgs e)
|
||||
{
|
||||
if (_blCloseByUser)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
Logging.SaveLog("OnClosing -> " + e.CloseReason.ToString());
|
||||
|
||||
switch (e.CloseReason)
|
||||
{
|
||||
switch (action)
|
||||
case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing:
|
||||
e.Cancel = true;
|
||||
ShowHideWindow(false);
|
||||
break;
|
||||
|
||||
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
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.DispatcherReload:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.ReloadResult(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.Shutdown:
|
||||
if (obj != null && _blCloseByUser == false)
|
||||
{
|
||||
_blCloseByUser = (bool)obj;
|
||||
}
|
||||
StorageUI();
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
HotkeyHandler.Instance.Dispose();
|
||||
desktop.Shutdown();
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.ScanScreenTask:
|
||||
await ScanScreenTaskAsync();
|
||||
break;
|
||||
|
||||
case EViewAction.ScanImageTask:
|
||||
await ScanImageTaskAsync();
|
||||
break;
|
||||
|
||||
case EViewAction.AddServerViaClipboard:
|
||||
case Key.V:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
if (clipboardData.IsNotEmpty() && ViewModel != null)
|
||||
{
|
||||
@@ -253,254 +321,185 @@ namespace v2rayN.Desktop.Views
|
||||
}
|
||||
break;
|
||||
|
||||
case EViewAction.AdjustMainLvColWidth:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
Locator.Current.GetService<ProfilesViewModel>()?.AutofitColumnWidthAsync(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void OnHotkeyHandler(EGlobalHotkey e)
|
||||
{
|
||||
switch (e)
|
||||
{
|
||||
case EGlobalHotkey.ShowForm:
|
||||
ShowHideWindow(null);
|
||||
break;
|
||||
|
||||
case EGlobalHotkey.SystemProxyClear:
|
||||
case EGlobalHotkey.SystemProxySet:
|
||||
case EGlobalHotkey.SystemProxyUnchanged:
|
||||
case EGlobalHotkey.SystemProxyPac:
|
||||
Locator.Current.GetService<StatusBarViewModel>()?.SetListenerType((ESysProxyType)((int)e - 1));
|
||||
case Key.S:
|
||||
await ScanScreenTaskAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnClosing(WindowClosingEventArgs e)
|
||||
else
|
||||
{
|
||||
if (_blCloseByUser)
|
||||
if (e.Key == Key.F5)
|
||||
{
|
||||
ViewModel?.Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
|
||||
}
|
||||
|
||||
private void menuSettingsSetUWP_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||
}
|
||||
|
||||
public async Task ScanScreenTaskAsync()
|
||||
{
|
||||
//ShowHideWindow(false);
|
||||
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue("Not yet implemented.(还未实现)");
|
||||
await Task.CompletedTask;
|
||||
//if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
//{
|
||||
// //var bytes = QRCodeHelper.CaptureScreen(desktop);
|
||||
// //await ViewModel?.ScanScreenResult(bytes);
|
||||
//}
|
||||
|
||||
//ShowHideWindow(true);
|
||||
}
|
||||
|
||||
private async Task ScanImageTaskAsync()
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(this, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.ScanImageResult(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuCheckUpdate_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_checkUpdateView ??= new CheckUpdateView();
|
||||
DialogHost.Show(_checkUpdateView);
|
||||
}
|
||||
|
||||
private void MenuBackupAndRestore_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_backupAndRestoreView ??= new BackupAndRestoreView(this);
|
||||
DialogHost.Show(_backupAndRestoreView);
|
||||
}
|
||||
|
||||
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_blCloseByUser = true;
|
||||
StorageUI();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Event
|
||||
|
||||
#region UI
|
||||
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow ?? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized));
|
||||
if (bl)
|
||||
{
|
||||
this.Show();
|
||||
if (this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
this.WindowState = WindowState.Normal;
|
||||
}
|
||||
this.Activate();
|
||||
this.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.SaveLog("OnClosing -> " + e.CloseReason.ToString());
|
||||
|
||||
switch (e.CloseReason)
|
||||
foreach (var ownedWindow in this.OwnedWindows)
|
||||
{
|
||||
case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing:
|
||||
e.Cancel = true;
|
||||
ShowHideWindow(false);
|
||||
break;
|
||||
|
||||
case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(true);
|
||||
}
|
||||
break;
|
||||
ownedWindow.Close();
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private async void MainWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.V:
|
||||
var clipboardData = await AvaUtils.GetClipboardData(this);
|
||||
if (clipboardData.IsNotEmpty() && ViewModel != null)
|
||||
{
|
||||
await ViewModel.AddServerViaClipboardAsync(clipboardData);
|
||||
}
|
||||
break;
|
||||
_config.UiItem.ShowInTaskbar = bl;
|
||||
}
|
||||
|
||||
case Key.S:
|
||||
await ScanScreenTaskAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Key == Key.F5)
|
||||
{
|
||||
ViewModel?.Reload();
|
||||
}
|
||||
}
|
||||
private void RestoreUI()
|
||||
{
|
||||
if (_config.UiItem.MainWidth > 0 && _config.UiItem.MainHeight > 0)
|
||||
{
|
||||
Width = _config.UiItem.MainWidth;
|
||||
Height = _config.UiItem.MainHeight;
|
||||
}
|
||||
|
||||
private void menuPromotion_Click(object? sender, RoutedEventArgs e)
|
||||
if (_config.UiItem.MainGirdHeight1 > 0 && _config.UiItem.MainGirdHeight2 > 0)
|
||||
{
|
||||
ProcUtils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}");
|
||||
}
|
||||
|
||||
private void menuSettingsSetUWP_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
|
||||
}
|
||||
|
||||
public async Task ScanScreenTaskAsync()
|
||||
{
|
||||
//ShowHideWindow(false);
|
||||
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue("Not yet implemented.(还未实现)");
|
||||
await Task.CompletedTask;
|
||||
//if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
//{
|
||||
// //var bytes = QRCodeHelper.CaptureScreen(desktop);
|
||||
// //await ViewModel?.ScanScreenResult(bytes);
|
||||
//}
|
||||
|
||||
//ShowHideWindow(true);
|
||||
}
|
||||
|
||||
private async Task ScanImageTaskAsync()
|
||||
{
|
||||
var fileName = await UI.OpenFileDialog(this, null);
|
||||
if (fileName.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.ScanImageResult(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuCheckUpdate_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_checkUpdateView ??= new CheckUpdateView();
|
||||
DialogHost.Show(_checkUpdateView);
|
||||
}
|
||||
|
||||
private void MenuBackupAndRestore_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_backupAndRestoreView ??= new BackupAndRestoreView(this);
|
||||
DialogHost.Show(_backupAndRestoreView);
|
||||
}
|
||||
|
||||
private async void MenuClose_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (await UI.ShowYesNo(this, ResUI.menuExitTips) == ButtonResult.No)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_blCloseByUser = true;
|
||||
StorageUI();
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.MyAppExitAsync(false);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Event
|
||||
|
||||
#region UI
|
||||
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow ?? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized));
|
||||
if (bl)
|
||||
{
|
||||
this.Show();
|
||||
if (this.WindowState == WindowState.Minimized)
|
||||
{
|
||||
this.WindowState = WindowState.Normal;
|
||||
}
|
||||
this.Activate();
|
||||
this.Focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Utils.IsLinux() && _config.UiItem.Hide2TrayWhenClose == false)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var ownedWindow in this.OwnedWindows)
|
||||
{
|
||||
ownedWindow.Close();
|
||||
}
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
_config.UiItem.ShowInTaskbar = bl;
|
||||
}
|
||||
|
||||
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(string? n = null)
|
||||
{
|
||||
_config.UiItem.MainWidth = this.Width;
|
||||
_config.UiItem.MainHeight = 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);
|
||||
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)
|
||||
{
|
||||
_config.UiItem.MainGirdHeight1 = Math.Ceiling(gridMain1.RowDefinitions[0].ActualHeight + 0.1);
|
||||
_config.UiItem.MainGirdHeight2 = Math.Ceiling(gridMain1.RowDefinitions[2].ActualHeight + 0.1);
|
||||
gridMain1.RowDefinitions[0].Height = new GridLength(_config.UiItem.MainGirdHeight1, GridUnitType.Star);
|
||||
gridMain1.RowDefinitions[2].Height = new GridLength(_config.UiItem.MainGirdHeight2, GridUnitType.Star);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddHelpMenuItem()
|
||||
{
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||
foreach (var it in coreInfo
|
||||
.Where(t => t.CoreType != ECoreType.v2fly
|
||||
&& t.CoreType != ECoreType.hysteria))
|
||||
{
|
||||
var item = new MenuItem()
|
||||
{
|
||||
Tag = it.Url?.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)
|
||||
{
|
||||
ProcUtils.ProcessStart(item.Tag?.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion UI
|
||||
}
|
||||
|
||||
private void StorageUI(string? n = null)
|
||||
{
|
||||
_config.UiItem.MainWidth = this.Width;
|
||||
_config.UiItem.MainHeight = 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);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddHelpMenuItem()
|
||||
{
|
||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||
foreach (var it in coreInfo
|
||||
.Where(t => t.CoreType != ECoreType.v2fly
|
||||
&& t.CoreType != ECoreType.hysteria))
|
||||
{
|
||||
var item = new MenuItem()
|
||||
{
|
||||
Tag = it.Url?.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)
|
||||
{
|
||||
ProcUtils.ProcessStart(item.Tag?.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion UI
|
||||
}
|
||||
|
||||
@@ -5,75 +5,74 @@ using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||
{
|
||||
public partial class MsgView : ReactiveUserControl<MsgViewModel>
|
||||
public MsgView()
|
||||
{
|
||||
public MsgView()
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel = new MsgViewModel(UpdateViewHandler);
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
ViewModel = new MsgViewModel(UpdateViewHandler);
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherShowMsg:
|
||||
if (obj is null)
|
||||
return false;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
|
||||
});
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ShowMsg(obj),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
private void ShowMsg(object msg)
|
||||
{
|
||||
txtMsg.Text = msg.ToString();
|
||||
if (togScrollToEnd.IsChecked ?? true)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherShowMsg:
|
||||
if (obj is null)
|
||||
return false;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ShowMsg(obj),
|
||||
DispatcherPriority.ApplicationIdle);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void ShowMsg(object msg)
|
||||
{
|
||||
txtMsg.Text = msg.ToString();
|
||||
if (togScrollToEnd.IsChecked ?? true)
|
||||
{
|
||||
txtMsg.CaretIndex = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearMsg()
|
||||
{
|
||||
ViewModel?.ClearMsg();
|
||||
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();
|
||||
txtMsg.CaretIndex = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearMsg()
|
||||
{
|
||||
ViewModel?.ClearMsg();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,255 +3,254 @@ using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
||||
{
|
||||
public partial class OptionSettingWindow : ReactiveWindow<OptionSettingViewModel>
|
||||
private static Config _config;
|
||||
|
||||
public OptionSettingWindow()
|
||||
{
|
||||
private static Config _config;
|
||||
InitializeComponent();
|
||||
|
||||
public OptionSettingWindow()
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = AppHandler.Instance.Config;
|
||||
|
||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||
|
||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||
Global.destOverrideProtocols.ForEach(it =>
|
||||
{
|
||||
InitializeComponent();
|
||||
clbdestOverride.Items.Add(it);
|
||||
});
|
||||
_config.Inbound.First().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);
|
||||
});
|
||||
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
_config = AppHandler.Instance.Config;
|
||||
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);
|
||||
});
|
||||
|
||||
ViewModel = new OptionSettingViewModel(UpdateViewHandler);
|
||||
for (var i = 2; i <= 8; i++)
|
||||
{
|
||||
cmbMixedConcurrencyCount.Items.Add(i);
|
||||
}
|
||||
for (var i = 2; i <= 6; i++)
|
||||
{
|
||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||
}
|
||||
|
||||
clbdestOverride.SelectionChanged += ClbdestOverride_SelectionChanged;
|
||||
Global.destOverrideProtocols.ForEach(it =>
|
||||
{
|
||||
clbdestOverride.Items.Add(it);
|
||||
});
|
||||
_config.Inbound.First().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);
|
||||
});
|
||||
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||
|
||||
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);
|
||||
});
|
||||
Global.GeoFilesSources.ForEach(it =>
|
||||
{
|
||||
cmbGetFilesSourceUrl.Items.Add(it);
|
||||
});
|
||||
Global.SingboxRulesetSources.ForEach(it =>
|
||||
{
|
||||
cmbSrsFilesSourceUrl.Items.Add(it);
|
||||
});
|
||||
Global.RoutingRulesSources.ForEach(it =>
|
||||
{
|
||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
||||
});
|
||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||
{
|
||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||
}
|
||||
|
||||
for (var i = 2; i <= 8; i++)
|
||||
{
|
||||
cmbMixedConcurrencyCount.Items.Add(i);
|
||||
}
|
||||
for (var i = 2; i <= 6; i++)
|
||||
{
|
||||
cmbSpeedTestTimeout.Items.Add(i * 5);
|
||||
}
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SecondLocalPortEnabled, v => v.togSecondLocalPortEnabled.IsChecked).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);
|
||||
|
||||
cmbSpeedTestUrl.ItemsSource = Global.SpeedTestUrls;
|
||||
cmbSpeedPingTestUrl.ItemsSource = Global.SpeedPingTestUrls;
|
||||
cmbSubConvertUrl.ItemsSource = Global.SubConvertUrls;
|
||||
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.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.KeepOlderDedupl, v => v.togKeepOlderDedupl.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.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MixedConcurrencyCount, v => v.cmbMixedConcurrencyCount.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
|
||||
Global.GeoFilesSources.ForEach(it =>
|
||||
{
|
||||
cmbGetFilesSourceUrl.Items.Add(it);
|
||||
});
|
||||
Global.SingboxRulesetSources.ForEach(it =>
|
||||
{
|
||||
cmbSrsFilesSourceUrl.Items.Add(it);
|
||||
});
|
||||
Global.RoutingRulesSources.ForEach(it =>
|
||||
{
|
||||
cmbRoutingRulesSourceUrl.Items.Add(it);
|
||||
});
|
||||
foreach (EGirdOrientation it in Enum.GetValues(typeof(EGirdOrientation)))
|
||||
{
|
||||
cmbMainGirdOrientation.Items.Add(it.ToString());
|
||||
}
|
||||
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.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, vm => vm.localPort, v => v.txtlocalPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SecondLocalPortEnabled, v => v.togSecondLocalPortEnabled.IsChecked).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.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.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).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.DisplayRealTimeSpeed, v => v.togDisplayRealTimeSpeed.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.KeepOlderDedupl, v => v.togKeepOlderDedupl.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.Hide2TrayWhenClose, v => v.togHide2TrayWhenClose.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.DoubleClick2Activate, v => v.togDoubleClick2Activate.IsChecked).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.AutoUpdateInterval, v => v.txtautoUpdateInterval.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CurrentFontFamily, v => v.cmbcurrentFontFamily.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestTimeout, v => v.cmbSpeedTestTimeout.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedTestUrl, v => v.cmbSpeedTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SpeedPingTestUrl, v => v.cmbSpeedPingTestUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MixedConcurrencyCount, v => v.cmbMixedConcurrencyCount.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SubConvertUrl, v => v.cmbSubConvertUrl.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.MainGirdOrientation, v => v.cmbMainGirdOrientation.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.GeoFileSourceUrl, v => v.cmbGetFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SrsFileSourceUrl, v => v.cmbSrsFilesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.RoutingRulesSourceUrl, v => v.cmbRoutingRulesSourceUrl.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType1, v => v.cmbCoreType1.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.CoreType2, v => v.cmbCoreType2.SelectedValue).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.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.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.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).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.TunLinuxSudoPassword, v => v.txtLinuxSudoPassword.Text).DisposeWith(disposables);
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
txbSettingsExceptionTip2.IsVisible = false;
|
||||
|
||||
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);
|
||||
txtLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPasswordTip.IsVisible = false;
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
}
|
||||
else if (Utils.IsLinux())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
}
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
|
||||
case EViewAction.InitSettingFont:
|
||||
await InitSettingFont();
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task InitSettingFont()
|
||||
{
|
||||
var lstFonts = await GetFonts();
|
||||
|
||||
lstFonts.Add(string.Empty);
|
||||
cmbcurrentFontFamily.ItemsSource = lstFonts;
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetFonts()
|
||||
{
|
||||
var lstFonts = new List<string>();
|
||||
try
|
||||
{
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
txbSettingsExceptionTip2.IsVisible = false;
|
||||
|
||||
txtLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPassword.IsVisible = false;
|
||||
labLinuxSudoPasswordTip.IsVisible = false;
|
||||
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
return lstFonts;
|
||||
}
|
||||
else if (Utils.IsLinux())
|
||||
else if (Utils.IsNonWindows())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
}
|
||||
else if (Utils.IsOSX())
|
||||
{
|
||||
txbSettingsExceptionTip.IsVisible = false;
|
||||
panSystemProxyAdvanced.IsVisible = false;
|
||||
|
||||
labHide2TrayWhenClose.IsVisible = false;
|
||||
togHide2TrayWhenClose.IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
|
||||
case EViewAction.InitSettingFont:
|
||||
await InitSettingFont();
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private async Task InitSettingFont()
|
||||
{
|
||||
var lstFonts = await GetFonts();
|
||||
|
||||
lstFonts.Add(string.Empty);
|
||||
cmbcurrentFontFamily.ItemsSource = lstFonts;
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetFonts()
|
||||
{
|
||||
var lstFonts = new List<string>();
|
||||
try
|
||||
{
|
||||
if (Utils.IsWindows())
|
||||
var result = await Utils.GetLinuxFontFamily("zh");
|
||||
if (result.IsNullOrEmpty())
|
||||
{
|
||||
return lstFonts;
|
||||
}
|
||||
else if (Utils.IsNonWindows())
|
||||
{
|
||||
var result = await Utils.GetLinuxFontFamily("zh");
|
||||
if (result.IsNullOrEmpty())
|
||||
{
|
||||
return lstFonts;
|
||||
}
|
||||
|
||||
var lst = result.Split(Environment.NewLine)
|
||||
.Where(t => t.IsNotEmpty())
|
||||
.ToList()
|
||||
.Select(t => t.Split(",").FirstOrDefault() ?? "")
|
||||
.OrderBy(t => t)
|
||||
.ToList();
|
||||
return lst;
|
||||
}
|
||||
var lst = result.Split(Environment.NewLine)
|
||||
.Where(t => t.IsNotEmpty())
|
||||
.ToList()
|
||||
.Select(t => t.Split(",").FirstOrDefault() ?? "")
|
||||
.OrderBy(t => t)
|
||||
.ToList();
|
||||
return lst;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logging.SaveLog("GetFonts", ex);
|
||||
}
|
||||
return lstFonts;
|
||||
}
|
||||
|
||||
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
Logging.SaveLog("GetFonts", ex);
|
||||
}
|
||||
return lstFonts;
|
||||
}
|
||||
|
||||
private void ClbdestOverride_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.destOverride = clbdestOverride.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,502 +10,501 @@ using ReactiveUI;
|
||||
using Splat;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
{
|
||||
public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
|
||||
private static Config _config;
|
||||
private Window? _window;
|
||||
|
||||
public ProfilesView()
|
||||
{
|
||||
private static Config _config;
|
||||
private Window? _window;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public ProfilesView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
public ProfilesView(Window window)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
public ProfilesView(Window window)
|
||||
{
|
||||
InitializeComponent();
|
||||
_config = AppHandler.Instance.Config;
|
||||
_window = window;
|
||||
|
||||
_config = AppHandler.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;
|
||||
lstProfiles.Sorting += LstProfiles_Sorting;
|
||||
//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.SetDefaultMultipleServerXrayRandomCmd, v => v.menuSetDefaultMultipleServerXrayRandom).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayRoundRobinCmd, v => v.menuSetDefaultMultipleServerXrayRoundRobin).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayLeastPingCmd, v => v.menuSetDefaultMultipleServerXrayLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayLeastLoadCmd, v => v.menuSetDefaultMultipleServerXrayLeastLoad).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerSingBoxLeastPingCmd, v => v.menuSetDefaultMultipleServerSingBoxLeastPing).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);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||
|
||||
//servers export
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
||||
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();
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||
}
|
||||
|
||||
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
if (ViewModel != null && e.Column?.Tag?.ToString() != null)
|
||||
{
|
||||
await ViewModel.SortServer(e.Column.Tag.ToString());
|
||||
}
|
||||
|
||||
e.Handled = false;
|
||||
}
|
||||
|
||||
#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(() =>
|
||||
{
|
||||
_ = RefreshServersBiz();
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
public async Task ShareServer(string url)
|
||||
{
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dialog = new QrcodeView(url);
|
||||
await DialogHost.Show(dialog);
|
||||
}
|
||||
|
||||
public async Task RefreshServersBiz()
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.RefreshServersBiz();
|
||||
}
|
||||
|
||||
if (lstProfiles.SelectedIndex > 0)
|
||||
{
|
||||
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
var source = e.Source as Border;
|
||||
if (source?.Name == "HeaderBackground")
|
||||
return;
|
||||
if (_config.UiItem.DoubleClick2Activate)
|
||||
{
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||
{
|
||||
e.Row.Header = $" {e.Row.Index + 1}";
|
||||
}
|
||||
|
||||
//private void LstProfiles_ColumnHeader_Click(object? sender, RoutedEventArgs e)
|
||||
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;
|
||||
lstProfiles.Sorting += LstProfiles_Sorting;
|
||||
//if (_config.uiItem.enableDragDropSort)
|
||||
//{
|
||||
// var colHeader = sender as DataGridColumnHeader;
|
||||
// if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var colName = ((MyDGTextColumn)colHeader.Column).ExName;
|
||||
// ViewModel?.SortServer(colName);
|
||||
// lstProfiles.AllowDrop = true;
|
||||
// lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown;
|
||||
// lstProfiles.MouseMove += LstProfiles_MouseMove;
|
||||
// lstProfiles.DragEnter += LstProfiles_DragEnter;
|
||||
// lstProfiles.Drop += LstProfiles_Drop;
|
||||
//}
|
||||
|
||||
private void menuSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
ViewModel = new ProfilesViewModel(UpdateViewHandler);
|
||||
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ProfilesViewModel));
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
lstProfiles.SelectAll();
|
||||
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.SetDefaultMultipleServerXrayRandomCmd, v => v.menuSetDefaultMultipleServerXrayRandom).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayRoundRobinCmd, v => v.menuSetDefaultMultipleServerXrayRoundRobin).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayLeastPingCmd, v => v.menuSetDefaultMultipleServerXrayLeastPing).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerXrayLeastLoadCmd, v => v.menuSetDefaultMultipleServerXrayLeastLoad).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.SetDefaultMultipleServerSingBoxLeastPingCmd, v => v.menuSetDefaultMultipleServerSingBoxLeastPing).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);
|
||||
this.BindCommand(ViewModel, vm => vm.RemoveInvalidServerResultCmd, v => v.menuRemoveInvalidServerResult).DisposeWith(disposables);
|
||||
|
||||
//servers export
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, vm => vm.Export2ClientConfigClipboardCmd, v => v.menuExport2ClientConfigClipboard).DisposeWith(disposables);
|
||||
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();
|
||||
MessageBus.Current.Listen<string>(EMsgCommand.AppExit.ToString()).Subscribe(StorageUI);
|
||||
}
|
||||
|
||||
private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
if (ViewModel != null && e.Column?.Tag?.ToString() != null)
|
||||
{
|
||||
await ViewModel.SortServer(e.Column.Tag.ToString());
|
||||
}
|
||||
|
||||
private void LstProfiles_KeyDown(object? sender, KeyEventArgs e)
|
||||
e.Handled = false;
|
||||
}
|
||||
|
||||
#region Event
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
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(() =>
|
||||
{
|
||||
_ = RefreshServersBiz();
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
}
|
||||
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
public async Task ShareServer(string url)
|
||||
{
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dialog = new QrcodeView(url);
|
||||
await DialogHost.Show(dialog);
|
||||
}
|
||||
|
||||
public async Task RefreshServersBiz()
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
await ViewModel.RefreshServersBiz();
|
||||
}
|
||||
|
||||
if (lstProfiles.SelectedIndex > 0)
|
||||
{
|
||||
lstProfiles.ScrollIntoView(lstProfiles.SelectedItem, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void lstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
var source = e.Source as Border;
|
||||
if (source?.Name == "HeaderBackground")
|
||||
return;
|
||||
if (_config.UiItem.DoubleClick2Activate)
|
||||
{
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
}
|
||||
}
|
||||
|
||||
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
|
||||
{
|
||||
e.Row.Header = $" {e.Row.Index + 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 is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.A:
|
||||
menuSelectAll_Click(null, null);
|
||||
break;
|
||||
case Key.A:
|
||||
menuSelectAll_Click(null, null);
|
||||
break;
|
||||
|
||||
case Key.C:
|
||||
ViewModel?.Export2ShareUrlAsync(false);
|
||||
break;
|
||||
case Key.C:
|
||||
ViewModel?.Export2ShareUrlAsync(false);
|
||||
break;
|
||||
|
||||
case Key.D:
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
break;
|
||||
case Key.D:
|
||||
ViewModel?.EditServerAsync(EConfigType.Custom);
|
||||
break;
|
||||
|
||||
case Key.F:
|
||||
ViewModel?.ShareServerAsync();
|
||||
break;
|
||||
case Key.F:
|
||||
ViewModel?.ShareServerAsync();
|
||||
break;
|
||||
|
||||
case Key.O:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping);
|
||||
break;
|
||||
case Key.O:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping);
|
||||
break;
|
||||
|
||||
case Key.R:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Realping);
|
||||
break;
|
||||
case Key.R:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Realping);
|
||||
break;
|
||||
|
||||
case Key.T:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest);
|
||||
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();
|
||||
}
|
||||
case Key.E:
|
||||
ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
else
|
||||
{
|
||||
if (e.Key is Key.Enter or Key.Return)
|
||||
{
|
||||
ViewModel?.RefreshServers();
|
||||
ViewModel?.SetDefaultServer();
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
foreach (var item2 in lstProfiles.Columns)
|
||||
{
|
||||
if (item2.Tag == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (item2.Tag.Equals(item.Name))
|
||||
{
|
||||
if (item.Width < 0)
|
||||
{
|
||||
item2.IsVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel);
|
||||
item2.DisplayIndex = displayIndex++;
|
||||
}
|
||||
if (item.Name.ToLower().StartsWith("to"))
|
||||
{
|
||||
item2.IsVisible = _config.GuiItem.EnableStatistics;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 StorageUI(string? n = null)
|
||||
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)
|
||||
{
|
||||
List<ColumnItem> lvColumnItem = new();
|
||||
foreach (var item2 in lstProfiles.Columns)
|
||||
{
|
||||
if (item2.Tag == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
lvColumnItem.Add(new()
|
||||
if (item2.Tag.Equals(item.Name))
|
||||
{
|
||||
Name = (string)item2.Tag,
|
||||
Width = (int)(item2.IsVisible == true ? item2.ActualWidth : -1),
|
||||
Index = item2.DisplayIndex
|
||||
});
|
||||
if (item.Width < 0)
|
||||
{
|
||||
item2.IsVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel);
|
||||
item2.DisplayIndex = displayIndex++;
|
||||
}
|
||||
if (item.Name.ToLower().StartsWith("to"))
|
||||
{
|
||||
item2.IsVisible = _config.GuiItem.EnableStatistics;
|
||||
}
|
||||
}
|
||||
}
|
||||
_config.UiItem.MainColumnItem = lvColumnItem;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
private void StorageUI(string? n = null)
|
||||
{
|
||||
List<ColumnItem> lvColumnItem = new();
|
||||
foreach (var item2 in lstProfiles.Columns)
|
||||
{
|
||||
if (item2.Tag == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
lvColumnItem.Add(new()
|
||||
{
|
||||
Name = (string)item2.Tag,
|
||||
Width = (int)(item2.IsVisible == true ? item2.ActualWidth : -1),
|
||||
Index = item2.DisplayIndex
|
||||
});
|
||||
}
|
||||
_config.UiItem.MainColumnItem = lvColumnItem;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
@@ -2,40 +2,39 @@ using Avalonia.Controls;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class QrcodeView : UserControl
|
||||
{
|
||||
public partial class QrcodeView : UserControl
|
||||
public QrcodeView()
|
||||
{
|
||||
public QrcodeView()
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public QrcodeView(string? url)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
txtContent.Text = url;
|
||||
imgQrcode.Source = GetQRCode(url);
|
||||
|
||||
txtContent.GotFocus += (_, _) => Dispatcher.UIThread.Post(() => { txtContent.SelectAll(); });
|
||||
}
|
||||
|
||||
private Bitmap? GetQRCode(string? url)
|
||||
{
|
||||
var bytes = QRCodeHelper.GenQRCode(url);
|
||||
return ByteToBitmap(bytes);
|
||||
}
|
||||
|
||||
private Bitmap? ByteToBitmap(byte[]? bytes)
|
||||
{
|
||||
if (bytes is null)
|
||||
{
|
||||
InitializeComponent();
|
||||
return null;
|
||||
}
|
||||
|
||||
public QrcodeView(string? url)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
txtContent.Text = url;
|
||||
imgQrcode.Source = GetQRCode(url);
|
||||
|
||||
txtContent.GotFocus += (_, _) => Dispatcher.UIThread.Post(() => { txtContent.SelectAll(); });
|
||||
}
|
||||
|
||||
private Bitmap? GetQRCode(string? url)
|
||||
{
|
||||
var bytes = QRCodeHelper.GenQRCode(url);
|
||||
return ByteToBitmap(bytes);
|
||||
}
|
||||
|
||||
private Bitmap? ByteToBitmap(byte[]? bytes)
|
||||
{
|
||||
if (bytes is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var ms = new MemoryStream(bytes);
|
||||
return new Bitmap(ms);
|
||||
}
|
||||
using var ms = new MemoryStream(bytes);
|
||||
return new Bitmap(ms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,104 +4,103 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
||||
{
|
||||
public partial class RoutingRuleDetailsWindow : ReactiveWindow<RoutingRuleDetailsViewModel>
|
||||
public RoutingRuleDetailsWindow()
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public RoutingRuleDetailsWindow(RulesItem rulesItem)
|
||||
clbProtocol.Items.Add(it);
|
||||
});
|
||||
Global.InboundTags.ForEach(it =>
|
||||
{
|
||||
InitializeComponent();
|
||||
clbInboundTag.Items.Add(it);
|
||||
});
|
||||
Global.RuleNetworks.ForEach(it =>
|
||||
{
|
||||
cmbNetwork.Items.Add(it);
|
||||
});
|
||||
|
||||
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 =>
|
||||
if (!rulesItem.Id.IsNullOrEmpty())
|
||||
{
|
||||
rulesItem.Protocol?.ForEach(it =>
|
||||
{
|
||||
clbProtocol.Items.Add(it);
|
||||
clbProtocol?.SelectedItems?.Add(it);
|
||||
});
|
||||
Global.InboundTags.ForEach(it =>
|
||||
rulesItem.InboundTag?.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.Remarks, v => v.txtRemarks.Text).DisposeWith(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);
|
||||
clbInboundTag?.SelectedItems?.Add(it);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(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);
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
cmbOutboundTag.Focus();
|
||||
}
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
cmbOutboundTag.Focus();
|
||||
}
|
||||
|
||||
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/routing.html#ruleobject");
|
||||
ViewModel.ProtocolItems = clbProtocol.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClbInboundTag_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.InboundTagItems = clbInboundTag.SelectedItems.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void linkRuleobjectDoc_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/routing.html#ruleobject");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,214 +7,213 @@ using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
||||
{
|
||||
public partial class RoutingRuleSettingWindow : ReactiveWindow<RoutingRuleSettingViewModel>
|
||||
public RoutingRuleSettingWindow()
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
InitializeComponent();
|
||||
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);
|
||||
if (clipboardData.IsNotEmpty())
|
||||
{
|
||||
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
public RoutingRuleSettingWindow(RoutingItem routingItem)
|
||||
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 is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
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 =>
|
||||
if (e.Key == Key.A)
|
||||
{
|
||||
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);
|
||||
if (clipboardData.IsNotEmpty())
|
||||
{
|
||||
ViewModel?.ImportRulesFromClipboardAsync(clipboardData);
|
||||
}
|
||||
|
||||
break;
|
||||
lstRules.SelectAll();
|
||||
}
|
||||
|
||||
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 is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
else if (e.Key == Key.C)
|
||||
{
|
||||
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();
|
||||
}
|
||||
ViewModel?.RuleExportSelectedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
else
|
||||
{
|
||||
if (ViewModel != null)
|
||||
if (e.Key == Key.T)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
ViewModel?.MoveRule(EMove.Top);
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
else if (e.Key == Key.U)
|
||||
{
|
||||
return;
|
||||
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();
|
||||
}
|
||||
|
||||
txtCustomRulesetPath4Singbox.Text = fileName;
|
||||
}
|
||||
|
||||
private void linkCustomRulesetPath4Singbox(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://github.com/2dust/v2rayCustomRoutingList/blob/master/singbox_custom_ruleset_example.json");
|
||||
}
|
||||
}
|
||||
|
||||
private void lstRules_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRules.SelectedItems.Cast<RulesItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://github.com/2dust/v2rayCustomRoutingList/blob/master/singbox_custom_ruleset_example.json");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,142 +7,141 @@ using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
||||
{
|
||||
public partial class RoutingSettingWindow : ReactiveWindow<RoutingSettingViewModel>
|
||||
private bool _manualClose = false;
|
||||
|
||||
public RoutingSettingWindow()
|
||||
{
|
||||
private bool _manualClose = false;
|
||||
InitializeComponent();
|
||||
|
||||
public RoutingSettingWindow()
|
||||
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 =>
|
||||
{
|
||||
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)
|
||||
cmbdomainStrategy.Items.Add(it);
|
||||
});
|
||||
Global.DomainMatchers.ForEach(it =>
|
||||
{
|
||||
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)
|
||||
cmbdomainMatcher.Items.Add(it);
|
||||
});
|
||||
Global.DomainStrategies4Singbox.ForEach(it =>
|
||||
{
|
||||
if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
if (e.Key == Key.A)
|
||||
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)
|
||||
{
|
||||
lstRoutings.SelectAll();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (e.Key is Key.Enter or Key.Return)
|
||||
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 (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
|
||||
{
|
||||
if (e.Key == Key.A)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedSetDefault();
|
||||
}
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedRemoveAsync();
|
||||
lstRoutings.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void menuRoutingAdvancedSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
else if (e.Key is Key.Enter or Key.Return)
|
||||
{
|
||||
lstRoutings.SelectAll();
|
||||
ViewModel?.RoutingAdvancedSetDefault();
|
||||
}
|
||||
|
||||
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
else if (e.Key == Key.Delete)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
ViewModel?.RoutingAdvancedRemoveAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private void menuRoutingAdvancedSelectAll_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
lstRoutings.SelectAll();
|
||||
}
|
||||
|
||||
private void lstRoutings_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedEditAsync(false);
|
||||
}
|
||||
|
||||
private void linkdomainStrategy_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/routing.html");
|
||||
}
|
||||
|
||||
private void linkdomainStrategy4Singbox_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.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)
|
||||
{
|
||||
ViewModel.SelectedSources = lstRoutings.SelectedItems.Cast<RoutingItemModel>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private void LstRoutings_DoubleTapped(object? sender, TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.RoutingAdvancedEditAsync(false);
|
||||
}
|
||||
|
||||
private void linkdomainStrategy_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.ProcessStart("https://xtls.github.io/config/routing.html");
|
||||
}
|
||||
|
||||
private void linkdomainStrategy4Singbox_Click(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
ProcUtils.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);
|
||||
}
|
||||
btnCancel_Click(null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,97 +8,96 @@ using ReactiveUI;
|
||||
using Splat;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||
{
|
||||
public partial class StatusBarView : ReactiveUserControl<StatusBarViewModel>
|
||||
private static Config _config;
|
||||
|
||||
public StatusBarView()
|
||||
{
|
||||
private static Config _config;
|
||||
InitializeComponent();
|
||||
|
||||
public StatusBarView()
|
||||
_config = AppHandler.Instance.Config;
|
||||
//ViewModel = new StatusBarViewModel(UpdateViewHandler);
|
||||
//Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel));
|
||||
ViewModel = Locator.Current.GetService<StatusBarViewModel>();
|
||||
ViewModel?.InitUpdateView(UpdateViewHandler);
|
||||
|
||||
txtRunningServerDisplay.Tapped += TxtRunningServerDisplay_Tapped;
|
||||
txtRunningInfoDisplay.Tapped += TxtRunningServerDisplay_Tapped;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
//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);
|
||||
|
||||
_config = AppHandler.Instance.Config;
|
||||
//ViewModel = new StatusBarViewModel(UpdateViewHandler);
|
||||
//Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel));
|
||||
ViewModel = Locator.Current.GetService<StatusBarViewModel>();
|
||||
ViewModel?.InitUpdateView(UpdateViewHandler);
|
||||
this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
txtRunningServerDisplay.Tapped += TxtRunningServerDisplay_Tapped;
|
||||
txtRunningInfoDisplay.Tapped += TxtRunningServerDisplay_Tapped;
|
||||
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
|
||||
|
||||
this.WhenActivated(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.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables);
|
||||
});
|
||||
|
||||
//spEnableTun.IsVisible = (Utils.IsWindows() || AppHandler.Instance.IsAdministrator);
|
||||
|
||||
if (Utils.IsNonWindows() && cmbSystemProxy.Items.IsReadOnly == false)
|
||||
{
|
||||
cmbSystemProxy.Items.RemoveAt(cmbSystemProxy.Items.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
if (Utils.IsNonWindows() && cmbSystemProxy.Items.IsReadOnly == false)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherServerAvailability:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.TestServerAvailabilityResult((string)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshServersBiz(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshIcon:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
RefreshIcon();
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.SetClipboardData:
|
||||
if (obj is null)
|
||||
return false;
|
||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void RefreshIcon()
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.SystemProxyItem.SysProxyType);
|
||||
var iconslist = TrayIcon.GetIcons(Application.Current);
|
||||
iconslist[0].Icon = desktop.MainWindow.Icon;
|
||||
TrayIcon.SetIcons(Application.Current, iconslist);
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.TestServerAvailability();
|
||||
cmbSystemProxy.Items.RemoveAt(cmbSystemProxy.Items.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.DispatcherServerAvailability:
|
||||
if (obj is null)
|
||||
return false;
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.TestServerAvailabilityResult((string)obj),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshServersBiz:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
ViewModel?.RefreshServersBiz(),
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.DispatcherRefreshIcon:
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
RefreshIcon();
|
||||
},
|
||||
DispatcherPriority.Default);
|
||||
break;
|
||||
|
||||
case EViewAction.SetClipboardData:
|
||||
if (obj is null)
|
||||
return false;
|
||||
await AvaUtils.SetClipboardData(this, (string)obj);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void RefreshIcon()
|
||||
{
|
||||
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.SystemProxyItem.SysProxyType);
|
||||
var iconslist = TrayIcon.GetIcons(Application.Current);
|
||||
iconslist[0].Icon = desktop.MainWindow.Icon;
|
||||
TrayIcon.SetIcons(Application.Current, iconslist);
|
||||
}
|
||||
}
|
||||
|
||||
private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.TestServerAvailability();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,63 +4,62 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||
{
|
||||
public partial class SubEditWindow : ReactiveWindow<SubEditViewModel>
|
||||
public SubEditWindow()
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
cmbConvertTarget.Items.Add(it);
|
||||
});
|
||||
|
||||
public SubEditWindow(SubItem subItem)
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
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.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Memo, v => v.txtMemo.Text).DisposeWith(disposables);
|
||||
|
||||
Loaded += Window_Loaded;
|
||||
btnCancel.Click += (s, e) => this.Close();
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
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.Bind(ViewModel, vm => vm.SelectedSource.PreSocksPort, v => v.txtPreSocksPort.Text).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource.Memo, v => v.txtMemo.Text).DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close(true);
|
||||
break;
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
private void Window_Loaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
txtRemarks.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,102 +8,101 @@ using MsBox.Avalonia.Enums;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.Common;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
||||
{
|
||||
public partial class SubSettingWindow : ReactiveWindow<SubSettingViewModel>
|
||||
private bool _manualClose = false;
|
||||
|
||||
public SubSettingWindow()
|
||||
{
|
||||
private bool _manualClose = false;
|
||||
InitializeComponent();
|
||||
|
||||
public SubSettingWindow()
|
||||
menuClose.Click += menuClose_Click;
|
||||
this.Closing += SubSettingWindow_Closing;
|
||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstSubscription.ItemsSource).DisposeWith(disposables);
|
||||
this.Bind(ViewModel, vm => vm.SelectedSource, v => v.lstSubscription.SelectedItem).DisposeWith(disposables);
|
||||
|
||||
menuClose.Click += menuClose_Click;
|
||||
this.Closing += SubSettingWindow_Closing;
|
||||
ViewModel = new SubSettingViewModel(UpdateViewHandler);
|
||||
lstSubscription.DoubleTapped += LstSubscription_DoubleTapped;
|
||||
lstSubscription.SelectionChanged += LstSubscription_SelectionChanged;
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case EViewAction.CloseWindow:
|
||||
this.Close();
|
||||
break;
|
||||
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 (url.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var dialog = new QrcodeView(url);
|
||||
await DialogHost.Show(dialog, "dialogHostSub");
|
||||
}
|
||||
|
||||
private void LstSubscription_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.EditSubAsync(false);
|
||||
}
|
||||
|
||||
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
case EViewAction.ShowYesNo:
|
||||
if (await UI.ShowYesNo(this, ResUI.RemoveServer) == ButtonResult.No)
|
||||
{
|
||||
menuClose_Click(null, null);
|
||||
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 (url.IsNullOrEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
var dialog = new QrcodeView(url);
|
||||
await DialogHost.Show(dialog, "dialogHostSub");
|
||||
}
|
||||
|
||||
private void LstSubscription_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
|
||||
{
|
||||
ViewModel?.EditSubAsync(false);
|
||||
}
|
||||
|
||||
private void LstSubscription_SelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
ViewModel.SelectedSources = lstSubscription.SelectedItems.Cast<SubItem>().ToList();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,39 +4,38 @@ using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using v2rayN.Desktop.ViewModels;
|
||||
|
||||
namespace v2rayN.Desktop.Views
|
||||
namespace v2rayN.Desktop.Views;
|
||||
|
||||
/// <summary>
|
||||
/// ThemeSettingView.xaml
|
||||
/// </summary>
|
||||
public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewModel>
|
||||
{
|
||||
/// <summary>
|
||||
/// ThemeSettingView.xaml
|
||||
/// </summary>
|
||||
public partial class ThemeSettingView : ReactiveUserControl<ThemeSettingViewModel>
|
||||
public ThemeSettingView()
|
||||
{
|
||||
public ThemeSettingView()
|
||||
InitializeComponent();
|
||||
ViewModel = new ThemeSettingViewModel();
|
||||
|
||||
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = new ThemeSettingViewModel();
|
||||
|
||||
foreach (ETheme it in Enum.GetValues(typeof(ETheme)))
|
||||
{
|
||||
cmbCurrentTheme.Items.Add(it.ToString());
|
||||
}
|
||||
|
||||
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.CurrentTheme, v => v.cmbCurrentTheme.SelectedValue).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);
|
||||
});
|
||||
cmbCurrentTheme.Items.Add(it.ToString());
|
||||
}
|
||||
|
||||
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.CurrentTheme, v => v.cmbCurrentTheme.SelectedValue).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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user