Repository: Flow-Launcher/Flow.Launcher
Pull request #3411: Add clean cache option & Add exception handler for cleaning folders
Author: login: Jack251970
Labels: name: enhancement
description: New feature or request
Created: 2025-04-01T12:13:58Z | Merged: 2025-04-02T10:57:41Z

![image](https://github.com/user-attachments/assets/e3a4c974-fb52-405a-a225-c9b4dbd8e5a3)



Diff:
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 2df430c3b67..24ab3cf9477 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -325,6 +325,9 @@
     <system:String x:Key="logfolder">Log Folder</system:String>
     <system:String x:Key="clearlogfolder">Clear Logs</system:String>
     <system:String x:Key="clearlogfolderMessage">Are you sure you want to delete all logs?</system:String>
+    <system:String x:Key="clearcachefolder">Clear Caches</system:String>
+    <system:String x:Key="clearcachefolderMessage">Are you sure you want to delete all caches?</system:String>
+    <system:String x:Key="clearfolderfailMessage">Failed to clear part of folders and files. Please see log file for more information</system:String>
     <system:String x:Key="welcomewindow">Wizard</system:String>
     <system:String x:Key="userdatapath">User Data Location</system:String>
     <system:String x:Key="userdatapathToolTip">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.</system:String>
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
index 20f905411d2..6cfb9830656 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
@@ -6,7 +6,6 @@
 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;
@@ -16,6 +15,8 @@ namespace Flow.Launcher.SettingPages.ViewModels;
 
 public partial class SettingsPaneAboutViewModel : BaseModel
 {
+    private static readonly string ClassName = nameof(SettingsPaneAboutViewModel);
+
     private readonly Settings _settings;
     private readonly Updater _updater;
 
@@ -24,7 +25,16 @@ public string LogFolderSize
         get
         {
             var size = GetLogFiles().Sum(file => file.Length);
-            return $"{InternationalizationManager.Instance.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})";
+            return $"{App.API.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})";
+        }
+    }
+
+    public string CacheFolderSize
+    {
+        get
+        {
+            var size = GetCacheFiles().Sum(file => file.Length);
+            return $"{App.API.GetTranslation("clearcachefolder")} ({BytesToReadableString(size)})";
         }
     }
 
@@ -42,7 +52,7 @@ public string LogFolderSize
     };
 
     public string ActivatedTimes => string.Format(
-        InternationalizationManager.Instance.GetTranslation("about_activate_times"),
+        App.API.GetTranslation("about_activate_times"),
         _settings.ActivateTimes
     );
 
@@ -88,14 +98,35 @@ private void OpenWelcomeWindow()
     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
         );
 
         if (confirmResult == MessageBoxResult.Yes)
         {
-            ClearLogFolder();
+            if (!ClearLogFolder())
+            {
+                App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
+            }
+        }
+    }
+
+    [RelayCommand]
+    private void AskClearCacheFolderConfirmation()
+    {
+        var confirmResult = App.API.ShowMsgBox(
+            App.API.GetTranslation("clearcachefolderMessage"),
+            App.API.GetTranslation("clearcachefolder"),
+            MessageBoxButton.YesNo
+        );
+
+        if (confirmResult == MessageBoxResult.Yes)
+        {
+            if (!ClearCacheFolder())
+            {
+                App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
+            }
         }
     }
 
@@ -113,7 +144,6 @@ private void OpenParentOfSettingsFolder(object parameter)
         App.API.OpenDirectory(parentFolderPath);
     }
 
-
     [RelayCommand]
     private void OpenLogsFolder()
     {
@@ -121,21 +151,47 @@ private void OpenLogsFolder()
     }
 
     [RelayCommand]
-    private Task UpdateApp() => _updater.UpdateAppAsync(false);
+    private Task UpdateAppAsync() => _updater.UpdateAppAsync(false);
 
-    private void ClearLogFolder()
+    private bool ClearLogFolder()
     {
+        var success = true;
         var logDirectory = GetLogDir();
         var logFiles = GetLogFiles();
 
-        logFiles.ForEach(f => f.Delete());
+        logFiles.ForEach(f =>
+        {
+            try
+            {
+                f.Delete();
+            }
+            catch (Exception e)
+            {
+                App.API.LogException(ClassName, $"Failed to delete log file: {f.Name}", e);
+                success = false;
+            }
+        });
 
         logDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
+            // Do not clean log files of current version
             .Where(dir => !Constant.Version.Equals(dir.Name))
             .ToList()
-            .ForEach(dir => dir.Delete());
+            .ForEach(dir =>
+            {
+                try
+                {
+                    dir.Delete(true);
+                }
+                catch (Exception e)
+                {
+                    App.API.LogException(ClassName, $"Failed to delete log directory: {dir.Name}", e);
+                    success = false;
+                }
+            });
 
         OnPropertyChanged(nameof(LogFolderSize));
+
+        return success;
     }
 
     private static DirectoryInfo GetLogDir(string version = "")
@@ -148,6 +204,55 @@ private static List<FileInfo> GetLogFiles(string version = "")
         return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList();
     }
 
+    private bool ClearCacheFolder()
+    {
+        var success = true;
+        var cacheDirectory = GetCacheDir();
+        var cacheFiles = GetCacheFiles();
+
+        cacheFiles.ForEach(f =>
+        {
+            try
+            {
+                f.Delete();
+            }
+            catch (Exception e)
+            {
+                App.API.LogException(ClassName, $"Failed to delete cache file: {f.Name}", e);
+                success = false;
+            }
+        });
+
+        cacheDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
+            .ToList()
+            .ForEach(dir =>
+            {
+                try
+                {
+                    dir.Delete(true);
+                }
+                catch (Exception e)
+                {
+                    App.API.LogException(ClassName, $"Failed to delete cache directory: {dir.Name}", e);
+                    success = false;
+                }
+            });
+
+        OnPropertyChanged(nameof(CacheFolderSize));
+
+        return success;
+    }
+
+    private static DirectoryInfo GetCacheDir()
+    {
+        return new DirectoryInfo(DataLocation.CacheDirectory);
+    }
+
+    private static List<FileInfo> GetCacheFiles()
+    {
+        return GetCacheDir().EnumerateFiles("*", SearchOption.AllDirectories).ToList();
+    }
+
     private static string BytesToReadableString(long bytes)
     {
         const int scale = 1024;
@@ -156,8 +261,7 @@ private static string BytesToReadableString(long bytes)
 
         foreach (string order in orders)
         {
-            if (bytes > max)
-                return $"{decimal.Divide(bytes, max):##.##} {order}";
+            if (bytes > max) return $"{decimal.Divide(bytes, max):##.##} {order}";
 
             max /= scale;
         }
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml
index 75c51341133..f7deee7cfdc 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="&#xf12b;">
                 <StackPanel Orientation="Horizontal">
+                    <Button
+                        Margin="0 0 12 0"
+                        Command="{Binding AskClearCacheFolderConfirmationCommand}"
+                        Content="{Binding CacheFolderSize, Mode=OneWay}" />
                     <Button
                         Margin="0 0 12 0"
                         Command="{Binding AskClearLogFolderConfirmationCommand}"


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds a new clean cache option to the settings view, updating translation calls across the board and introducing functionality for clearing the cache folder.  
- Updated translation calls to use App.API.GetTranslation  
- Added a new CacheFolderSize property to display the cache size  
- Introduced AskClearCacheFolderConfirmation and supporting methods to clear the cache folder

<details>
<summary>Files not reviewed (2)</summary>

* **Flow.Launcher/Languages/en.xaml**: Language not supported
* **Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:173**
* Consider checking if the cache directory exists (e.g. using cacheDirectory.Exists) before enumerating files and directories to avoid potential runtime exceptions when the directory is missing.
```
private void ClearCacheFolder()
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:14:34Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (1)</summary><blockquote>

`149-161`: **Refactor duplicated code in folder clearing methods.**

The `ClearLogFolder` and `ClearCacheFolder` methods contain very similar code with only minor differences, which introduces maintenance challenges.

Consider refactoring to a more generic method:

```diff
+ private void ClearFolder(DirectoryInfo directory, Func<List<FileInfo>> getFiles, string propertyToUpdate, bool deleteSubdirectories = false, Func<DirectoryInfo, bool> directoryFilter = null)
+ {
+     var files = getFiles();
+     
+     try {
+         files.ForEach(f => {
+             try {
+                 f.Delete();
+             } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) {
+                 Log.Error($"Failed to delete file {f.FullName}: {ex.Message}", ex);
+             }
+         });
+         
+         var directories = directory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly);
+         if (directoryFilter != null)
+             directories = directories.Where(directoryFilter);
+             
+         directories.ToList().ForEach(dir => {
+             try {
+                 dir.Delete(deleteSubdirectories);
+             } catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) {
+                 Log.Error($"Failed to delete directory {dir.FullName}: {ex.Message}", ex);
+             }
+         });
+     } finally {
+         OnPropertyChanged(propertyToUpdate);
+     }
+ }
+
- private void ClearLogFolder()
- {
-     var logDirectory = GetLogDir();
-     var logFiles = GetLogFiles();
-
-     logFiles.ForEach(f => f.Delete());
-
-     logDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
-         .Where(dir => !Constant.Version.Equals(dir.Name))
-         .ToList()
-         .ForEach(dir => dir.Delete());
-
-     OnPropertyChanged(nameof(LogFolderSize));
- }
+ private void ClearLogFolder()
+ {
+     ClearFolder(
+         GetLogDir(), 
+         GetLogFiles, 
+         nameof(LogFolderSize),
+         false,
+         dir => !Constant.Version.Equals(dir.Name));
+ }

- 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 void ClearCacheFolder()
+ {
+     ClearFolder(
+         GetCacheDir(), 
+         GetCacheFiles, 
+         nameof(CacheFolderSize),
+         true);
+ }
```

This refactoring reduces code duplication, adds error handling, and makes future maintenance easier.


Also applies to: 173-185

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a3c18a6e3b2c7827038a030364fe07dfe55515e9 and 482fdc939f9fd01dfdd4b75f485e30768c43e63d.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `Flow.Launcher/Languages/en.xaml` (1 hunks)
* `Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs` (6 hunks)
* `Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (4)</summary><blockquote>

<details>
<summary>Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs (4)</summary>

* `RelayCommand` (241-251)
* `RelayCommand` (253-263)
* `RelayCommand` (265-270)
* `RelayCommand` (272-277)

</details>
<details>
<summary>Flow.Launcher/ViewModel/PluginViewModel.cs (7)</summary>

* `RelayCommand` (153-158)
* `RelayCommand` (160-166)
* `RelayCommand` (168-172)
* `RelayCommand` (174-179)
* `RelayCommand` (181-186)
* `RelayCommand` (188-193)
* `Task` (46-50)

</details>
<details>
<summary>Flow.Launcher/ViewModel/MainViewModel.cs (10)</summary>

* `RelayCommand` (272-280)
* `RelayCommand` (282-294)
* `RelayCommand` (296-304)
* `RelayCommand` (313-324)
* `RelayCommand` (326-337)
* `RelayCommand` (339-353)
* `Task` (259-270)
* `Task` (641-668)
* `Task` (900-927)
* `Task` (951-955)

</details>
<details>
<summary>Flow.Launcher.Core/Plugin/PluginManager.cs (11)</summary>

* `Task` (78-89)
* `Task` (91-99)
* `Task` (101-108)
* `Task` (110-117)
* `Task` (119-126)
* `Task` (187-244)
* `Task` (260-302)
* `Task` (467-472)
* `Task` (485-488)
* `Task` (568-635)
* `List` (335-362)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (2)</summary>

* GitHub Check: gitStream.cm
* GitHub Check: gitStream.cm

</details>

<details>
<summary>🔇 Additional comments (8)</summary><blockquote>

<details>
<summary>Flow.Launcher/Languages/en.xaml (1)</summary>

`328-329`: **New string resources added for cache cleaning feature.**

The new string resources follow the same pattern as existing log clearing resources, providing clear and consistent messaging for the new cache clearing functionality.

</details>
<details>
<summary>Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml (1)</summary>

`93-96`: **New button for clearing cache added.**

The button is properly positioned alongside the existing log clearing button, with consistent margin and binding pattern. It uses the CacheFolderSize property to display the current size of the cache.

</details>
<details>
<summary>Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs (6)</summary>

`22-28`: **Translation API method updated.**

Changed from using `InternationalizationManager.Instance.GetTranslation` to `App.API.GetTranslation` for consistent API usage throughout the application.

---

`30-36`: **New CacheFolderSize property added.**

The property calculates the total size of all cache files using the same pattern as LogFolderSize, providing a consistent user experience.

---

`53-53`: **Translation API method updated.**

Consistent update from `InternationalizationManager.Instance.GetTranslation` to `App.API.GetTranslation`.

---

`99-100`: **Translation API method updated.**

Consistent update from `InternationalizationManager.Instance.GetTranslation` to `App.API.GetTranslation`.

---

`110-123`: **New method added for confirming cache folder clearing.**

The method follows the same pattern as the existing log folder confirmation, providing a consistent user experience.

---

`146-146`: **Method signature changed to indicate async operation.**

The method signature has been updated from `UpdateApp` to `UpdateAppAsync` to better reflect its asynchronous nature.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:17:23Z
user: login: onesounds
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:42:17Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds a clean cache option and introduces exception handling for cleaning folders, while also updating translation calls from InternationalizationManager to App.API.  
- Replaces translation calls for internationalized strings  
- Adds a new CacheFolderSize property and methods for clearing cache and retrieving cache files  
- Introduces exception handling in folder cleaning methods and renames a method for clarity

<details>
<summary>Files not reviewed (2)</summary>

* **Flow.Launcher/Languages/en.xaml**: Language not supported
* **Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:162**
* The method has been renamed to 'UpdateAppAsync' to reflect its asynchronous behavior; please ensure that all command bindings and invocations are updated accordingly.
```
private Task UpdateAppAsync() => _updater.UpdateAppAsync(false);
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T12:57:05Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request introduces a clean cache option and robust error handling for the cleaning of log and cache folders. Key changes include replacing translations from InternationalizationManager with App.API, adding a new property and confirmation command for cleaning the cache folder, and incorporating try-catch error handling for file and directory deletions.

<details>
<summary>Files not reviewed (2)</summary>

* **Flow.Launcher/Languages/en.xaml**: Language not supported
* **Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:183**
* In ClearLogFolder the deletion of directories uses a non-recursive Delete() method, while ClearCacheFolder uses dir.Delete(true) for recursive deletion. Please verify that this difference is intentional to ensure consistent folder cleaning behavior.
```
dir.Delete();
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T02:12:00Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR introduces an option to clean the cache and enhances error handling during folder clean-up operations. Key changes include:
- Removing the unused resource import and updating translation calls to use App.API.
- Adding a new CacheFolderSize property along with a ClearCacheFolder() method to handle cache cleaning with exception handling.
- Renaming the asynchronous update method to UpdateAppAsync and incorporating improved error handling in log folder deletion.

<details>
<summary>Files not reviewed (2)</summary>

* **Flow.Launcher/Languages/en.xaml**: Language not supported
* **Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:154**
* Ensure that all callers and bindings referring to the previous UpdateApp method are updated to use the new UpdateAppAsync name for consistency with asynchronous conventions.
```
private Task UpdateAppAsync() => _updater.UpdateAppAsync(false);
```
**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:170**
* [nitpick] Consider catching more specific exceptions rather than a generic Exception in the log file deletion block to handle expected file system errors more accurately.
```
App.API.LogException(ClassName, "Failed to delete log file: {f.Name}", e);
```
**Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs:236**
* [nitpick] Consider catching more specific exceptions rather than a generic Exception in the cache directory deletion block to better distinguish and manage different error conditions.
```
App.API.LogException(ClassName, "Failed to delete cache directory: {dir.Name}", e);
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T02:13:33Z
user: login: onesounds
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T10:57:40Z

Review comments:
diff_hunk: @@ -99,6 +107,21 @@ private void AskClearLogFolderConfirmation()
         }
     }
 
+    [RelayCommand]
+    private void AskClearCacheFolderConfirmation()
+    {
+        var confirmResult = App.API.ShowMsgBox(
+            App.API.GetTranslation("clearcachefolderMessage"),
+            App.API.GetTranslation("clearcachefolder"),
+            MessageBoxButton.YesNo
+        );
+
+        if (confirmResult == MessageBoxResult.Yes)
+        {
+            ClearCacheFolder();
path: Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
user: login: Copilot
body: Consider wrapping the ClearCacheFolder() call in a try-catch block to gracefully handle any exceptions that may occur during file deletion.
```suggestion
            try
            {
                ClearCacheFolder();
            }
            catch (Exception ex)
            {
                Log.Error("SettingsPaneAboutViewModel", "Failed to clear cache folder", ex);
                App.API.ShowMsgBox(
                    App.API.GetTranslation("clearcachefolderErrorMessage"),
                    App.API.GetTranslation("clearcachefolderError"),
                    MessageBoxButton.OK
                );
            }
```
created_at: 2025-04-01T12:14:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -148,6 +170,30 @@ private static List<FileInfo> GetLogFiles(string version = "")
         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<FileInfo> GetCacheFiles()
+    {
+        return GetCacheDir().EnumerateFiles("*", SearchOption.AllDirectories).ToList();
+    }
path: Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add error handling to cache clearing operations.**

The cache clearing methods don't include any error handling for file operations. If a file is locked or cannot be deleted for any reason, this could cause the application to crash.

Consider adding try-catch blocks to handle potential IO exceptions:

```diff
private void ClearCacheFolder()
{
    var cacheDirectory = GetCacheDir();
    var cacheFiles = GetCacheFiles();

-   cacheFiles.ForEach(f => f.Delete());
+   cacheFiles.ForEach(f => {
+       try {
+           f.Delete();
+       } catch (IOException ex) {
+           Log.Error($"Failed to delete cache file {f.FullName}: {ex.Message}", ex);
+       } catch (UnauthorizedAccessException ex) {
+           Log.Error($"Access denied when deleting cache file {f.FullName}: {ex.Message}", ex);
+       }
+   });

-   cacheDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
-       .ToList()
-       .ForEach(dir => dir.Delete(true));
+   cacheDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
+       .ToList()
+       .ForEach(dir => {
+           try {
+               dir.Delete(true);
+           } catch (IOException ex) {
+               Log.Error($"Failed to delete cache directory {dir.FullName}: {ex.Message}", ex);
+           } catch (UnauthorizedAccessException ex) {
+               Log.Error($"Access denied when deleting cache directory {dir.FullName}: {ex.Message}", ex);
+           }
+       });

    OnPropertyChanged(nameof(CacheFolderSize));
}
```

The same improvements should also be applied to the `ClearLogFolder` method for consistency.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    private void ClearCacheFolder()
    {
        var cacheDirectory = GetCacheDir();
        var cacheFiles = GetCacheFiles();

        cacheFiles.ForEach(f => {
            try {
                f.Delete();
            } catch (IOException ex) {
                Log.Error($"Failed to delete cache file {f.FullName}: {ex.Message}", ex);
            } catch (UnauthorizedAccessException ex) {
                Log.Error($"Access denied when deleting cache file {f.FullName}: {ex.Message}", ex);
            }
        });

        cacheDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
            .ToList()
            .ForEach(dir => {
                try {
                    dir.Delete(true);
                } catch (IOException ex) {
                    Log.Error($"Failed to delete cache directory {dir.FullName}: {ex.Message}", ex);
                } catch (UnauthorizedAccessException ex) {
                    Log.Error($"Access denied when deleting cache directory {dir.FullName}: {ex.Message}", ex);
                }
            });

        OnPropertyChanged(nameof(CacheFolderSize));
    }

    private static DirectoryInfo GetCacheDir()
    {
        return new DirectoryInfo(DataLocation.CacheDirectory);
    }

    private static List<FileInfo> GetCacheFiles()
    {
        return GetCacheDir().EnumerateFiles("*", SearchOption.AllDirectories).ToList();
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-01T12:17:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -148,6 +186,30 @@ private static List<FileInfo> GetLogFiles(string version = "")
         return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList();
     }
 
+    private void ClearCacheFolder()
+    {
+        var cacheDirectory = GetCacheDir();
+        var cacheFiles = GetCacheFiles();
+
+        cacheFiles.ForEach(f => f.Delete());
+
path: Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs
user: login: Copilot
body: Deleting files using a lambda without individual error handling may lead to partial cache clearance if a deletion fails; consider iterating over the files with a try-catch block around each deletion for more granular error handling.
```suggestion
        foreach (var file in cacheFiles)
        {
            try
            {
                file.Delete();
            }
            catch (Exception ex)
            {
                // Log the exception or handle it as needed
                Log.Error($"Failed to delete cache file {file.FullName}: {ex.Message}");
            }
        }
```
created_at: 2025-04-01T12:57:05Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-01T12:14:43Z
body: 
# @check-spelling-bot Report
## :red_circle: Please review
### See the [:open_file_folder: files](https://github.com/Flow-Launcher/Flow.Launcher/pull/3411/files/) view, the [:scroll:action log](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14195301400/job/39768960576#step:4:1),  or [:memo: job summary](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14195301400/attempts/1#summary-39768960576) for details.

[:x: Errors](https://docs.check-spelling.dev/Event-descriptions) | Count
-|-
[:x: forbidden-pattern](https://docs.check-spelling.dev/Event-descriptions#forbidden-pattern) | 22
[:warning: non-alpha-in-dictionary](https://docs.check-spelling.dev/Event-descriptions#non-alpha-in-dictionary) | 19

See [:x: Event descriptions](https://docs.check-spelling.dev/Event-descriptions) for more information.

<!-- Because only_check_changed_files is active, checking for obsolete items cannot be performed-->

<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details><summary>If the flagged items are :exploding_head: false positives</summary>

If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).

  Please add a file path to the `excludes.txt` file matching the containing file.

  File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.

  `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).

* well-formed pattern.

  If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
  try adding it to the `patterns.txt` file.

  Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.

  Note that patterns can't match multiline strings.

</details>

author_association: NONE
user: login: gitstream-cm[bot]
created_at: 2025-04-01T12:14:58Z
body: 🥷 **Code experts: Yusyuriv, onesounds** 
 
Jack251970 has most 👩‍💻 **activity** in the files. 
Yusyuriv, Jack251970 have most 🧠 **knowledge** in the files. 
 <details>
 <summary>See details</summary>


`Flow.Launcher/Languages/en.xaml` 
 

Activity based on git-commit: 

 |  | Jack251970 |  
 | --- | --- | 
| APR | 5 additions & 0 deletions |  
| MAR | 67 additions & 42 deletions |  
| FEB | 15 additions & 9 deletions |  
| JAN | 1 additions & 0 deletions |  
| DEC |   |  
| NOV |   |  
 

Knowledge based on git-blame: 
 Jack251970: 10% 
Yusyuriv: 5% 

`Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs` 
 

Activity based on git-commit: 

 |  | Jack251970 |  
 | --- | --- | 
| APR |   |  
| MAR | 27 additions & 2 deletions |  
| FEB | 7 additions & 8 deletions |  
| JAN | 2 additions & 2 deletions |  
| DEC |   |  
| NOV | 2 additions & 3 deletions |  
 

Knowledge based on git-blame: 
 Yusyuriv: 75% 
Jack251970: 20% 

`Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml` 
 

Activity based on git-commit: 

 |  | Jack251970 |  
 | --- | --- | 
| APR |   |  
| MAR | 9 additions & 1 deletions |  
| FEB |   |  
| JAN |   |  
| DEC |   |  
| NOV |   |  
 

Knowledge based on git-blame: 
 Yusyuriv: 41% 
Jack251970: 6% 

</details>
 
 
 
 
To learn more about /:\ gitStream - [Visit our Docs](https://docs.gitstream.cm/) 
 
 

<automation id="gitstream/explain_code_experts"/>
author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-04-01T12:17:19Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Walkthrough
This pull request introduces enhancements to cache management in the application. Three new string resources related to cache clearing messages are added to the language file. The settings view model is updated with a new property for cache size and methods for prompting user confirmation and clearing the cache. Additionally, a new button is added in the view to trigger the cache clearing functionality, along with updates to localization calls and method names for consistency.

## Changes

| File(s)                                              | Change Summary                                                                                                                                                  |
|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Flow.Launcher/Languages/en.xaml`                    | Added three string resources: `clearcachefolder` ("Clear Caches"), `clearcachefolderMessage` ("Are you sure you want to delete all caches?"), and `clearfolderfailMessage` ("Failed to clear folders and files").              |
| `Flow.Launcher/SettingPages/…/SettingsPaneAboutViewModel.cs` &<br>`Flow.Launcher/SettingPages/…/SettingsPaneAbout.xaml` | Introduced cache clearing functionality: added `CacheFolderSize` property, new methods (`AskClearCacheFolderConfirmation`, `ClearCacheFolder`), updated localization calls, and modified the update method signature. A new button was added in the view to trigger the cache clearing confirmation. |

## Sequence Diagram(s)
```mermaid
sequenceDiagram
    participant User
    participant UI
    participant VM as ViewModel
    participant FS as FileSystem

    User->>UI: Click "Clear Caches" button
    UI->>VM: Execute AskClearCacheFolderConfirmationCommand
    VM->>User: Show confirmation dialog ("Are you sure you want to delete all caches?")
    User-->>VM: Confirm
    VM->>FS: Delete cache files
    FS-->>VM: Deletion complete
    VM->>UI: Update CacheFolderSize property
```

## Suggested labels
`enhancement`, `bug`, `kind/ui`, `5 min review`

## Suggested reviewers
- onesounds

## Poem
> I'm just a rabbit with a hop so spry,  
> Clearing caches as the bytes fly by.  
> With buttons clicked and code set free,  
> My burrow's neat, as neat as can be.  
> 🐇 Code and carrots, oh my!

</details>

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 35ea1e33a9d7be5ff0b45897dd8f795cd21eee4f and 7fc453330f08f33c8a87bbdc5cc5d1f7c38b2484.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `Flow.Launcher/Languages/en.xaml` (1 hunks)
* `Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs` (7 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* Flow.Launcher/Languages/en.xaml
* Flow.Launcher/SettingPages/ViewModels/SettingsPaneAboutViewModel.cs

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: gitStream workflow automation
* GitHub Check: gitStream.cm
* GitHub Check: gitStream.cm

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Flow-Launcher/Flow.Launcher&utm_content=3411):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-01T12:55:26Z
body: 
# @check-spelling-bot Report
## :red_circle: Please review
### See the [:open_file_folder: files](https://github.com/Flow-Launcher/Flow.Launcher/pull/3411/files/) view, the [:scroll:action log](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14196155447/job/39771651423#step:4:1),  or [:memo: job summary](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14196155447/attempts/1#summary-39771651423) for details.

[:x: Errors](https://docs.check-spelling.dev/Event-descriptions) | Count
-|-
[:x: forbidden-pattern](https://docs.check-spelling.dev/Event-descriptions#forbidden-pattern) | 22
[:warning: non-alpha-in-dictionary](https://docs.check-spelling.dev/Event-descriptions#non-alpha-in-dictionary) | 19

See [:x: Event descriptions](https://docs.check-spelling.dev/Event-descriptions) for more information.

<!-- Because only_check_changed_files is active, checking for obsolete items cannot be performed-->

<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details><summary>If the flagged items are :exploding_head: false positives</summary>

If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).

  Please add a file path to the `excludes.txt` file matching the containing file.

  File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.

  `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).

* well-formed pattern.

  If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
  try adding it to the `patterns.txt` file.

  Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.

  Note that patterns can't match multiline strings.

</details>

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-02T02:12:04Z
body: 
# @check-spelling-bot Report
## :red_circle: Please review
### See the [:open_file_folder: files](https://github.com/Flow-Launcher/Flow.Launcher/pull/3411/files/) view, the [:scroll:action log](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14209992109/job/39815291704#step:4:1),  or [:memo: job summary](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14209992109/attempts/1#summary-39815291704) for details.

[:x: Errors](https://docs.check-spelling.dev/Event-descriptions) | Count
-|-
[:x: forbidden-pattern](https://docs.check-spelling.dev/Event-descriptions#forbidden-pattern) | 22
[:warning: non-alpha-in-dictionary](https://docs.check-spelling.dev/Event-descriptions#non-alpha-in-dictionary) | 19

See [:x: Event descriptions](https://docs.check-spelling.dev/Event-descriptions) for more information.

<!-- Because only_check_changed_files is active, checking for obsolete items cannot be performed-->

<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details><summary>If the flagged items are :exploding_head: false positives</summary>

If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).

  Please add a file path to the `excludes.txt` file matching the containing file.

  File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.

  `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).

* well-formed pattern.

  If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
  try adding it to the `patterns.txt` file.

  Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.

  Note that patterns can't match multiline strings.

</details>

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-02T02:14:03Z
body: 
# @check-spelling-bot Report
## :red_circle: Please review
### See the [:open_file_folder: files](https://github.com/Flow-Launcher/Flow.Launcher/pull/3411/files/) view, the [:scroll:action log](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14210009357/job/39815340117#step:4:1),  or [:memo: job summary](https://github.com/Flow-Launcher/Flow.Launcher/actions/runs/14210009357/attempts/1#summary-39815340117) for details.

[:x: Errors](https://docs.check-spelling.dev/Event-descriptions) | Count
-|-
[:x: forbidden-pattern](https://docs.check-spelling.dev/Event-descriptions#forbidden-pattern) | 22
[:warning: non-alpha-in-dictionary](https://docs.check-spelling.dev/Event-descriptions#non-alpha-in-dictionary) | 19

See [:x: Event descriptions](https://docs.check-spelling.dev/Event-descriptions) for more information.

<!-- Because only_check_changed_files is active, checking for obsolete items cannot be performed-->

<!-- See https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples%3A-advice --> <!-- markdownlint-disable MD033 MD041 -->
<details><summary>If the flagged items are :exploding_head: false positives</summary>

If items relate to a ...
* binary file (or some other file you wouldn't want to check at all).

  Please add a file path to the `excludes.txt` file matching the containing file.

  File paths are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your files.

  `^` refers to the file's path from the root of the repository, so `^README\.md$` would exclude [README.md](
../tree/HEAD/README.md) (on whichever branch you're using).

* well-formed pattern.

  If you can write a [pattern](https://github.com/check-spelling/check-spelling/wiki/Configuration-Examples:-patterns) that would match it,
  try adding it to the `patterns.txt` file.

  Patterns are Perl 5 Regular Expressions - you can [test](
https://www.regexplanet.com/advanced/perl/) yours before committing to verify it will match your lines.

  Note that patterns can't match multiline strings.

</details>

author_association: NONE