From 82909cd9fa81e3f8855bfe8c0f5c1ddda390c756 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 28 Mar 2025 21:39:25 +0800 Subject: [PATCH 1/3] Fix application null exception & Remove unused MainWindowOpacity --- Flow.Launcher/MainWindow.xaml | 1 - Flow.Launcher/ViewModel/MainViewModel.cs | 15 +++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 34b376cc9af..533819d1730 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -24,7 +24,6 @@ Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Loaded="OnLoaded" LocationChanged="OnLocationChanged" - Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" PreviewKeyDown="OnKeyDown" PreviewKeyUp="OnKeyUp" PreviewMouseMove="OnPreviewMouseMove" diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 18ee2cb5b65..c69fc4484a2 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -753,8 +753,7 @@ private ResultsViewModel SelectedResults public Visibility ProgressBarVisibility { get; set; } public Visibility MainWindowVisibility { get; set; } - public double MainWindowOpacity { get; set; } = 1; - + // This is to be used for determining the visibility status of the mainwindow instead of MainWindowVisibility // because it is more accurate and reliable representation than using Visibility as a condition check public bool MainWindowVisibilityStatus { get; set; } = true; @@ -1454,9 +1453,11 @@ public bool ShouldIgnoreHotkeys() public void Show() { + // Invoke on UI thread Application.Current.Dispatcher.Invoke(() => { - if (Application.Current.MainWindow is MainWindow mainWindow) + // When application is exitting, the Application.Current will be null + if (Application.Current?.MainWindow is MainWindow mainWindow) { // 📌 Remove DWM Cloak (Make the window visible normally) Win32Helper.DWMSetCloakForWindow(mainWindow, false); @@ -1481,10 +1482,10 @@ public void Show() // Update WPF properties MainWindowVisibility = Visibility.Visible; - MainWindowOpacity = 1; MainWindowVisibilityStatus = true; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true }); + // Switch keyboard layout if (StartWithEnglishMode) { Win32Helper.SwitchToEnglishKeyboardLayout(true); @@ -1527,9 +1528,11 @@ public async void Hide() break; } + // Invoke on UI thread Application.Current.Dispatcher.Invoke(() => { - if (Application.Current.MainWindow is MainWindow mainWindow) + // When application is exitting, the Application.Current will be null + if (Application.Current?.MainWindow is MainWindow mainWindow) { // Set clock and search icon opacity var opacity = Settings.UseAnimation ? 0.0 : 1.0; @@ -1549,6 +1552,7 @@ public async void Hide() } }, DispatcherPriority.Render); + // Switch keyboard layout if (StartWithEnglishMode) { Win32Helper.RestorePreviousKeyboardLayout(); @@ -1558,7 +1562,6 @@ public async void Hide() await Task.Delay(50); // Update WPF properties - //MainWindowOpacity = 0; MainWindowVisibilityStatus = false; MainWindowVisibility = Visibility.Collapsed; VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = false }); From 494e947ccc4134bcf6709ae570ee5c61a7d9fb83 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 28 Mar 2025 21:42:40 +0800 Subject: [PATCH 2/3] Code quality --- Flow.Launcher/MainWindow.xaml.cs | 49 ++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 86b65386eed..d8c05971ad1 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -241,7 +241,7 @@ private async void OnLoaded(object sender, RoutedEventArgs _) }; // QueryTextBox.Text change detection (modified to only work when character count is 1 or higher) - QueryTextBox.TextChanged += (sender, e) => UpdateClockPanelVisibility(); + QueryTextBox.TextChanged += (s, e) => UpdateClockPanelVisibility(); // Detecting ContextMenu.Visibility changes DependencyPropertyDescriptor @@ -351,7 +351,6 @@ private void OnKeyDown(object sender, KeyEventArgs e) _viewModel.LoadContextMenuCommand.Execute(null); e.Handled = true; } - break; case Key.Left: if (!_viewModel.QueryResultsSelected() && QueryTextBox.CaretIndex == 0) @@ -359,7 +358,6 @@ private void OnKeyDown(object sender, KeyEventArgs e) _viewModel.EscCommand.Execute(null); e.Handled = true; } - break; case Key.Back: if (specialKeyState.CtrlPressed) @@ -378,7 +376,6 @@ private void OnKeyDown(object sender, KeyEventArgs e) } } } - break; default: break; @@ -864,8 +861,11 @@ private void WindowAnimation() private void UpdateClockPanelVisibility() { if (QueryTextBox == null || ContextMenu == null || History == null || ClockPanel == null) + { return; + } + // ✅ Initialize animation length & duration var animationLength = _settings.AnimationSpeed switch { AnimationSpeeds.Slow => 560, @@ -873,7 +873,6 @@ private void UpdateClockPanelVisibility() AnimationSpeeds.Fast => 160, _ => _settings.CustomAnimationLength }; - var animationDuration = TimeSpan.FromMilliseconds(animationLength * 2 / 3); // ✅ Conditions for showing ClockPanel (No query input & ContextMenu, History are closed) @@ -890,15 +889,21 @@ private void UpdateClockPanelVisibility() } // ✅ 2. When ContextMenu is closed, keep it Hidden if there's text in the query (remember previous state) - if (ContextMenu.Visibility != Visibility.Visible && QueryTextBox.Text.Length > 0) + else if (QueryTextBox.Text.Length > 0) { _viewModel.ClockPanelVisibility = Visibility.Hidden; _viewModel.ClockPanelOpacity = 0.0; return; } + // ✅ Prevent multiple animations + if (_isClockPanelAnimating) + { + return; + } + // ✅ 3. When hiding ClockPanel (apply fade-out animation) - if ((!shouldShowClock) && _viewModel.ClockPanelVisibility == Visibility.Visible && !_isClockPanelAnimating) + if ((!shouldShowClock) && _viewModel.ClockPanelVisibility == Visibility.Visible) { _isClockPanelAnimating = true; @@ -920,32 +925,32 @@ private void UpdateClockPanelVisibility() } // ✅ 4. When showing ClockPanel (apply fade-in animation) - else if (shouldShowClock && _viewModel.ClockPanelVisibility != Visibility.Visible && !_isClockPanelAnimating) + else if (shouldShowClock && _viewModel.ClockPanelVisibility != Visibility.Visible) { _isClockPanelAnimating = true; - Application.Current.Dispatcher.Invoke(() => + _viewModel.ClockPanelVisibility = Visibility.Visible; // ✅ Set Visibility to Visible first + + var fadeIn = new DoubleAnimation { - _viewModel.ClockPanelVisibility = Visibility.Visible; // ✅ Set Visibility to Visible first + From = 0.0, + To = 1.0, + Duration = animationDuration, + FillBehavior = FillBehavior.HoldEnd + }; - var fadeIn = new DoubleAnimation - { - From = 0.0, - To = 1.0, - Duration = animationDuration, - FillBehavior = FillBehavior.HoldEnd - }; - - fadeIn.Completed += (s, e) => _isClockPanelAnimating = false; - ClockPanel.BeginAnimation(OpacityProperty, fadeIn); - }, DispatcherPriority.Render); + fadeIn.Completed += (s, e) => _isClockPanelAnimating = false; + + ClockPanel.BeginAnimation(OpacityProperty, fadeIn); } } private static double GetOpacityFromStyle(Style style, double defaultOpacity = 1.0) { if (style == null) + { return defaultOpacity; + } foreach (Setter setter in style.Setters.Cast()) { @@ -961,7 +966,9 @@ private static double GetOpacityFromStyle(Style style, double defaultOpacity = 1 private static Thickness GetThicknessFromStyle(Style style, Thickness defaultThickness) { if (style == null) + { return defaultThickness; + } foreach (Setter setter in style.Setters.Cast()) { From c64e16d086366d712bb33f23485250c852934775 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 28 Mar 2025 21:46:23 +0800 Subject: [PATCH 3/3] Code quality --- Flow.Launcher/MainWindow.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index d8c05971ad1..0fd802f1e13 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -111,8 +111,8 @@ private async void OnLoaded(object sender, RoutedEventArgs _) App.API.SaveAppAllSettings(); // Show Welcome Window - var WelcomeWindow = new WelcomeWindow(); - WelcomeWindow.Show(); + var welcomeWindow = new WelcomeWindow(); + welcomeWindow.Show(); } // Hide window if need