diff --git a/v2rayN/v2rayN/Base/MyDGTextColumn.cs b/v2rayN/v2rayN/Base/MyDGTextColumn.cs deleted file mode 100644 index 427ffacc..00000000 --- a/v2rayN/v2rayN/Base/MyDGTextColumn.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Windows.Controls; - -namespace v2rayN.Base -{ - internal class MyDGTextColumn : DataGridTextColumn - { - public string ExName { get; set; } - } -} \ No newline at end of file diff --git a/v2rayN/v2rayN/Base/MyDgTextColumnAttachedProperties.cs b/v2rayN/v2rayN/Base/MyDgTextColumnAttachedProperties.cs new file mode 100644 index 00000000..96085ed0 --- /dev/null +++ b/v2rayN/v2rayN/Base/MyDgTextColumnAttachedProperties.cs @@ -0,0 +1,20 @@ +using System.Windows; + +namespace v2rayN.Base +{ + public static class MyDgTextColumnAttachedProperties + { + public static readonly DependencyProperty ExNameProperty = + DependencyProperty.RegisterAttached("ExName", typeof(string), typeof(MyDgTextColumnAttachedProperties), new PropertyMetadata(default(string))); + + public static void SetExName(DependencyObject element, string value) + { + element.SetValue(ExNameProperty, value); + } + + public static string GetExName(DependencyObject element) + { + return (string)element.GetValue(ExNameProperty); + } + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index bc37d8ff..cf09d947 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -19,645 +19,646 @@ using Point = System.Windows.Point; namespace v2rayN.Views { - public partial class MainWindow - { - private static Config _config; - - public MainWindow() - { - InitializeComponent(); - - // 设置窗口的尺寸不大于屏幕的尺寸 - if (this.Width > SystemParameters.WorkArea.Width) - { - this.Width = SystemParameters.WorkArea.Width; - } - if (this.Height > SystemParameters.WorkArea.Height) - { - this.Height = SystemParameters.WorkArea.Height; - } - - lstGroup.MaxHeight = Math.Floor(SystemParameters.WorkArea.Height * 0.20 / 40) * 40; - - _config = LazyConfig.Instance.GetConfig(); - - App.Current.SessionEnding += Current_SessionEnding; - this.Closing += MainWindow_Closing; - this.PreviewKeyDown += MainWindow_PreviewKeyDown; - btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click; - txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown; - lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown; - lstProfiles.SelectionChanged += lstProfiles_SelectionChanged; - lstProfiles.LoadingRow += LstProfiles_LoadingRow; - if (_config.uiItem.enableDragDropSort) - { - lstProfiles.AllowDrop = true; - lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown; - lstProfiles.MouseMove += LstProfiles_MouseMove; - lstProfiles.DragEnter += LstProfiles_DragEnter; - lstProfiles.Drop += LstProfiles_Drop; - } - - ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler); - Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); - - for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++) - { - cmbCurrentFontSize.Items.Add(i.ToString()); - } - - Global.Languages.ForEach(it => - { - cmbCurrentLanguage.Items.Add(it); - }); - - 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 - 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); - - //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); - - //servers move - this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables); - - this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables); - - //servers ping - this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables); - - //servers export - this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.Export2SubContentCmd, v => v.menuExport2SubContent).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.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables); - - //check update - this.BindCommand(ViewModel, vm => vm.CheckUpdateNCmd, v => v.menuCheckUpdateN).DisposeWith(disposables); - //this.BindCommand(ViewModel, vm => vm.CheckUpdateV2flyCoreCmd, v => v.menuCheckUpdateV2flyCore).DisposeWith(disposables); - //this.BindCommand(ViewModel, vm => vm.CheckUpdateSagerNetCoreCmd, v => v.menuCheckUpdateSagerNetCore).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables); - //this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.menuCheckUpdateClashCore).DisposeWith(disposables); - //this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateClashMetaCore).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.CheckUpdateSingBoxCoreCmd, v => v.menuCheckUpdateSingBoxCore).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables); - - this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables); - - //system proxy - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); - - //routings and servers - this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); - - this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); - - //tray menu - this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); - - this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); - //this.OneWayBind(ViewModel, vm => vm.BlShowTrayTip, v => v.borTrayToolTip.Visibility).DisposeWith(disposables); - - //status bar - this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); - - this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); - - //UI - this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.followSystemTheme.IsChecked).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables); - }); - - RestoreUI(); - AddHelpMenuItem(); - - var IsAdministrator = Utils.IsAdministrator(); - this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; - - //if (_config.uiItem.autoHideStartup) - //{ - // WindowState = WindowState.Minimized; - //} - - if (!_config.guiItem.enableHWA) - { - RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; - } - - var helper = new WindowInteropHelper(this); - var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle()); - hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => - { - if (_config.uiItem.followSystemTheme) - { - const int WM_SETTINGCHANGE = 0x001A; - if (msg == WM_SETTINGCHANGE) - { - if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") - { - ViewModel?.ModifyTheme(!Utils.IsLightTheme()); - } - } - } - - return IntPtr.Zero; - }); - } - - #region Event - - private void UpdateViewHandler(EViewAction action) - { - if (action == EViewAction.AdjustMainLvColWidth) - { - Application.Current.Dispatcher.Invoke(() => - { - AutofitColumnWidth(); - }); - } - else if (action == EViewAction.ProfilesFocus) - { - lstProfiles.Focus(); - } - } - - private void MainWindow_Closing(object? sender, CancelEventArgs e) - { - e.Cancel = true; - ViewModel?.ShowHideWindow(false); - } - - private void menuExit_Click(object sender, RoutedEventArgs e) - { - tbNotify.Dispose(); - StorageUI(); - ViewModel?.MyAppExit(false); - } - - private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) - { - Logging.SaveLog("Current_SessionEnding"); - StorageUI(); - ViewModel?.MyAppExit(true); - } - - private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) - { - ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast().ToList(); - } - - private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e) - { - e.Row.Header = $" {e.Row.GetIndex() + 1}"; - } - - private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e) - { - if (_config.uiItem.doubleClick2Activate) - { - ViewModel?.SetDefaultServer(); - } - else - { - ViewModel?.EditServer(false, EConfigType.Custom); - } - } - - 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 MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - switch (e.Key) - { - case Key.V: - ViewModel?.AddServerViaClipboard(); - break; - - case Key.O: - ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping); - break; - - case Key.R: - ViewModel?.ServerSpeedtest(ESpeedActionType.Realping); - break; - - case Key.S: - ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { }); - break; - - case Key.T: - ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest); - break; - - case Key.E: - ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest); - break; - } - } - else - { - if (e.Key == Key.F5) - { - ViewModel?.Reload(); - } - else if (e.Key == Key.Escape) - { - MessageBus.Current.SendMessage("true", Global.CommandStopSpeedTest); - } - } - } - - private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) - { - if (e.Key == Key.A) - { - menuSelectAll_Click(null, null); - } - else if (e.Key == Key.C) - { - ViewModel?.Export2ShareUrl(); - } - else if (e.Key == Key.D) - { - ViewModel?.EditServer(false, EConfigType.Custom); - } - else if (e.Key == Key.F) - { - ViewModel?.ShareServer(); - } - } - else - { - if (e.Key is Key.Enter or Key.Return) - { - ViewModel?.SetDefaultServer(); - } - else if (e.Key == Key.Delete) - { - ViewModel?.RemoveServer(); - } - 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); - } - } - } - - private void menuClose_Click(object sender, RoutedEventArgs e) - { - StorageUI(); - ViewModel?.ShowHideWindow(false); - } - - private void menuPromotion_Click(object sender, RoutedEventArgs e) - { - Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}"); - } - - private void txtRunningInfoDisplay_MouseDoubleClick(object sender, MouseButtonEventArgs e) - { - ViewModel?.TestServerAvailability(); - } - - private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) - { - Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); - } - - 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_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key is Key.Enter or Key.Return) - { - ViewModel?.RefreshServers(); - } - } - - #endregion Event - - #region UI - - private void RestoreUI() - { - if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) - { - Width = _config.uiItem.mainWidth; - Height = _config.uiItem.mainHeight; - } - - var maxWidth = SystemParameters.WorkArea.Width; - var maxHeight = SystemParameters.WorkArea.Height; - if (Width > maxWidth) Width = maxWidth; - if (Height > maxHeight) Height = maxHeight; - if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0) - { - gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star); - gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star); - } - - var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList(); - var displayIndex = 0; - foreach (var item in lvColumnItem) - { - foreach (MyDGTextColumn item2 in lstProfiles.Columns) - { - if (item2.ExName == item.Name) - { - if (item.Width < 0) - { - item2.Visibility = Visibility.Hidden; - } - else - { - item2.Width = item.Width; - item2.DisplayIndex = displayIndex++; - } - } - } - } - - if (!_config.guiItem.enableStatistics) - { - colTodayUp.Visibility = - colTodayDown.Visibility = - colTotalUp.Visibility = - colTotalDown.Visibility = Visibility.Hidden; - } - else - { - colTodayUp.Visibility = - colTodayDown.Visibility = - colTotalUp.Visibility = - colTotalDown.Visibility = Visibility.Visible; - } - } - - private void StorageUI() - { - _config.uiItem.mainWidth = Utils.ToInt(this.Width); - _config.uiItem.mainHeight = Utils.ToInt(this.Height); - - List lvColumnItem = new(); - for (int k = 0; k < lstProfiles.Columns.Count; k++) - { - var item2 = (MyDGTextColumn)lstProfiles.Columns[k]; - lvColumnItem.Add(new() - { - Name = item2.ExName, - Width = item2.Visibility == Visibility.Visible ? Utils.ToInt(item2.ActualWidth) : -1, - Index = item2.DisplayIndex - }); - } - _config.uiItem.mainColumnItem = lvColumnItem; - - _config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1); - _config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1); - } - - private void AddHelpMenuItem() - { - var coreInfo = LazyConfig.Instance.GetCoreInfo(); - foreach (var it in coreInfo - .Where(t => t.coreType != ECoreType.v2fly - && t.coreType != ECoreType.clash - && t.coreType != ECoreType.clash_meta - && t.coreType != ECoreType.hysteria)) - { - var item = new MenuItem() - { - Tag = it.coreUrl.Replace(@"/releases", ""), - Header = string.Format(Resx.ResUI.menuWebsiteItem, it.coreType.ToString().Replace("_", " ")).UpperFirstChar() - }; - item.Click += MenuItem_Click; - menuHelp.Items.Add(item); - } - } - - private void MenuItem_Click(object sender, RoutedEventArgs e) - { - if (sender is MenuItem item) - { - Utils.ProcessStart(item.Tag.ToString()); - } - } - - #endregion UI - - #region Drag and Drop - - private Point startPoint = new(); - private int startIndex = -1; - private string formatData = "ProfileItemModel"; - - /// - /// Helper to search up the VisualTree - /// - /// - /// - /// - private static T? FindAncestor(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((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((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 - } + public partial class MainWindow + { + private static Config _config; + + public MainWindow() + { + InitializeComponent(); + + // 设置窗口的尺寸不大于屏幕的尺寸 + if (this.Width > SystemParameters.WorkArea.Width) + { + this.Width = SystemParameters.WorkArea.Width; + } + if (this.Height > SystemParameters.WorkArea.Height) + { + this.Height = SystemParameters.WorkArea.Height; + } + + lstGroup.MaxHeight = Math.Floor(SystemParameters.WorkArea.Height * 0.20 / 40) * 40; + + _config = LazyConfig.Instance.GetConfig(); + + App.Current.SessionEnding += Current_SessionEnding; + this.Closing += MainWindow_Closing; + this.PreviewKeyDown += MainWindow_PreviewKeyDown; + btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click; + txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown; + lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown; + lstProfiles.SelectionChanged += lstProfiles_SelectionChanged; + lstProfiles.LoadingRow += LstProfiles_LoadingRow; + if (_config.uiItem.enableDragDropSort) + { + lstProfiles.AllowDrop = true; + lstProfiles.PreviewMouseLeftButtonDown += LstProfiles_PreviewMouseLeftButtonDown; + lstProfiles.MouseMove += LstProfiles_MouseMove; + lstProfiles.DragEnter += LstProfiles_DragEnter; + lstProfiles.Drop += LstProfiles_Drop; + } + + ViewModel = new MainWindowViewModel(MainSnackbar.MessageQueue!, UpdateViewHandler); + Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); + + for (int i = Global.MinFontSize; i <= Global.MinFontSize + 8; i++) + { + cmbCurrentFontSize.Items.Add(i.ToString()); + } + + Global.Languages.ForEach(it => + { + cmbCurrentLanguage.Items.Add(it); + }); + + 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 + 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); + + //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); + + //servers move + this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbMoveToGroup.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedMoveToGroup, v => v.cmbMoveToGroup.SelectedItem).DisposeWith(disposables); + + this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables); + + //servers ping + this.BindCommand(ViewModel, vm => vm.MixedTestServerCmd, v => v.menuMixedTestServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.TcpingServerCmd, v => v.menuTcpingServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.RealPingServerCmd, v => v.menuRealPingServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SpeedServerCmd, v => v.menuSpeedServer).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SortServerResultCmd, v => v.menuSortServerResult).DisposeWith(disposables); + + //servers export + this.BindCommand(ViewModel, vm => vm.Export2ClientConfigCmd, v => v.menuExport2ClientConfig).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.Export2ShareUrlCmd, v => v.menuExport2ShareUrl).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.Export2SubContentCmd, v => v.menuExport2SubContent).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.ImportOldGuiConfigCmd, v => v.menuImportOldGuiConfig).DisposeWith(disposables); + + //check update + this.BindCommand(ViewModel, vm => vm.CheckUpdateNCmd, v => v.menuCheckUpdateN).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.CheckUpdateV2flyCoreCmd, v => v.menuCheckUpdateV2flyCore).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.CheckUpdateSagerNetCoreCmd, v => v.menuCheckUpdateSagerNetCore).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.CheckUpdateXrayCoreCmd, v => v.menuCheckUpdateXrayCore).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.CheckUpdateClashCoreCmd, v => v.menuCheckUpdateClashCore).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.CheckUpdateClashMetaCoreCmd, v => v.menuCheckUpdateClashMetaCore).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.CheckUpdateSingBoxCoreCmd, v => v.menuCheckUpdateSingBoxCore).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.CheckUpdateGeoCmd, v => v.menuCheckUpdateGeo).DisposeWith(disposables); + + this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables); + + //system proxy + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); + + //routings and servers + this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); + + this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); + + //tray menu + this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables); + + this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlShowTrayTip, v => v.borTrayToolTip.Visibility).DisposeWith(disposables); + + //status bar + this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); + + this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); + + //UI + this.Bind(ViewModel, vm => vm.ColorModeDark, v => v.togDarkMode.IsChecked).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.FollowSystemTheme, v => v.followSystemTheme.IsChecked).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.Swatches, v => v.cmbSwatches.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedSwatch, v => v.cmbSwatches.SelectedItem).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CurrentFontSize, v => v.cmbCurrentFontSize.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.CurrentLanguage, v => v.cmbCurrentLanguage.Text).DisposeWith(disposables); + }); + + RestoreUI(); + AddHelpMenuItem(); + + var IsAdministrator = Utils.IsAdministrator(); + this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; + + //if (_config.uiItem.autoHideStartup) + //{ + // WindowState = WindowState.Minimized; + //} + + if (!_config.guiItem.enableHWA) + { + RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; + } + + var helper = new WindowInteropHelper(this); + var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle()); + hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) => + { + if (_config.uiItem.followSystemTheme) + { + const int WM_SETTINGCHANGE = 0x001A; + if (msg == WM_SETTINGCHANGE) + { + if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") + { + ViewModel?.ModifyTheme(!Utils.IsLightTheme()); + } + } + } + + return IntPtr.Zero; + }); + } + + #region Event + + private void UpdateViewHandler(EViewAction action) + { + if (action == EViewAction.AdjustMainLvColWidth) + { + Application.Current.Dispatcher.Invoke(() => + { + AutofitColumnWidth(); + }); + } + else if (action == EViewAction.ProfilesFocus) + { + lstProfiles.Focus(); + } + } + + private void MainWindow_Closing(object? sender, CancelEventArgs e) + { + e.Cancel = true; + ViewModel?.ShowHideWindow(false); + } + + private void menuExit_Click(object sender, RoutedEventArgs e) + { + tbNotify.Dispose(); + StorageUI(); + ViewModel?.MyAppExit(false); + } + + private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) + { + Logging.SaveLog("Current_SessionEnding"); + StorageUI(); + ViewModel?.MyAppExit(true); + } + + private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast().ToList(); + } + + private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e) + { + e.Row.Header = $" {e.Row.GetIndex() + 1}"; + } + + private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if (_config.uiItem.doubleClick2Activate) + { + ViewModel?.SetDefaultServer(); + } + else + { + ViewModel?.EditServer(false, EConfigType.Custom); + } + } + + 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 = MyDgTextColumnAttachedProperties.GetExName(colHeader.Column); + ViewModel?.SortServer(colName); + } + + private void menuSelectAll_Click(object sender, RoutedEventArgs e) + { + lstProfiles.SelectAll(); + } + + private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + switch (e.Key) + { + case Key.V: + ViewModel?.AddServerViaClipboard(); + break; + + case Key.O: + ViewModel?.ServerSpeedtest(ESpeedActionType.Tcping); + break; + + case Key.R: + ViewModel?.ServerSpeedtest(ESpeedActionType.Realping); + break; + + case Key.S: + ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { }); + break; + + case Key.T: + ViewModel?.ServerSpeedtest(ESpeedActionType.Speedtest); + break; + + case Key.E: + ViewModel?.ServerSpeedtest(ESpeedActionType.Mixedtest); + break; + } + } + else + { + if (e.Key == Key.F5) + { + ViewModel?.Reload(); + } + else if (e.Key == Key.Escape) + { + MessageBus.Current.SendMessage("true", Global.CommandStopSpeedTest); + } + } + } + + private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + { + if (e.Key == Key.A) + { + menuSelectAll_Click(null, null); + } + else if (e.Key == Key.C) + { + ViewModel?.Export2ShareUrl(); + } + else if (e.Key == Key.D) + { + ViewModel?.EditServer(false, EConfigType.Custom); + } + else if (e.Key == Key.F) + { + ViewModel?.ShareServer(); + } + } + else + { + if (e.Key is Key.Enter or Key.Return) + { + ViewModel?.SetDefaultServer(); + } + else if (e.Key == Key.Delete) + { + ViewModel?.RemoveServer(); + } + 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); + } + } + } + + private void menuClose_Click(object sender, RoutedEventArgs e) + { + StorageUI(); + ViewModel?.ShowHideWindow(false); + } + + private void menuPromotion_Click(object sender, RoutedEventArgs e) + { + Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}"); + } + + private void txtRunningInfoDisplay_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + ViewModel?.TestServerAvailability(); + } + + private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) + { + Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); + } + + 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_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key is Key.Enter or Key.Return) + { + ViewModel?.RefreshServers(); + } + } + + #endregion Event + + #region UI + + private void RestoreUI() + { + if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) + { + Width = _config.uiItem.mainWidth; + Height = _config.uiItem.mainHeight; + } + + var maxWidth = SystemParameters.WorkArea.Width; + var maxHeight = SystemParameters.WorkArea.Height; + if (Width > maxWidth) Width = maxWidth; + if (Height > maxHeight) Height = maxHeight; + if (_config.uiItem.mainGirdHeight1 > 0 && _config.uiItem.mainGirdHeight2 > 0) + { + gridMain.RowDefinitions[0].Height = new GridLength(_config.uiItem.mainGirdHeight1, GridUnitType.Star); + gridMain.RowDefinitions[2].Height = new GridLength(_config.uiItem.mainGirdHeight2, GridUnitType.Star); + } + + var lvColumnItem = _config.uiItem.mainColumnItem.OrderBy(t => t.Index).ToList(); + var displayIndex = 0; + foreach (var item in lvColumnItem) + { + foreach (var item2 in lstProfiles.Columns) + { + var colName = MyDgTextColumnAttachedProperties.GetExName(item2); + if (colName == item.Name) + { + if (item.Width < 0) + { + item2.Visibility = Visibility.Hidden; + } + else + { + item2.Width = item.Width; + item2.DisplayIndex = displayIndex++; + } + } + } + } + + if (!_config.guiItem.enableStatistics) + { + colTodayUp.Visibility = + colTodayDown.Visibility = + colTotalUp.Visibility = + colTotalDown.Visibility = Visibility.Hidden; + } + else + { + colTodayUp.Visibility = + colTodayDown.Visibility = + colTotalUp.Visibility = + colTotalDown.Visibility = Visibility.Visible; + } + } + + private void StorageUI() + { + _config.uiItem.mainWidth = Utils.ToInt(this.Width); + _config.uiItem.mainHeight = Utils.ToInt(this.Height); + + List lvColumnItem = new(); + for (int k = 0; k < lstProfiles.Columns.Count; k++) + { + var item2 = lstProfiles.Columns[k]; + lvColumnItem.Add(new() + { + Name = MyDgTextColumnAttachedProperties.GetExName(item2), + Width = item2.Visibility == Visibility.Visible ? Utils.ToInt(item2.ActualWidth) : -1, + Index = item2.DisplayIndex + }); + } + _config.uiItem.mainColumnItem = lvColumnItem; + + _config.uiItem.mainGirdHeight1 = Math.Ceiling(gridMain.RowDefinitions[0].ActualHeight + 0.1); + _config.uiItem.mainGirdHeight2 = Math.Ceiling(gridMain.RowDefinitions[2].ActualHeight + 0.1); + } + + private void AddHelpMenuItem() + { + var coreInfo = LazyConfig.Instance.GetCoreInfo(); + foreach (var it in coreInfo + .Where(t => t.coreType != ECoreType.v2fly + && t.coreType != ECoreType.clash + && t.coreType != ECoreType.clash_meta + && t.coreType != ECoreType.hysteria)) + { + var item = new MenuItem() + { + Tag = it.coreUrl.Replace(@"/releases", ""), + Header = string.Format(Resx.ResUI.menuWebsiteItem, it.coreType.ToString().Replace("_", " ")).UpperFirstChar() + }; + item.Click += MenuItem_Click; + menuHelp.Items.Add(item); + } + } + + private void MenuItem_Click(object sender, RoutedEventArgs e) + { + if (sender is MenuItem item) + { + Utils.ProcessStart(item.Tag.ToString()); + } + } + + #endregion UI + + #region Drag and Drop + + private Point startPoint = new(); + private int startIndex = -1; + private string formatData = "ProfileItemModel"; + + /// + /// Helper to search up the VisualTree + /// + /// + /// + /// + private static T? FindAncestor(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((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((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 + } } \ No newline at end of file