Skip to content

Commit c351a38

Browse files
authored
Merge branch 'dev' into 250331-NewPluginsPage
2 parents d09899e + 8cc9f2d commit c351a38

File tree

31 files changed

+619
-256
lines changed

31 files changed

+619
-256
lines changed

Flow.Launcher.Core/Plugin/JsonRPCV2Models/JsonRPCPublicAPI.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models
1212
{
1313
public class JsonRPCPublicAPI
1414
{
15-
private IPublicAPI _api;
15+
private readonly IPublicAPI _api;
1616

1717
public JsonRPCPublicAPI(IPublicAPI api)
1818
{
@@ -104,7 +104,6 @@ public List<PluginPair> GetAllPlugins()
104104
return _api.GetAllPlugins();
105105
}
106106

107-
108107
public MatchResult FuzzySearch(string query, string stringToCompare)
109108
{
110109
return _api.FuzzySearch(query, stringToCompare);
@@ -156,6 +155,11 @@ public void LogWarn(string className, string message, [CallerMemberName] string
156155
_api.LogWarn(className, message, methodName);
157156
}
158157

158+
public void LogError(string className, string message, [CallerMemberName] string methodName = "")
159+
{
160+
_api.LogError(className, message, methodName);
161+
}
162+
159163
public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null)
160164
{
161165
_api.OpenDirectory(DirectoryPath, FileNameOrFilePath);
@@ -185,5 +189,10 @@ public void StopLoadingBar()
185189
{
186190
_api.StopLoadingBar();
187191
}
192+
193+
public void SavePluginCaches()
194+
{
195+
_api.SavePluginCaches();
196+
}
188197
}
189198
}

Flow.Launcher.Core/Plugin/PluginManager.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Flow.Launcher.Infrastructure.UserSettings;
1414
using Flow.Launcher.Plugin;
1515
using Flow.Launcher.Plugin.SharedCommands;
16+
using IRemovable = Flow.Launcher.Core.Storage.IRemovable;
1617
using ISavable = Flow.Launcher.Plugin.ISavable;
1718

1819
namespace Flow.Launcher.Core.Plugin
@@ -65,6 +66,7 @@ public static void Save()
6566
}
6667

6768
API.SavePluginSettings();
69+
API.SavePluginCaches();
6870
}
6971

7072
public static async ValueTask DisposePluginsAsync()
@@ -575,11 +577,11 @@ internal static async Task UninstallPluginAsync(PluginMetadata plugin, bool remo
575577

576578
if (removePluginSettings)
577579
{
578-
// For dotnet plugins, we need to remove their PluginJsonStorage instance
579-
if (AllowedLanguage.IsDotNet(plugin.Language))
580+
// For dotnet plugins, we need to remove their PluginJsonStorage and PluginBinaryStorage instances
581+
if (AllowedLanguage.IsDotNet(plugin.Language) && API is IRemovable removable)
580582
{
581-
var method = API.GetType().GetMethod("RemovePluginSettings");
582-
method?.Invoke(API, new object[] { plugin.AssemblyName });
583+
removable.RemovePluginSettings(plugin.AssemblyName);
584+
removable.RemovePluginCaches(plugin.PluginCacheDirectoryPath);
583585
}
584586

585587
try

Flow.Launcher.Core/Resource/Theme.cs

+20-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Flow.Launcher.Infrastructure.Logger;
1717
using Flow.Launcher.Infrastructure.UserSettings;
1818
using Flow.Launcher.Plugin;
19+
using Flow.Launcher.Plugin.SharedModels;
1920
using Microsoft.Win32;
2021

2122
namespace Flow.Launcher.Core.Resource
@@ -81,11 +82,6 @@ public Theme(IPublicAPI publicAPI, Settings settings)
8182

8283
#region Theme Resources
8384

84-
public string GetCurrentTheme()
85-
{
86-
return _settings.Theme;
87-
}
88-
8985
private void MakeSureThemeDirectoriesExist()
9086
{
9187
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
@@ -127,7 +123,7 @@ public void UpdateFonts()
127123
try
128124
{
129125
// Load a ResourceDictionary for the specified theme.
130-
var themeName = GetCurrentTheme();
126+
var themeName = _settings.Theme;
131127
var dict = GetThemeResourceDictionary(themeName);
132128

133129
// Apply font settings to the theme resource.
@@ -330,7 +326,7 @@ private ResourceDictionary GetResourceDictionary(string theme)
330326

331327
private ResourceDictionary GetCurrentResourceDictionary()
332328
{
333-
return GetResourceDictionary(GetCurrentTheme());
329+
return GetResourceDictionary(_settings.Theme);
334330
}
335331

336332
private ThemeData GetThemeDataFromPath(string path)
@@ -383,9 +379,20 @@ private string GetThemePath(string themeName)
383379

384380
#endregion
385381

386-
#region Load & Change
382+
#region Get & Change Theme
383+
384+
public ThemeData GetCurrentTheme()
385+
{
386+
var themes = GetAvailableThemes();
387+
var matchingTheme = themes.FirstOrDefault(t => t.FileNameWithoutExtension == _settings.Theme);
388+
if (matchingTheme == null)
389+
{
390+
Log.Warn($"No matching theme found for '{_settings.Theme}'. Falling back to the first available theme.");
391+
}
392+
return matchingTheme ?? themes.FirstOrDefault();
393+
}
387394

388-
public List<ThemeData> LoadAvailableThemes()
395+
public List<ThemeData> GetAvailableThemes()
389396
{
390397
List<ThemeData> themes = new List<ThemeData>();
391398
foreach (var themeDirectory in _themeDirectories)
@@ -403,7 +410,7 @@ public List<ThemeData> LoadAvailableThemes()
403410
public bool ChangeTheme(string theme = null)
404411
{
405412
if (string.IsNullOrEmpty(theme))
406-
theme = GetCurrentTheme();
413+
theme = _settings.Theme;
407414

408415
string path = GetThemePath(theme);
409416
try
@@ -426,7 +433,7 @@ public bool ChangeTheme(string theme = null)
426433

427434
BlurEnabled = IsBlurTheme();
428435

429-
// Can only apply blur but here also apply drop shadow effect to avoid possible drop shadow effect issues
436+
// Apply blur and drop shadow effect so that we do not need to call it again
430437
_ = RefreshFrameAsync();
431438

432439
return true;
@@ -591,7 +598,7 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
591598
{
592599
AutoDropShadow(useDropShadowEffect);
593600
}
594-
SetBlurForWindow(GetCurrentTheme(), backdropType);
601+
SetBlurForWindow(_settings.Theme, backdropType);
595602

596603
if (!BlurEnabled)
597604
{
@@ -610,7 +617,7 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
610617
// Get the actual backdrop type and drop shadow effect settings
611618
var (backdropType, _) = GetActualValue();
612619

613-
SetBlurForWindow(GetCurrentTheme(), backdropType);
620+
SetBlurForWindow(_settings.Theme, backdropType);
614621
}, DispatcherPriority.Render);
615622
}
616623

@@ -898,11 +905,5 @@ private static bool IsBlurTheme()
898905
}
899906

900907
#endregion
901-
902-
#region Classes
903-
904-
public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null);
905-
906-
#endregion
907908
}
908909
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Flow.Launcher.Core.Storage;
2+
3+
/// <summary>
4+
/// Remove storage instances from <see cref="Launcher.Plugin.IPublicAPI"/> instance
5+
/// </summary>
6+
public interface IRemovable
7+
{
8+
/// <summary>
9+
/// Remove all <see cref="Infrastructure.Storage.PluginJsonStorage{T}"/> instances of one plugin
10+
/// </summary>
11+
/// <param name="assemblyName"></param>
12+
public void RemovePluginSettings(string assemblyName);
13+
14+
/// <summary>
15+
/// Remove all <see cref="Infrastructure.Storage.PluginBinaryStorage{T}"/> instances of one plugin
16+
/// </summary>
17+
/// <param name="cacheDirectory"></param>
18+
public void RemovePluginCaches(string cacheDirectory);
19+
}

Flow.Launcher.Infrastructure/Image/ImageLoader.cs

+9-6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public static async Task InitializeAsync()
3434
_hashGenerator = new ImageHashGenerator();
3535

3636
var usage = await LoadStorageToConcurrentDictionaryAsync();
37+
_storage.ClearData();
3738

3839
ImageCache.Initialize(usage);
3940

@@ -284,7 +285,7 @@ public static bool TryGetValue(string path, bool loadFullImage, out ImageSource
284285
return ImageCache.TryGetValue(path, loadFullImage, out image);
285286
}
286287

287-
public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullImage = false)
288+
public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullImage = false, bool cacheImage = true)
288289
{
289290
var imageResult = await LoadInternalAsync(path, loadFullImage);
290291

@@ -300,16 +301,18 @@ public static async ValueTask<ImageSource> LoadAsync(string path, bool loadFullI
300301
// image already exists
301302
img = ImageCache[key, loadFullImage] ?? img;
302303
}
303-
else
304+
else if (cacheImage)
304305
{
305-
// new guid
306-
306+
// save guid key
307307
GuidToKey[hash] = path;
308308
}
309309
}
310310

311-
// update cache
312-
ImageCache[path, loadFullImage] = img;
311+
if (cacheImage)
312+
{
313+
// update cache
314+
ImageCache[path, loadFullImage] = img;
315+
}
313316
}
314317

315318
return img;

Flow.Launcher.Infrastructure/Logger/Log.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using System.Diagnostics;
22
using System.IO;
33
using System.Runtime.CompilerServices;
4+
using System.Runtime.ExceptionServices;
5+
using Flow.Launcher.Infrastructure.UserSettings;
46
using NLog;
57
using NLog.Config;
68
using NLog.Targets;
7-
using Flow.Launcher.Infrastructure.UserSettings;
89
using NLog.Targets.Wrappers;
9-
using System.Runtime.ExceptionServices;
1010

1111
namespace Flow.Launcher.Infrastructure.Logger
1212
{

Flow.Launcher.Infrastructure/Storage/BinaryStorage.cs

+50-15
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,76 @@
22
using System.Threading.Tasks;
33
using Flow.Launcher.Infrastructure.Logger;
44
using Flow.Launcher.Infrastructure.UserSettings;
5+
using Flow.Launcher.Plugin;
56
using Flow.Launcher.Plugin.SharedCommands;
67
using MemoryPack;
78

9+
#nullable enable
10+
811
namespace Flow.Launcher.Infrastructure.Storage
912
{
1013
/// <summary>
1114
/// Stroage object using binary data
1215
/// Normally, it has better performance, but not readable
1316
/// </summary>
1417
/// <remarks>
15-
/// It utilize MemoryPack, which means the object must be MemoryPackSerializable <see href="https://github.com/Cysharp/MemoryPack"/>
18+
/// It utilizes MemoryPack, which means the object must be MemoryPackSerializable <see href="https://github.com/Cysharp/MemoryPack"/>
1619
/// </remarks>
17-
public class BinaryStorage<T>
20+
public class BinaryStorage<T> : ISavable
1821
{
22+
protected T? Data;
23+
1924
public const string FileSuffix = ".cache";
2025

26+
protected string FilePath { get; init; } = null!;
27+
28+
protected string DirectoryPath { get; init; } = null!;
29+
2130
// Let the derived class to set the file path
22-
public BinaryStorage(string filename, string directoryPath = null)
31+
protected BinaryStorage()
2332
{
24-
directoryPath ??= DataLocation.CacheDirectory;
25-
FilesFolders.ValidateDirectory(directoryPath);
26-
27-
FilePath = Path.Combine(directoryPath, $"{filename}{FileSuffix}");
2833
}
2934

30-
public string FilePath { get; }
35+
public BinaryStorage(string filename)
36+
{
37+
DirectoryPath = DataLocation.CacheDirectory;
38+
FilesFolders.ValidateDirectory(DirectoryPath);
39+
40+
FilePath = Path.Combine(DirectoryPath, $"{filename}{FileSuffix}");
41+
}
3142

3243
public async ValueTask<T> TryLoadAsync(T defaultData)
3344
{
45+
if (Data != null) return Data;
46+
3447
if (File.Exists(FilePath))
3548
{
3649
if (new FileInfo(FilePath).Length == 0)
3750
{
3851
Log.Error($"|BinaryStorage.TryLoad|Zero length cache file <{FilePath}>");
39-
await SaveAsync(defaultData);
40-
return defaultData;
52+
Data = defaultData;
53+
await SaveAsync();
4154
}
4255

4356
await using var stream = new FileStream(FilePath, FileMode.Open);
44-
var d = await DeserializeAsync(stream, defaultData);
45-
return d;
57+
Data = await DeserializeAsync(stream, defaultData);
4658
}
4759
else
4860
{
4961
Log.Info("|BinaryStorage.TryLoad|Cache file not exist, load default data");
50-
await SaveAsync(defaultData);
51-
return defaultData;
62+
Data = defaultData;
63+
await SaveAsync();
5264
}
65+
66+
return Data;
5367
}
5468

5569
private static async ValueTask<T> DeserializeAsync(Stream stream, T defaultData)
5670
{
5771
try
5872
{
5973
var t = await MemoryPackSerializer.DeserializeAsync<T>(stream);
60-
return t;
74+
return t ?? defaultData;
6175
}
6276
catch (System.Exception)
6377
{
@@ -66,6 +80,27 @@ private static async ValueTask<T> DeserializeAsync(Stream stream, T defaultData)
6680
}
6781
}
6882

83+
public void Save()
84+
{
85+
var serialized = MemoryPackSerializer.Serialize(Data);
86+
87+
File.WriteAllBytes(FilePath, serialized);
88+
}
89+
90+
public async ValueTask SaveAsync()
91+
{
92+
await SaveAsync(Data.NonNull());
93+
}
94+
95+
// ImageCache need to convert data into concurrent dictionary for usage,
96+
// so we would better to clear the data
97+
public void ClearData()
98+
{
99+
Data = default;
100+
}
101+
102+
// ImageCache storages data in its class,
103+
// so we need to pass it to SaveAsync
69104
public async ValueTask SaveAsync(T data)
70105
{
71106
await using var stream = new FileStream(FilePath, FileMode.Create);

0 commit comments

Comments
 (0)