diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 34e86a3ed..0816d7626 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -82,6 +82,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings } }; + public bool UseAnimation { get; set; } = true; + public bool UseSound { get; set; } = true; /// /// when false Alphabet static service will always return empty results diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 8c869e941..9ee486b3b 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -100,8 +100,6 @@ namespace Flow.Launcher AutoUpdates(); API.SaveAppAllSettings(); - - _mainVM.MainWindowVisibility = _settings.HideOnStartup ? Visibility.Hidden : Visibility.Visible; Log.Info("|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- "); }); } @@ -178,7 +176,7 @@ namespace Flow.Launcher public void OnSecondAppStarted() { - Current.MainWindow.Visibility = Visibility.Visible; + Current.MainWindow.Show(); } } } \ No newline at end of file diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml b/Flow.Launcher/CustomQueryHotkeySetting.xaml index 23bd89906..e9d486fe1 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml @@ -1,57 +1,126 @@ - + - + - + - + - + - - + + - + - - - - + + + + - - - - diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs index 0109474e1..ab4047cec 100644 --- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs +++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs @@ -1,8 +1,6 @@ using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; -using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.UserSettings; -using System; using System.Collections.ObjectModel; using System.Linq; using System.Windows; @@ -91,9 +89,9 @@ namespace Flow.Launcher private void BtnTestActionKeyword_OnClick(object sender, RoutedEventArgs e) { App.API.ChangeQuery(tbAction.Text); - Application.Current.MainWindow.Visibility = Visibility.Visible; + Application.Current.MainWindow.Show(); + Application.Current.MainWindow.Opacity = 1; Application.Current.MainWindow.Focus(); - } private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index fd2f5f1d9..f431504c2 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -104,6 +104,12 @@ + + + Always + + + diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index fe25ecf18..98327d8da 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -6,8 +6,6 @@ using NHotkey.Wpf; using Flow.Launcher.Core.Resource; using System.Windows; using Flow.Launcher.ViewModel; -using System.Threading.Tasks; -using System.Threading; namespace Flow.Launcher.Helper { @@ -27,7 +25,8 @@ namespace Flow.Launcher.Helper internal static void OnToggleHotkey(object sender, HotkeyEventArgs args) { - mainViewModel.ToggleFlowLauncher(); + if (!mainViewModel.GameModeStatus) + mainViewModel.ToggleFlowLauncher(); } private static void SetHotkey(string hotkeyStr, EventHandler action) @@ -75,10 +74,10 @@ namespace Flow.Launcher.Helper { SetHotkey(hotkey.Hotkey, (s, e) => { - if (mainViewModel.ShouldIgnoreHotkeys()) + if (mainViewModel.ShouldIgnoreHotkeys() || mainViewModel.GameModeStatus) return; - mainViewModel.MainWindowVisibility = Visibility.Visible; + mainViewModel.Show(); mainViewModel.ChangeQueryText(hotkey.ActionKeyword, true); }); } diff --git a/Flow.Launcher/Helper/SingletonWindowOpener.cs b/Flow.Launcher/Helper/SingletonWindowOpener.cs index fdfaaa4fc..8efc9be99 100644 --- a/Flow.Launcher/Helper/SingletonWindowOpener.cs +++ b/Flow.Launcher/Helper/SingletonWindowOpener.cs @@ -10,7 +10,6 @@ namespace Flow.Launcher.Helper { var window = Application.Current.Windows.OfType().FirstOrDefault(x => x.GetType() == typeof(T)) ?? (T)Activator.CreateInstance(typeof(T), args); - Application.Current.MainWindow.Hide(); // Fix UI bug // Add `window.WindowState = WindowState.Normal` diff --git a/Flow.Launcher/Images/gamemode.ico b/Flow.Launcher/Images/gamemode.ico new file mode 100644 index 000000000..27a46a904 Binary files /dev/null and b/Flow.Launcher/Images/gamemode.ico differ diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 5ca6bdbfd..8020cc53e 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -15,6 +15,7 @@ About Exit Close + Game Mode Flow Launcher Settings @@ -83,6 +84,10 @@ Fail to load theme {0}, fallback to default theme Theme Folder Open Theme Folder + Sound Effect + Play a small sound when the search window opens + Animation + Use Animation in UI Hotkey diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index daea406db..2b2e4b85e 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -1,105 +1,193 @@ - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - - + + - + - - - + + + - - + + - + @@ -121,49 +209,69 @@ - + - - + - - - + + + - + - - - + + + - - - + + + - + - - - + + + - - - - + + + + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 16e4be8a0..5b0a620ae 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Threading.Tasks; using System.Windows; @@ -11,16 +11,11 @@ using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.ViewModel; -using Microsoft.AspNetCore.Authorization; -using Application = System.Windows.Application; using Screen = System.Windows.Forms.Screen; using ContextMenuStrip = System.Windows.Forms.ContextMenuStrip; -using DataFormats = System.Windows.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; using KeyEventArgs = System.Windows.Input.KeyEventArgs; -using MessageBox = System.Windows.MessageBox; using NotifyIcon = System.Windows.Forms.NotifyIcon; -using System.Windows.Interop; namespace Flow.Launcher { @@ -34,6 +29,7 @@ namespace Flow.Launcher private NotifyIcon _notifyIcon; private ContextMenu contextMenu; private MainViewModel _viewModel; + private bool _animating; #endregion @@ -43,6 +39,7 @@ namespace Flow.Launcher _viewModel = mainVM; _settings = settings; InitializeComponent(); + InitializePosition(); } public MainWindow() @@ -52,6 +49,8 @@ namespace Flow.Launcher private async void OnClosing(object sender, CancelEventArgs e) { + _settings.WindowTop = Top; + _settings.WindowLeft = Left; _notifyIcon.Visible = false; _viewModel.Save(); e.Cancel = true; @@ -65,12 +64,11 @@ namespace Flow.Launcher private void OnLoaded(object sender, RoutedEventArgs _) { + HideStartup(); // show notify icon when flowlauncher is hidden InitializeNotifyIcon(); - WindowsInteropHelper.DisableControlBox(this); InitProgressbarAnimation(); - InitializePosition(); // since the default main window visibility is visible // so we need set focus during startup QueryTextBox.Focus(); @@ -79,13 +77,13 @@ namespace Flow.Launcher { switch (e.PropertyName) { - case nameof(MainViewModel.MainWindowVisibility): + case nameof(MainViewModel.MainWindowVisibilityStatus): { - if (_viewModel.MainWindowVisibility == Visibility.Visible) + if (_viewModel.MainWindowVisibilityStatus) { + UpdatePosition(); Activate(); QueryTextBox.Focus(); - UpdatePosition(); _settings.ActivateTimes++; if (!_viewModel.LastQuerySelected) { @@ -117,7 +115,7 @@ namespace Flow.Launcher _progressBarStoryboard.Stop(ProgressBar); isProgressBarStoryboardPaused = true; } - else if (_viewModel.MainWindowVisibility == Visibility.Visible && + else if (_viewModel.MainWindowVisibilityStatus && isProgressBarStoryboardPaused) { _progressBarStoryboard.Begin(ProgressBar, true); @@ -148,24 +146,29 @@ namespace Flow.Launcher break; } }; - - InitializePosition(); } private void InitializePosition() { - Top = WindowTop(); - Left = WindowLeft(); - _settings.WindowTop = Top; - _settings.WindowLeft = Left; + if (_settings.RememberLastLaunchLocation) + { + Top = _settings.WindowTop; + Left = _settings.WindowLeft; + } + else + { + Left = WindowLeft(); + Top = WindowTop(); + } } private void UpdateNotifyIconText() { var menu = contextMenu; ((MenuItem)menu.Items[1]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen"); - ((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"); - ((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"); + ((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("GameMode"); + ((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"); + ((MenuItem)menu.Items[4]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"); } private void InitializeNotifyIcon() @@ -180,13 +183,17 @@ namespace Flow.Launcher var header = new MenuItem { - Header = "Flow Launcher", + Header = "Flow Launcher", IsEnabled = false }; var open = new MenuItem { Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") }; + var gamemode = new MenuItem + { + Header = InternationalizationManager.Instance.GetTranslation("GameMode") + }; var settings = new MenuItem { Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings") @@ -196,11 +203,13 @@ namespace Flow.Launcher Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit") }; - open.Click += (o, e) => Visibility = Visibility.Visible; + open.Click += (o, e) => _viewModel.ToggleFlowLauncher(); + gamemode.Click += (o, e) => ToggleGameMode(); settings.Click += (o, e) => App.API.OpenSettingDialog(); exit.Click += (o, e) => Close(); contextMenu.Items.Add(header); contextMenu.Items.Add(open); + contextMenu.Items.Add(gamemode); contextMenu.Items.Add(settings); contextMenu.Items.Add(exit); @@ -220,6 +229,19 @@ namespace Flow.Launcher }; } + private void ToggleGameMode() + { + if (_viewModel.GameModeStatus) + { + _notifyIcon.Icon = Properties.Resources.app; + _viewModel.GameModeStatus = false; + } + else + { + _notifyIcon.Icon = Properties.Resources.gamemode; + _viewModel.GameModeStatus = true; + } + } private void InitProgressbarAnimation() { var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 150, @@ -235,6 +257,54 @@ namespace Flow.Launcher isProgressBarStoryboardPaused = true; } + public void WindowAnimator() + { + if (_animating) + return; + + _animating = true; + UpdatePosition(); + Storyboard sb = new Storyboard(); + Storyboard iconsb = new Storyboard(); + CircleEase easing = new CircleEase(); // or whatever easing class you want + easing.EasingMode = EasingMode.EaseInOut; + var da = new DoubleAnimation + { + From = 0, + To = 1, + Duration = TimeSpan.FromSeconds(0.25), + FillBehavior = FillBehavior.Stop + }; + + var da2 = new DoubleAnimation + { + From = Top + 10, + To = Top, + Duration = TimeSpan.FromSeconds(0.25), + FillBehavior = FillBehavior.Stop + }; + var da3 = new DoubleAnimation + { + From = 12, + To = 0, + EasingFunction = easing, + Duration = TimeSpan.FromSeconds(0.36), + FillBehavior = FillBehavior.Stop + }; + Storyboard.SetTarget(da, this); + Storyboard.SetTargetProperty(da, new PropertyPath(Window.OpacityProperty)); + Storyboard.SetTargetProperty(da2, new PropertyPath(Window.TopProperty)); + Storyboard.SetTargetProperty(da3, new PropertyPath(TopProperty)); + sb.Children.Add(da); + sb.Children.Add(da2); + iconsb.Children.Add(da3); + sb.Completed += (_, _) => _animating = false; + _settings.WindowLeft = Left; + _settings.WindowTop = Top; + iconsb.Begin(SearchIcon); + sb.Begin(FlowMainWindow); + } + private void OnMouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Left) DragMove(); @@ -267,22 +337,41 @@ namespace Flow.Launcher e.Handled = true; } - private void OnContextMenusForSettingsClick(object sender, RoutedEventArgs e) + private async void OnContextMenusForSettingsClick(object sender, RoutedEventArgs e) { + _viewModel.Hide(); + + if(_settings.UseAnimation) + await Task.Delay(100); + App.API.OpenSettingDialog(); } - private void OnDeactivated(object sender, EventArgs e) + private async void OnDeactivated(object sender, EventArgs e) { - if (_settings.HideWhenDeactive) + //This condition stops extra hide call when animator is on, + // which causes the toggling to occasional hide instead of show. + if (_viewModel.MainWindowVisibilityStatus) { - _viewModel.Hide(); + // Need time to initialize the main query window animation. + // This also stops the mainwindow from flickering occasionally after Settings window is opened + // and always after Settings window is closed. + if (_settings.UseAnimation) + await Task.Delay(100); + + if (_settings.HideWhenDeactive) + { + _viewModel.Hide(); + } } } private void UpdatePosition() { + if (_animating) + return; + if (_settings.RememberLastLaunchLocation) { Left = _settings.WindowLeft; @@ -297,6 +386,8 @@ namespace Flow.Launcher private void OnLocationChanged(object sender, EventArgs e) { + if (_animating) + return; if (_settings.RememberLastLaunchLocation) { _settings.WindowLeft = Left; @@ -304,7 +395,20 @@ namespace Flow.Launcher } } - private double WindowLeft() + public void HideStartup() + { + UpdatePosition(); + if (_settings.HideOnStartup) + { + _viewModel.Hide(); + } + else + { + _viewModel.Show(); + } + } + + public double WindowLeft() { var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0); @@ -313,7 +417,7 @@ namespace Flow.Launcher return left; } - private double WindowTop() + public double WindowTop() { var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y); diff --git a/Flow.Launcher/Properties/Resources.Designer.cs b/Flow.Launcher/Properties/Resources.Designer.cs index a19716073..43927cb98 100644 --- a/Flow.Launcher/Properties/Resources.Designer.cs +++ b/Flow.Launcher/Properties/Resources.Designer.cs @@ -69,5 +69,13 @@ namespace Flow.Launcher.Properties { return ((System.Drawing.Icon)(obj)); } } + internal static System.Drawing.Icon gamemode + { + get + { + object obj = ResourceManager.GetObject("gamemode", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } } } diff --git a/Flow.Launcher/Properties/Resources.resx b/Flow.Launcher/Properties/Resources.resx index 3ae43d89b..2126cb185 100644 --- a/Flow.Launcher/Properties/Resources.resx +++ b/Flow.Launcher/Properties/Resources.resx @@ -112,13 +112,16 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + ..\Resources\app.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Images\gamemode.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index e90a53fc3..51484e53e 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -55,7 +55,7 @@ namespace Flow.Launcher public void RestartApp() { - _mainVM.MainWindowVisibility = Visibility.Hidden; + _mainVM.Hide(); // we must manually save // UpdateManager.RestartApp() will call Environment.Exit(0) @@ -70,7 +70,7 @@ namespace Flow.Launcher public void RestarApp() => RestartApp(); - public void ShowMainWindow() => _mainVM.MainWindowVisibility = Visibility.Visible; + public void ShowMainWindow() => _mainVM.Show(); public void CheckForNewUpdate() => _settingsVM.UpdateApp(); diff --git a/Flow.Launcher/Resources/open.wav b/Flow.Launcher/Resources/open.wav new file mode 100644 index 000000000..4f13724f7 Binary files /dev/null and b/Flow.Launcher/Resources/open.wav differ diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index d52474d3f..c674e9a70 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -1,25 +1,32 @@ - - + + @@ -30,46 +37,88 @@ - + - + - + - - + + - + - + - - + + - - + + - + - + - + @@ -77,8 +126,13 @@ - + @@ -92,11 +146,9 @@ - + - + @@ -105,7 +157,7 @@ - +