From ce93e24c7e490ab136abfa0797a0b85dabdb8fe7 Mon Sep 17 00:00:00 2001 From: DB p Date: Mon, 31 Mar 2025 20:30:29 +0900 Subject: [PATCH 01/33] Ungroup Item in general page --- .../Views/SettingsPaneGeneral.xaml | 57 ++++++------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index edb2c1441..3f8272dda 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -28,16 +28,16 @@ Style="{StaticResource PageTitle}" Text="{DynamicResource general}" TextAlignment="left" /> - - - - + + - - + - - - - - + + + + - - - - - - - - - - Date: Mon, 31 Mar 2025 21:27:59 +0800 Subject: [PATCH 02/33] Code quality --- .../Environments/AbstractPluginEnvironment.cs | 50 +++++++++---------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs index 7e9cc9a48..f80e573f9 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs @@ -1,15 +1,14 @@ -using Flow.Launcher.Infrastructure.Logger; -using Flow.Launcher.Infrastructure.UserSettings; -using Flow.Launcher.Plugin; -using Flow.Launcher.Plugin.SharedCommands; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows; using System.Windows.Forms; -using Flow.Launcher.Core.Resource; using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Core.ExternalPlugins.Environments { @@ -43,8 +42,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal IEnumerable Setup() { + // If no plugin is using the language, return empty list if (!PluginMetadataList.Any(o => o.Language.Equals(Language, StringComparison.OrdinalIgnoreCase))) + { return new List(); + } if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath)) { @@ -56,24 +58,21 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments } var noRuntimeMessage = string.Format( - InternationalizationManager.Instance.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"), + API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"), Language, EnvName, Environment.NewLine ); if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No) { - var msg = string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName); - string selectedFile; + var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName); - selectedFile = GetFileFromDialog(msg, FileDialogFilter); + var selectedFile = GetFileFromDialog(msg, FileDialogFilter); - if (!string.IsNullOrEmpty(selectedFile)) - PluginsSettingsFilePath = selectedFile; + if (!string.IsNullOrEmpty(selectedFile)) PluginsSettingsFilePath = selectedFile; // Nothing selected because user pressed cancel from the file dialog window - if (string.IsNullOrEmpty(selectedFile)) - InstallEnvironment(); + if (string.IsNullOrEmpty(selectedFile)) InstallEnvironment(); } else { @@ -86,7 +85,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments } else { - API.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language)); + API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language)); Log.Error("PluginsLoader", $"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.", $"{Language}Environment"); @@ -99,13 +98,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments private void EnsureLatestInstalled(string expectedPath, string currentPath, string installedDirPath) { - if (expectedPath == currentPath) - return; + if (expectedPath == currentPath) return; FilesFolders.RemoveFolderIfExists(installedDirPath, (s) => API.ShowMsgBox(s)); InstallEnvironment(); - } internal abstract PluginPair CreatePluginPair(string filePath, PluginMetadata metadata); @@ -126,7 +123,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments return pluginPairs; } - private string GetFileFromDialog(string title, string filter = "") + private static string GetFileFromDialog(string title, string filter = "") { var dlg = new OpenFileDialog { @@ -140,7 +137,6 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments var result = dlg.ShowDialog(); return result == DialogResult.OK ? dlg.FileName : string.Empty; - } /// @@ -183,31 +179,33 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments else { if (IsUsingPortablePath(settings.PluginSettings.PythonExecutablePath, DataLocation.PythonEnvironmentName)) + { settings.PluginSettings.PythonExecutablePath = GetUpdatedEnvironmentPath(settings.PluginSettings.PythonExecutablePath); + } if (IsUsingPortablePath(settings.PluginSettings.NodeExecutablePath, DataLocation.NodeEnvironmentName)) + { settings.PluginSettings.NodeExecutablePath = GetUpdatedEnvironmentPath(settings.PluginSettings.NodeExecutablePath); + } } } private static bool IsUsingPortablePath(string filePath, string pluginEnvironmentName) { - if (string.IsNullOrEmpty(filePath)) - return false; + if (string.IsNullOrEmpty(filePath)) return false; // DataLocation.PortableDataPath returns the current portable path, this determines if an out // of date path is also a portable path. - var portableAppEnvLocation = $"UserData\\{DataLocation.PluginEnvironments}\\{pluginEnvironmentName}"; + var portableAppEnvLocation = Path.Combine("UserData", DataLocation.PluginEnvironments, pluginEnvironmentName); return filePath.Contains(portableAppEnvLocation); } private static bool IsUsingRoamingPath(string filePath) { - if (string.IsNullOrEmpty(filePath)) - return false; + if (string.IsNullOrEmpty(filePath)) return false; return filePath.StartsWith(DataLocation.RoamingDataPath); } @@ -217,7 +215,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments var index = filePath.IndexOf(DataLocation.PluginEnvironments); // get the substring after "Environments" because we can not determine it dynamically - var ExecutablePathSubstring = filePath.Substring(index + DataLocation.PluginEnvironments.Count()); + var ExecutablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..]; return $"{DataLocation.PluginEnvironmentsPath}{ExecutablePathSubstring}"; } } From cc1e6dd7eeb40218e1c89b6399530d6db9c5a8e7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 31 Mar 2025 21:53:33 +0800 Subject: [PATCH 03/33] Fix theme select initialization issue --- Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs index 4467b94fb..31faeba52 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs @@ -9,9 +9,13 @@ namespace Flow.Launcher.Plugin.Sys { public const string Keyword = "fltheme"; - private readonly Theme _theme; private readonly PluginInitContext _context; + // Do not initialize it in the constructor, because it will cause null reference in + // var dicts = Application.Current.Resources.MergedDictionaries; line of Theme + private Theme theme = null; + private Theme Theme => theme ??= Ioc.Default.GetRequiredService(); + #region Theme Selection // Theme select codes simplified from SettingsPaneThemeViewModel.cs @@ -19,24 +23,23 @@ namespace Flow.Launcher.Plugin.Sys private Theme.ThemeData _selectedTheme; public Theme.ThemeData SelectedTheme { - get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme()); + get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == Theme.GetCurrentTheme()); set { _selectedTheme = value; - _theme.ChangeTheme(value.FileNameWithoutExtension); + Theme.ChangeTheme(value.FileNameWithoutExtension); - _ = _theme.RefreshFrameAsync(); + _ = Theme.RefreshFrameAsync(); } } - private List Themes => _theme.LoadAvailableThemes(); + private List Themes => Theme.LoadAvailableThemes(); #endregion public ThemeSelector(PluginInitContext context) { _context = context; - _theme = Ioc.Default.GetRequiredService(); } public List Query(Query query) From bf259dcb13eb0258417f79e1858303717c32a1e9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 08:47:57 +0800 Subject: [PATCH 04/33] Fix application dispose issue --- Flow.Launcher/App.xaml.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 7b1d113fb..9aee56bff 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -138,6 +138,11 @@ namespace Flow.Launcher { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { + // Because new message box api uses MessageBoxEx window, + // if it is created and closed before main window is created, it will cause the application to exit. + // So set to OnExplicitShutdown to prevent the application from shutting down before main window is created + Current.ShutdownMode = ShutdownMode.OnExplicitShutdown; + Log.SetLogLevel(_settings.LogLevel); Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate(); From 6a2b3495a009927c8593de42a3c21020f01c12d7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 09:26:39 +0800 Subject: [PATCH 05/33] Ask reselect environment path until it is valid --- .../Environments/AbstractPluginEnvironment.cs | 40 +++++++++++++++++-- Flow.Launcher/Languages/en.xaml | 5 +++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs index f80e573f9..0bd00d982 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs @@ -69,10 +69,44 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments var selectedFile = GetFileFromDialog(msg, FileDialogFilter); - if (!string.IsNullOrEmpty(selectedFile)) PluginsSettingsFilePath = selectedFile; - + if (!string.IsNullOrEmpty(selectedFile)) + { + PluginsSettingsFilePath = selectedFile; + } // Nothing selected because user pressed cancel from the file dialog window - if (string.IsNullOrEmpty(selectedFile)) InstallEnvironment(); + else + { + var forceDownloadMessage = string.Format( + API.GetTranslation("runtimeExecutableInvalidChooseDownload"), + Language, + EnvName, + Environment.NewLine + ); + + // Let users select valid path or choose to download + while (string.IsNullOrEmpty(selectedFile)) + { + if (API.ShowMsgBox(forceDownloadMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + // Continue select file + selectedFile = GetFileFromDialog(msg, FileDialogFilter); + } + else + { + // User selected no, break the loop + break; + } + } + + if (!string.IsNullOrEmpty(selectedFile)) + { + PluginsSettingsFilePath = selectedFile; + } + else + { + InstallEnvironment(); + } + } } else { diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 3c0e5b153..2df430c3b 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -9,6 +9,11 @@ Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable Please select the {0} executable + + Your selected {0} executable is invalid. + {2}{2} + Click yes if you would like select the {0} executable agian. Click no if you would like to download {1} + Unable to set {0} executable path, please try from Flow's settings (scroll down to the bottom). Fail to Init Plugins Plugins: {0} - fail to load and would be disabled, please contact plugin creator for help From a9dfd1b377d2129cf74a51171386db84bc486a78 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 09:57:04 +0800 Subject: [PATCH 06/33] Code quality --- .../Environments/AbstractPluginEnvironment.cs | 4 ++-- .../Environments/PythonEnvironment.cs | 12 ++++++++---- .../Environments/TypeScriptEnvironment.cs | 14 +++++++++----- .../Environments/TypeScriptV2Environment.cs | 14 +++++++++----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs index 0bd00d982..bbb6cf638 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs @@ -249,8 +249,8 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments var index = filePath.IndexOf(DataLocation.PluginEnvironments); // get the substring after "Environments" because we can not determine it dynamically - var ExecutablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..]; - return $"{DataLocation.PluginEnvironmentsPath}{ExecutablePathSubstring}"; + var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..]; + return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}"; } } } diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs index 607c19062..fab5738de 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs @@ -1,10 +1,10 @@ -using Droplex; +using System.Collections.Generic; +using System.IO; +using Droplex; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; -using System.Collections.Generic; -using System.IO; namespace Flow.Launcher.Core.ExternalPlugins.Environments { @@ -22,7 +22,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override string FileDialogFilter => "Python|pythonw.exe"; - internal override string PluginsSettingsFilePath { get => PluginSettings.PythonExecutablePath; set => PluginSettings.PythonExecutablePath = value; } + internal override string PluginsSettingsFilePath + { + get => PluginSettings.PythonExecutablePath; + set => PluginSettings.PythonExecutablePath = value; + } internal PythonEnvironment(List pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { } diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs index 399f7cc03..8a4f527ba 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -using Droplex; -using Flow.Launcher.Infrastructure.UserSettings; -using Flow.Launcher.Plugin.SharedCommands; -using Flow.Launcher.Plugin; using System.IO; +using Droplex; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Core.ExternalPlugins.Environments { @@ -19,7 +19,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override string InstallPath => Path.Combine(EnvPath, "Node-v16.18.0"); internal override string ExecutablePath => Path.Combine(InstallPath, "node-v16.18.0-win-x64\\node.exe"); - internal override string PluginsSettingsFilePath { get => PluginSettings.NodeExecutablePath; set => PluginSettings.NodeExecutablePath = value; } + internal override string PluginsSettingsFilePath + { + get => PluginSettings.NodeExecutablePath; + set => PluginSettings.NodeExecutablePath = value; + } internal TypeScriptEnvironment(List pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { } diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs index e8cb72e11..61fd28376 100644 --- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs +++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; -using Droplex; -using Flow.Launcher.Infrastructure.UserSettings; -using Flow.Launcher.Plugin.SharedCommands; -using Flow.Launcher.Plugin; using System.IO; +using Droplex; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Core.ExternalPlugins.Environments { @@ -19,7 +19,11 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments internal override string InstallPath => Path.Combine(EnvPath, "Node-v16.18.0"); internal override string ExecutablePath => Path.Combine(InstallPath, "node-v16.18.0-win-x64\\node.exe"); - internal override string PluginsSettingsFilePath { get => PluginSettings.NodeExecutablePath; set => PluginSettings.NodeExecutablePath = value; } + internal override string PluginsSettingsFilePath + { + get => PluginSettings.NodeExecutablePath; + set => PluginSettings.NodeExecutablePath = value; + } internal TypeScriptV2Environment(List pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { } From f9c1b6aa3e4dd7052f484e8518e92fffbe234861 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 09:57:55 +0800 Subject: [PATCH 07/33] Adjust usings --- Flow.Launcher.Core/Plugin/PluginManager.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 4f869901c..17517832b 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -1,20 +1,19 @@ -using Flow.Launcher.Core.ExternalPlugins; -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using ISavable = Flow.Launcher.Plugin.ISavable; using Flow.Launcher.Plugin.SharedCommands; -using System.Text.Json; -using Flow.Launcher.Core.Resource; -using CommunityToolkit.Mvvm.DependencyInjection; +using ISavable = Flow.Launcher.Plugin.ISavable; namespace Flow.Launcher.Core.Plugin { From 8e8b5dbbba6d45c9304b556c022fe2ebf277ed5d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 19:18:32 +0800 Subject: [PATCH 08/33] Code quality --- .../ViewModels/SettingsPaneAboutViewModel.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs index 20f905411..07e9fba1e 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using System.Windows; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core; -using Flow.Launcher.Core.Resource; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; @@ -24,7 +23,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel get { var size = GetLogFiles().Sum(file => file.Length); - return $"{InternationalizationManager.Instance.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})"; + return $"{App.API.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})"; } } @@ -42,7 +41,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel }; public string ActivatedTimes => string.Format( - InternationalizationManager.Instance.GetTranslation("about_activate_times"), + App.API.GetTranslation("about_activate_times"), _settings.ActivateTimes ); @@ -88,8 +87,8 @@ public partial class SettingsPaneAboutViewModel : BaseModel private void AskClearLogFolderConfirmation() { var confirmResult = App.API.ShowMsgBox( - InternationalizationManager.Instance.GetTranslation("clearlogfolderMessage"), - InternationalizationManager.Instance.GetTranslation("clearlogfolder"), + App.API.GetTranslation("clearlogfolderMessage"), + App.API.GetTranslation("clearlogfolder"), MessageBoxButton.YesNo ); @@ -121,7 +120,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel } [RelayCommand] - private Task UpdateApp() => _updater.UpdateAppAsync(false); + private Task UpdateAppAsync() => _updater.UpdateAppAsync(false); private void ClearLogFolder() { From 482fdc939f9fd01dfdd4b75f485e30768c43e63d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 1 Apr 2025 20:12:27 +0800 Subject: [PATCH 09/33] Add clean cache option --- Flow.Launcher/Languages/en.xaml | 2 + .../ViewModels/SettingsPaneAboutViewModel.cs | 49 ++++++++++++++++++- .../SettingPages/Views/SettingsPaneAbout.xaml | 4 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 2df430c3b..6963d81c9 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -325,6 +325,8 @@ Log Folder Clear Logs Are you sure you want to delete all logs? + Clear Caches + Are you sure you want to delete all caches? Wizard User Data Location User settings and installed plugins are saved in the user data folder. This location may vary depending on whether it's in portable mode or not. diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs index 07e9fba1e..47cb1b6c3 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs @@ -27,6 +27,15 @@ public partial class SettingsPaneAboutViewModel : BaseModel } } + public string CacheFolderSize + { + get + { + var size = GetCacheFiles().Sum(file => file.Length); + return $"{App.API.GetTranslation("clearcachefolder")} ({BytesToReadableString(size)})"; + } + } + public string Website => Constant.Website; public string SponsorPage => Constant.SponsorPage; public string ReleaseNotes => _updater.GitHubRepository + "/releases/latest"; @@ -98,6 +107,21 @@ public partial class SettingsPaneAboutViewModel : BaseModel } } + [RelayCommand] + private void AskClearCacheFolderConfirmation() + { + var confirmResult = App.API.ShowMsgBox( + App.API.GetTranslation("clearcachefolderMessage"), + App.API.GetTranslation("clearcachefolder"), + MessageBoxButton.YesNo + ); + + if (confirmResult == MessageBoxResult.Yes) + { + ClearCacheFolder(); + } + } + [RelayCommand] private void OpenSettingsFolder() { @@ -112,7 +136,6 @@ public partial class SettingsPaneAboutViewModel : BaseModel App.API.OpenDirectory(parentFolderPath); } - [RelayCommand] private void OpenLogsFolder() { @@ -147,6 +170,30 @@ public partial class SettingsPaneAboutViewModel : BaseModel return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList(); } + private void ClearCacheFolder() + { + var cacheDirectory = GetCacheDir(); + var cacheFiles = GetCacheFiles(); + + cacheFiles.ForEach(f => f.Delete()); + + cacheDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly) + .ToList() + .ForEach(dir => dir.Delete(true)); + + OnPropertyChanged(nameof(CacheFolderSize)); + } + + private static DirectoryInfo GetCacheDir() + { + return new DirectoryInfo(DataLocation.CacheDirectory); + } + + private static List GetCacheFiles() + { + return GetCacheDir().EnumerateFiles("*", SearchOption.AllDirectories).ToList(); + } + private static string BytesToReadableString(long bytes) { const int scale = 1024; diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml index 75c513411..f7deee7cf 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml @@ -90,6 +90,10 @@ Margin="0 12 0 0" Icon=""> + /// - private UpdateManager NewUpdateManager() + private static UpdateManager NewUpdateManager() { var applicationFolderName = Constant.ApplicationDirectory .Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None) @@ -81,20 +81,16 @@ namespace Flow.Launcher.Core.Configuration public void RemoveShortcuts() { - using (var portabilityUpdater = NewUpdateManager()) - { - portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu); - portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop); - portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup); - } + using var portabilityUpdater = NewUpdateManager(); + portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu); + portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop); + portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup); } public void RemoveUninstallerEntry() { - using (var portabilityUpdater = NewUpdateManager()) - { - portabilityUpdater.RemoveUninstallerRegistryEntry(); - } + using var portabilityUpdater = NewUpdateManager(); + portabilityUpdater.RemoveUninstallerRegistryEntry(); } public void MoveUserDataFolder(string fromLocation, string toLocation) @@ -110,12 +106,10 @@ namespace Flow.Launcher.Core.Configuration public void CreateShortcuts() { - using (var portabilityUpdater = NewUpdateManager()) - { - portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu, false); - portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop, false); - portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup, false); - } + using var portabilityUpdater = NewUpdateManager(); + portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.StartMenu, false); + portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Desktop, false); + portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup, false); } public void CreateUninstallerEntry() @@ -129,18 +123,14 @@ namespace Flow.Launcher.Core.Configuration subKey2.SetValue("DisplayIcon", Path.Combine(Constant.ApplicationDirectory, "app.ico"), RegistryValueKind.String); } - using (var portabilityUpdater = NewUpdateManager()) - { - _ = portabilityUpdater.CreateUninstallerRegistryEntry(); - } + using var portabilityUpdater = NewUpdateManager(); + _ = portabilityUpdater.CreateUninstallerRegistryEntry(); } - internal void IndicateDeletion(string filePathTodelete) + private static void IndicateDeletion(string filePathTodelete) { var deleteFilePath = Path.Combine(filePathTodelete, DataLocation.DeletionIndicatorFile); - using (var _ = File.CreateText(deleteFilePath)) - { - } + using var _ = File.CreateText(deleteFilePath); } /// From 2f53a79a26fc84cb012d580a37c9c2bab7eb7965 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 3 Apr 2025 22:56:31 +0800 Subject: [PATCH 19/33] Revert "Fix environment exit" This reverts commit 5d16216a5519a42c6f201219ddca60ef24289308. --- Flow.Launcher.Core/Configuration/Portable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs index 8abdae8d8..2b570d2c0 100644 --- a/Flow.Launcher.Core/Configuration/Portable.cs +++ b/Flow.Launcher.Core/Configuration/Portable.cs @@ -159,7 +159,7 @@ namespace Flow.Launcher.Core.Configuration { FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s)); - Application.Current.Shutdown(); + Environment.Exit(0); } } // Otherwise, if the portable data folder is marked for deletion, From b725975b9898e249a7382171cf2edb07437871d0 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 3 Apr 2025 23:01:16 +0800 Subject: [PATCH 20/33] Fix environment exit stuck issue --- Flow.Launcher/App.xaml.cs | 8 ++++++++ Flow.Launcher/MainWindow.xaml.cs | 13 +++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 9aee56bff..f484d4dba 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -304,6 +304,14 @@ namespace Flow.Launcher return; } + // If we call Environment.Exit(0), the application dispose will be called before _mainWindow.Close() + // Accessing _mainWindow?.Dispatcher will cause the application stuck + // So here we need to check it and just return so that we will not acees _mainWindow?.Dispatcher + if (!_mainWindow.CanClose) + { + return; + } + _disposed = true; } diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 011d46d6b..c62606743 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -32,6 +32,13 @@ namespace Flow.Launcher { public partial class MainWindow : IDisposable { + #region Public Property + + // Window Event: Close Event + public bool CanClose { get; set; } = false; + + #endregion + #region Private Fields // Dependency Injection @@ -45,8 +52,6 @@ namespace Flow.Launcher private readonly ContextMenu _contextMenu = new(); private readonly MainViewModel _viewModel; - // Window Event: Close Event - private bool _canClose = false; // Window Event: Key Event private bool _isArrowKeyPressed = false; @@ -279,7 +284,7 @@ namespace Flow.Launcher private async void OnClosing(object sender, CancelEventArgs e) { - if (!_canClose) + if (!CanClose) { _notifyIcon.Visible = false; App.API.SaveAppAllSettings(); @@ -287,7 +292,7 @@ namespace Flow.Launcher await PluginManager.DisposePluginsAsync(); Notification.Uninstall(); // After plugins are all disposed, we can close the main window - _canClose = true; + CanClose = true; // Use this instead of Close() to avoid InvalidOperationException when calling Close() in OnClosing event Application.Current.Shutdown(); } From 95b38d21af7b8790659d9eb49e2edbbba9a037b1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 09:57:03 +0800 Subject: [PATCH 21/33] Wait image cache saved before restarting --- Flow.Launcher.Infrastructure/Image/ImageLoader.cs | 8 +++++++- Flow.Launcher/PublicAPIInstance.cs | 7 +++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index 6f7b1cd90..0ba059b7b 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -61,7 +61,7 @@ namespace Flow.Launcher.Infrastructure.Image }); } - public static async Task Save() + public static async Task SaveAsync() { await storageLock.WaitAsync(); @@ -77,6 +77,12 @@ namespace Flow.Launcher.Infrastructure.Image } } + public static async Task WaitSaveAsync() + { + await storageLock.WaitAsync(); + storageLock.Release(); + } + private static async Task> LoadStorageToConcurrentDictionaryAsync() { await storageLock.WaitAsync(); diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index e19ad2fdc..b86e731b3 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -57,7 +57,7 @@ namespace Flow.Launcher _mainVM.ChangeQueryText(query, requery); } - public void RestartApp() + public async void RestartApp() { _mainVM.Hide(); @@ -66,6 +66,9 @@ namespace Flow.Launcher // which will cause ungraceful exit SaveAppAllSettings(); + // wait for all image caches to be saved + await ImageLoader.WaitSaveAsync(); + // Restart requires Squirrel's Update.exe to be present in the parent folder, // it is only published from the project's release pipeline. When debugging without it, // the project may not restart or just terminates. This is expected. @@ -88,7 +91,7 @@ namespace Flow.Launcher PluginManager.Save(); _mainVM.Save(); _settings.Save(); - _ = ImageLoader.Save(); + _ = ImageLoader.SaveAsync(); } public Task ReloadAllPluginData() => PluginManager.ReloadDataAsync(); From e4577eb23edbe6ce4e13154d2588d9e42e494764 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 10:02:47 +0800 Subject: [PATCH 22/33] Improve code comment --- Flow.Launcher/PublicAPIInstance.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index b86e731b3..a9862c74c 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -57,16 +57,18 @@ namespace Flow.Launcher _mainVM.ChangeQueryText(query, requery); } +#pragma warning disable VSTHRD100 // Avoid async void methods + public async void RestartApp() { _mainVM.Hide(); - // we must manually save + // We must manually save // UpdateManager.RestartApp() will call Environment.Exit(0) // which will cause ungraceful exit SaveAppAllSettings(); - // wait for all image caches to be saved + // Wait for all image caches to be saved before restarting await ImageLoader.WaitSaveAsync(); // Restart requires Squirrel's Update.exe to be present in the parent folder, @@ -75,6 +77,8 @@ namespace Flow.Launcher UpdateManager.RestartApp(Constant.ApplicationFileName); } +#pragma warning restore VSTHRD100 // Avoid async void methods + public void ShowMainWindow() => _mainVM.Show(); public void HideMainWindow() => _mainVM.Hide(); From 043fe76a613a5768bcd0e983acb555c58a8d681f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 10:03:19 +0800 Subject: [PATCH 23/33] Add settings save lock --- Flow.Launcher/PublicAPIInstance.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index a9862c74c..d88eeb7c9 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -37,6 +37,8 @@ namespace Flow.Launcher private readonly Internationalization _translater; private readonly MainViewModel _mainVM; + private readonly object _saveSettingsLock = new(); + #region Constructor public PublicAPIInstance(Settings settings, Internationalization translater, MainViewModel mainVM) @@ -92,9 +94,12 @@ namespace Flow.Launcher public void SaveAppAllSettings() { - PluginManager.Save(); - _mainVM.Save(); - _settings.Save(); + lock (_saveSettingsLock) + { + _settings.Save(); + PluginManager.Save(); + _mainVM.Save(); + } _ = ImageLoader.SaveAsync(); } From 95a3fd36dea778911d0f4f8b9a434e4813096b6a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 10:34:59 +0800 Subject: [PATCH 24/33] Do not crash when caught exception on saving settings --- .../Plugin/JsonRPCPluginSettings.cs | 20 +++++++++-- .../Storage/FlowLauncherJsonStorage.cs | 35 ++++++++++++++++++- .../Storage/PluginJsonStorage.cs | 33 +++++++++++++++++ 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs index 944b2fd10..e0a217251 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs @@ -23,6 +23,8 @@ namespace Flow.Launcher.Core.Plugin protected ConcurrentDictionary Settings { get; set; } = null!; public required IPublicAPI API { get; init; } + private static readonly string ClassName = nameof(JsonRPCPluginSettings); + private JsonStorage> _storage = null!; private static readonly Thickness SettingPanelMargin = (Thickness)Application.Current.FindResource("SettingPanelMargin"); @@ -122,12 +124,26 @@ namespace Flow.Launcher.Core.Plugin public async Task SaveAsync() { - await _storage.SaveAsync(); + try + { + await _storage.SaveAsync(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save plugin settings to path: {SettingPath}", e); + } } public void Save() { - _storage.Save(); + try + { + _storage.Save(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save plugin settings to path: {SettingPath}", e); + } } public bool NeedCreateSettingPanel() diff --git a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs index 865041fb3..a3634a0e2 100644 --- a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs @@ -1,10 +1,19 @@ using System.IO; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Infrastructure.Storage { public class FlowLauncherJsonStorage : JsonStorage where T : new() { + private static readonly string ClassName = "FlowLauncherJsonStorage"; + + // We should not initialize API in static constructor because it will create another API instance + private static IPublicAPI api = null; + private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService(); + public FlowLauncherJsonStorage() { var directoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName); @@ -13,5 +22,29 @@ namespace Flow.Launcher.Infrastructure.Storage var filename = typeof(T).Name; FilePath = Path.Combine(directoryPath, $"{filename}{FileSuffix}"); } + + public new void Save() + { + try + { + base.Save(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save FL settings to path: {FilePath}", e); + } + } + + public new async Task SaveAsync() + { + try + { + await base.SaveAsync(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save FL settings to path: {FilePath}", e); + } + } } -} \ No newline at end of file +} diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index b377c81aa..e02d51bdb 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -1,5 +1,8 @@ using System.IO; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Infrastructure.Storage { @@ -8,6 +11,12 @@ namespace Flow.Launcher.Infrastructure.Storage // Use assembly name to check which plugin is using this storage public readonly string AssemblyName; + private static readonly string ClassName = "PluginJsonStorage"; + + // We should not initialize API in static constructor because it will create another API instance + private static IPublicAPI api = null; + private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService(); + public PluginJsonStorage() { // C# related, add python related below @@ -23,5 +32,29 @@ namespace Flow.Launcher.Infrastructure.Storage { Data = data; } + + public new void Save() + { + try + { + base.Save(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save plugin settings to path: {FilePath}", e); + } + } + + public new async Task SaveAsync() + { + try + { + await base.SaveAsync(); + } + catch (System.Exception e) + { + API.LogException(ClassName, $"Failed to save plugin settings to path: {FilePath}", e); + } + } } } From f6e3608f72ab28c48bf8563ea3bb58af7b9950bb Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 10:42:48 +0800 Subject: [PATCH 25/33] Do not crash when saving cache --- Flow.Launcher.Infrastructure/Image/ImageLoader.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index 0ba059b7b..1ee033821 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -71,6 +71,10 @@ namespace Flow.Launcher.Infrastructure.Image .Select(x => x.Key) .ToList()); } + catch (System.Exception e) + { + Log.Exception($"|ImageLoader.SaveAsync|Failed to save image cache to file", e); + } finally { storageLock.Release(); From 2d6667bb53549c5580004fe194b56b90d20cdcd7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 10:42:55 +0800 Subject: [PATCH 26/33] Test save error --- Flow.Launcher.Infrastructure/Storage/JsonStorage.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 40106acd8..52bcdcfab 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -180,20 +180,24 @@ namespace Flow.Launcher.Infrastructure.Storage public void Save() { - string serialized = JsonSerializer.Serialize(Data, + throw new NotImplementedException("Save error"); + + /*string serialized = JsonSerializer.Serialize(Data, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(TempFilePath, serialized); - AtomicWriteSetting(); + AtomicWriteSetting();*/ } public async Task SaveAsync() { - await using var tempOutput = File.OpenWrite(TempFilePath); + throw new NotImplementedException("SaveAsync error"); + + /*await using var tempOutput = File.OpenWrite(TempFilePath); await JsonSerializer.SerializeAsync(tempOutput, Data, new JsonSerializerOptions { WriteIndented = true }); - AtomicWriteSetting(); + AtomicWriteSetting();*/ } private void AtomicWriteSetting() From c2f8480c049a4a818831c05558080907f2bac8d0 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:15:13 +0800 Subject: [PATCH 27/33] Revert "Test save error" This reverts commit 2d6667bb53549c5580004fe194b56b90d20cdcd7. --- Flow.Launcher.Infrastructure/Storage/JsonStorage.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 52bcdcfab..40106acd8 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -180,24 +180,20 @@ namespace Flow.Launcher.Infrastructure.Storage public void Save() { - throw new NotImplementedException("Save error"); - - /*string serialized = JsonSerializer.Serialize(Data, + string serialized = JsonSerializer.Serialize(Data, new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(TempFilePath, serialized); - AtomicWriteSetting();*/ + AtomicWriteSetting(); } public async Task SaveAsync() { - throw new NotImplementedException("SaveAsync error"); - - /*await using var tempOutput = File.OpenWrite(TempFilePath); + await using var tempOutput = File.OpenWrite(TempFilePath); await JsonSerializer.SerializeAsync(tempOutput, Data, new JsonSerializerOptions { WriteIndented = true }); - AtomicWriteSetting();*/ + AtomicWriteSetting(); } private void AtomicWriteSetting() From 2a2ef234d952be3bc44507f95248b1622b92256d Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:17:30 +0800 Subject: [PATCH 28/33] Fix typos Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Infrastructure/Win32Helper.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 42461dc18..f2b99588d 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -489,8 +489,7 @@ namespace Flow.Launcher.Infrastructure #endregion - #region Noticification - + #region Notification public static bool IsNotificationSupport() { // Noticification only supported Windows 10 19041+ From 834780d6e7d57577a59f35c0ad5715f99e7b61cf Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:17:37 +0800 Subject: [PATCH 29/33] Fix typos Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Infrastructure/Win32Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index f2b99588d..5bec3e5e7 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -492,7 +492,7 @@ namespace Flow.Launcher.Infrastructure #region Notification public static bool IsNotificationSupport() { - // Noticification only supported Windows 10 19041+ + // Notification only supported Windows 10 19041+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.OSVersion.Version.Build >= 19041; } From 8df1e6a0ce9977346327c9e9249ef2359c3a9ad1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:18:57 +0800 Subject: [PATCH 30/33] Add blank line --- Flow.Launcher.Infrastructure/Win32Helper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 5bec3e5e7..d3023a3f0 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -490,6 +490,7 @@ namespace Flow.Launcher.Infrastructure #endregion #region Notification + public static bool IsNotificationSupport() { // Notification only supported Windows 10 19041+ From 3283adce59384003887d5d91dfa767ca6822c92e Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:27:10 +0800 Subject: [PATCH 31/33] Fix typos Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- Flow.Launcher.Infrastructure/Win32Helper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index d3023a3f0..c21849403 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -491,9 +491,9 @@ namespace Flow.Launcher.Infrastructure #region Notification - public static bool IsNotificationSupport() + public static bool IsNotificationSupported() { - // Notification only supported Windows 10 19041+ + // Notifications only supported on Windows 10 19041+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.OSVersion.Version.Build >= 19041; } From ec7a4e8aaa1463524ae0cacebceb5ec7f89e94b8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:27:50 +0800 Subject: [PATCH 32/33] Fix build issue --- Flow.Launcher/Notification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Notification.cs b/Flow.Launcher/Notification.cs index 23125de15..30b3a0673 100644 --- a/Flow.Launcher/Notification.cs +++ b/Flow.Launcher/Notification.cs @@ -9,7 +9,7 @@ namespace Flow.Launcher { internal static class Notification { - internal static bool legacy = !Win32Helper.IsNotificationSupport(); + internal static bool legacy = !Win32Helper.IsNotificationSupported(); internal static void Uninstall() { From 28ab71f11a60304db888c465e871c24be5b18ab5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 4 Apr 2025 11:46:07 +0800 Subject: [PATCH 33/33] Fix build issue --- Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs | 1 + Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs index 0fbeed9f5..8b4062b6b 100644 --- a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Infrastructure.Storage { diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index 910672119..e8cbd70fb 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; +using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Infrastructure.Storage {