mirror of
				https://github.com/2dust/v2rayN.git
				synced 2025-10-31 20:42:52 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			503 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			503 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Avalonia.Controls.Notifications;
 | |
| using DialogHostAvalonia;
 | |
| using v2rayN.Desktop.Base;
 | |
| using v2rayN.Desktop.Common;
 | |
| using v2rayN.Desktop.Manager;
 | |
| 
 | |
| namespace v2rayN.Desktop.Views;
 | |
| 
 | |
| public partial class MainWindow : WindowBase<MainWindowViewModel>
 | |
| {
 | |
|     private static Config _config;
 | |
|     private readonly WindowNotificationManager? _manager;
 | |
|     private CheckUpdateView? _checkUpdateView;
 | |
|     private BackupAndRestoreView? _backupAndRestoreView;
 | |
|     private bool _blCloseByUser = false;
 | |
| 
 | |
|     public MainWindow()
 | |
|     {
 | |
|         InitializeComponent();
 | |
| 
 | |
|         _config = AppManager.Instance.Config;
 | |
|         _manager = new WindowNotificationManager(TopLevel.GetTopLevel(this)) { MaxItems = 3, Position = NotificationPosition.TopRight };
 | |
| 
 | |
|         this.KeyDown += MainWindow_KeyDown;
 | |
|         menuSettingsSetUWP.Click += menuSettingsSetUWP_Click;
 | |
|         menuPromotion.Click += menuPromotion_Click;
 | |
|         menuCheckUpdate.Click += MenuCheckUpdate_Click;
 | |
|         menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
 | |
|         menuClose.Click += MenuClose_Click;
 | |
| 
 | |
|         ViewModel = new MainWindowViewModel(UpdateViewHandler);
 | |
| 
 | |
|         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;
 | |
|                 break;
 | |
| 
 | |
|             case EGirdOrientation.Vertical:
 | |
|                 tabProfiles1.Content ??= new ProfilesView(this);
 | |
|                 tabMsgView1.Content ??= new MsgView();
 | |
|                 tabClashProxies1.Content ??= new ClashProxiesView();
 | |
|                 tabClashConnections1.Content ??= new ClashConnectionsView();
 | |
|                 gridMain1.IsVisible = true;
 | |
|                 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;
 | |
|                 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.AddAnytlsServerCmd, v => v.menuAddAnytlsServer).DisposeWith(disposables);
 | |
|             this.BindCommand(ViewModel, vm => vm.AddCustomServerCmd, v => v.menuAddCustomServer).DisposeWith(disposables);
 | |
|             this.BindCommand(ViewModel, vm => vm.AddPolicyGroupServerCmd, v => v.menuAddPolicyGroupServer).DisposeWith(disposables);
 | |
|             this.BindCommand(ViewModel, vm => vm.AddProxyChainServerCmd, v => v.menuAddProxyChainServer).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.FullConfigTemplateCmd, v => v.menuFullConfigTemplate).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;
 | |
|             }
 | |
| 
 | |
|             AppEvents.SendSnackMsgRequested
 | |
|               .AsObservable()
 | |
|               .ObserveOn(RxApp.MainThreadScheduler)
 | |
|               .Subscribe(async content => await DelegateSnackMsg(content))
 | |
|               .DisposeWith(disposables);
 | |
| 
 | |
|             AppEvents.AppExitRequested
 | |
|               .AsObservable()
 | |
|               .ObserveOn(RxApp.MainThreadScheduler)
 | |
|               .Subscribe(_ => StorageUI())
 | |
|               .DisposeWith(disposables);
 | |
| 
 | |
|             AppEvents.ShutdownRequested
 | |
|               .AsObservable()
 | |
|               .ObserveOn(RxApp.MainThreadScheduler)
 | |
|               .Subscribe(content => Shutdown(content))
 | |
|               .DisposeWith(disposables);
 | |
| 
 | |
|             AppEvents.ShowHideWindowRequested
 | |
|              .AsObservable()
 | |
|              .ObserveOn(RxApp.MainThreadScheduler)
 | |
|              .Subscribe(blShow => ShowHideWindow(blShow))
 | |
|              .DisposeWith(disposables);
 | |
|         });
 | |
| 
 | |
|         if (Utils.IsWindows())
 | |
|         {
 | |
|             this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
 | |
| 
 | |
|             ThreadPool.RegisterWaitForSingleObject(Program.ProgramStarted, OnProgramStarted, null, -1, false);
 | |
|             HotkeyManager.Instance.Init(_config, OnHotkeyHandler);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             this.Title = $"{Utils.GetVersion()}";
 | |
| 
 | |
|             menuRebootAsAdmin.IsVisible = false;
 | |
|             menuSettingsSetUWP.IsVisible = false;
 | |
|             menuGlobalHotkeySetting.IsVisible = false;
 | |
|         }
 | |
|         menuAddServerViaScan.IsVisible = false;
 | |
| 
 | |
|         if (_config.UiItem.AutoHideStartup && Utils.IsWindows())
 | |
|         {
 | |
|             this.WindowState = WindowState.Minimized;
 | |
|         }
 | |
| 
 | |
|         AddHelpMenuItem();
 | |
|     }
 | |
| 
 | |
|     #region Event
 | |
| 
 | |
|     private void OnProgramStarted(object state, bool timeout)
 | |
|     {
 | |
|         Dispatcher.UIThread.Post(() =>
 | |
|                 ShowHideWindow(true),
 | |
|             DispatcherPriority.Default);
 | |
|     }
 | |
| 
 | |
|     private async Task DelegateSnackMsg(string content)
 | |
|     {
 | |
|         _manager?.Show(new Notification(null, content, NotificationType.Information));
 | |
|     }
 | |
| 
 | |
|     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.AddGroupServerWindow:
 | |
|                 if (obj is null)
 | |
|                     return false;
 | |
|                 return await new AddGroupServerWindow((ProfileItem)obj).ShowDialog<bool>(this);
 | |
| 
 | |
|             case EViewAction.DNSSettingWindow:
 | |
|                 return await new DNSSettingWindow().ShowDialog<bool>(this);
 | |
| 
 | |
|             case EViewAction.FullConfigTemplateWindow:
 | |
|                 return await new FullConfigTemplateWindow().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.ScanScreenTask:
 | |
|                 await ScanScreenTaskAsync();
 | |
|                 break;
 | |
| 
 | |
|             case EViewAction.ScanImageTask:
 | |
|                 await ScanImageTaskAsync();
 | |
|                 break;
 | |
| 
 | |
|             case EViewAction.AddServerViaClipboard:
 | |
|                 await AddServerViaClipboardAsync();
 | |
|                 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:
 | |
|                 AppEvents.SysProxyChangeRequested.Publish((ESysProxyType)((int)e - 1));
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     protected override async void OnClosing(WindowClosingEventArgs e)
 | |
|     {
 | |
|         if (_blCloseByUser)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         Logging.SaveLog("OnClosing -> " + e.CloseReason.ToString());
 | |
| 
 | |
|         switch (e.CloseReason)
 | |
|         {
 | |
|             case WindowCloseReason.OwnerWindowClosing or WindowCloseReason.WindowClosing:
 | |
|                 e.Cancel = true;
 | |
|                 ShowHideWindow(false);
 | |
|                 break;
 | |
| 
 | |
|             case WindowCloseReason.ApplicationShutdown or WindowCloseReason.OSShutdown:
 | |
|                 await AppManager.Instance.AppExitAsync(false);
 | |
|                 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 Key.V:
 | |
|                     await AddServerViaClipboardAsync();
 | |
|                     break;
 | |
| 
 | |
|                 case Key.S:
 | |
|                     await ScanScreenTaskAsync();
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             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 AddServerViaClipboardAsync()
 | |
|     {
 | |
|         var clipboardData = await AvaUtils.GetClipboardData(this);
 | |
|         if (clipboardData.IsNotEmpty() && ViewModel != null)
 | |
|         {
 | |
|             await ViewModel.AddServerViaClipboardAsync(clipboardData);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public async Task ScanScreenTaskAsync()
 | |
|     {
 | |
|         //ShowHideWindow(false);
 | |
| 
 | |
|         NoticeManager.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.Yes)
 | |
|         {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         _blCloseByUser = true;
 | |
|         StorageUI();
 | |
| 
 | |
|         await AppManager.Instance.AppExitAsync(true);
 | |
|     }
 | |
| 
 | |
|     private void Shutdown(bool obj)
 | |
|     {
 | |
|         if (obj is bool b && _blCloseByUser == false)
 | |
|         {
 | |
|             _blCloseByUser = b;
 | |
|         }
 | |
|         StorageUI();
 | |
|         if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
 | |
|         {
 | |
|             HotkeyManager.Instance.Dispose();
 | |
|             desktop.Shutdown();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #endregion Event
 | |
| 
 | |
|     #region UI
 | |
| 
 | |
|     public void ShowHideWindow(bool? blShow)
 | |
|     {
 | |
|         var bl = blShow ??
 | |
|                     (Utils.IsLinux()
 | |
|                     ? (!_config.UiItem.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
 | |
|                     : !_config.UiItem.ShowInTaskbar);
 | |
|         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;
 | |
|     }
 | |
| 
 | |
|     protected override void OnLoaded(object? sender, RoutedEventArgs e)
 | |
|     {
 | |
|         base.OnLoaded(sender, e);
 | |
|         if (_config.UiItem.AutoHideStartup)
 | |
|         {
 | |
|             ShowHideWindow(false);
 | |
|         }
 | |
|         RestoreUI();
 | |
|     }
 | |
| 
 | |
|     private void RestoreUI()
 | |
|     {
 | |
|         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()
 | |
|     {
 | |
|         ConfigHandler.SaveWindowSizeItem(_config, GetType().Name, Width, Height);
 | |
| 
 | |
|         if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Horizontal)
 | |
|         {
 | |
|             ConfigHandler.SaveMainGirdHeight(_config, gridMain.ColumnDefinitions[0].ActualWidth, gridMain.ColumnDefinitions[2].ActualWidth);
 | |
|         }
 | |
|         else if (_config.UiItem.MainGirdOrientation == EGirdOrientation.Vertical)
 | |
|         {
 | |
|             ConfigHandler.SaveMainGirdHeight(_config, gridMain1.RowDefinitions[0].ActualHeight, gridMain1.RowDefinitions[2].ActualHeight);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private void AddHelpMenuItem()
 | |
|     {
 | |
|         var coreInfo = CoreInfoManager.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
 | |
| }
 | 
