diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 4ebff16a9..8c970eddd 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Text; using System.Threading.Tasks; @@ -104,14 +104,22 @@ namespace Flow.Launcher }); } - private void AutoStartup() { - if (_settings.StartFlowLauncherOnSystemStartup) + // we try to enable auto-startup on first launch, or reenable if it was removed + // but the user still has the setting set + if (_settings.StartFlowLauncherOnSystemStartup && !Helper.AutoStartup.IsEnabled) { - if (!SettingWindow.StartupSet()) + try { - SettingWindow.SetStartup(); + Helper.AutoStartup.Enable(); + } + catch (Exception e) + { + // but if it fails (permissions, etc) then don't keep retrying + // this also gives the user a visual indication in the Settings widget + _settings.StartFlowLauncherOnSystemStartup = false; + Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"), e.Message); } } } diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs new file mode 100644 index 000000000..956324020 --- /dev/null +++ b/Flow.Launcher/Helper/AutoStartup.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Logger; +using Microsoft.Win32; + +namespace Flow.Launcher.Helper +{ + public class AutoStartup + { + private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; + + public static bool IsEnabled + { + get + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + var path = key?.GetValue(Constant.FlowLauncher) as string; + return path == Constant.ExecutablePath; + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Ignoring non-critical registry error (querying if enabled): {e}"); + } + + return false; + } + } + + public static void Disable() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.DeleteValue(Constant.FlowLauncher, false); + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Failed to disable auto-startup: {e}"); + throw; + } + } + + internal static void Enable() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.SetValue(Constant.FlowLauncher, Constant.ExecutablePath); + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Failed to enable auto-startup: {e}"); + throw; + } + } + } +} diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 6ec3bb4ef..bdf745052 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -30,6 +30,7 @@ Portable Mode Store all settings and user data in one folder (Useful when used with removable drives or cloud services). Start Flow Launcher on system startup + Error setting launch on startup Hide Flow Launcher when focus is lost Do not show new version notifications Remember last launch location diff --git a/Flow.Launcher/Notification.cs b/Flow.Launcher/Notification.cs index 3f5565eeb..57c1e88f2 100644 --- a/Flow.Launcher/Notification.cs +++ b/Flow.Launcher/Notification.cs @@ -18,7 +18,7 @@ namespace Flow.Launcher } [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")] - public static void Show(string title, string subTitle, string iconPath) + public static void Show(string title, string subTitle, string iconPath = null) { // Handle notification for win7/8/early win10 if (legacy) @@ -45,4 +45,4 @@ namespace Flow.Launcher msg.Show(title, subTitle, iconPath); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 81f7a2389..e698ae597 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -286,4 +286,4 @@ namespace Flow.Launcher #endregion } -} \ No newline at end of file +} diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 73074abd3..06c9549e2 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -598,10 +598,8 @@ + IsChecked="{Binding StartFlowLauncherOnSystemStartup}" + Style="{DynamicResource SideControlCheckBox}" /> diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 120131830..c7b4baf2e 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -1,9 +1,10 @@ -using Flow.Launcher.Core.ExternalPlugins; +using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Core.Resource; using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Hotkey; +using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; @@ -30,8 +31,6 @@ namespace Flow.Launcher { public partial class SettingWindow { - private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; - public readonly IPublicAPI API; private Settings settings; private SettingWindowViewModel viewModel; @@ -58,39 +57,6 @@ namespace Flow.Launcher hwndTarget.RenderMode = RenderMode.SoftwareOnly; } - private void OnAutoStartupChecked(object sender, RoutedEventArgs e) - { - SetStartup(); - } - - private void OnAutoStartupUncheck(object sender, RoutedEventArgs e) - { - RemoveStartup(); - } - - public static void SetStartup() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.SetValue(Constant.FlowLauncher, Constant.ExecutablePath); - } - - private void RemoveStartup() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.DeleteValue(Constant.FlowLauncher, false); - } - - public static bool StartupSet() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - var path = key?.GetValue(Constant.FlowLauncher) as string; - if (path != null) - { - return path == Constant.ExecutablePath; - } - return false; - } - private void OnSelectPythonDirectoryClick(object sender, RoutedEventArgs e) { var dlg = new FolderBrowserDialog @@ -384,4 +350,4 @@ namespace Flow.Launcher Plugins.ScrollIntoView(Plugins.SelectedItem); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index fbcea504e..ab0e67519 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -306,8 +306,8 @@ namespace Flow.Launcher.ViewModel { Notification.Show( InternationalizationManager.Instance.GetTranslation("success"), - InternationalizationManager.Instance.GetTranslation("completedSuccessfully"), - ""); + InternationalizationManager.Instance.GetTranslation("completedSuccessfully") + ); })) .ConfigureAwait(false); }); @@ -927,4 +927,4 @@ namespace Flow.Launcher.ViewModel #endregion } -} \ No newline at end of file +} diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 2fc6934d5..a63e54f3b 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -60,7 +60,30 @@ namespace Flow.Launcher.ViewModel Settings.AutoUpdates = value; if (value) + { UpdateApp(); + } + } + } + + public bool StartFlowLauncherOnSystemStartup + { + get => Settings.StartFlowLauncherOnSystemStartup; + set + { + Settings.StartFlowLauncherOnSystemStartup = value; + + try + { + if (value) + AutoStartup.Enable(); + else + AutoStartup.Disable(); + } + catch (Exception e) + { + Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"), e.Message); + } } }