Skip to content

Commit 7695a46

Browse files
authored
Merge branch 'dev' into error_log
2 parents 5e63738 + 6ebb73b commit 7695a46

File tree

19 files changed

+255
-122
lines changed

19 files changed

+255
-122
lines changed

Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Flow.Launcher.Infrastructure.Http;
22
using Flow.Launcher.Infrastructure.Logger;
3+
using Flow.Launcher.Plugin;
34
using System;
45
using System.Collections.Generic;
56
using System.Net;

Flow.Launcher.Core/ExternalPlugins/CommunityPluginStore.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using System.Threading;
44
using System.Threading.Tasks;
5+
using Flow.Launcher.Plugin;
56

67
namespace Flow.Launcher.Core.ExternalPlugins
78
{

Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
using Flow.Launcher.Infrastructure.Logger;
2-
using System;
1+
using System;
32
using System.Collections.Generic;
43
using System.Threading;
54
using System.Threading.Tasks;
5+
using CommunityToolkit.Mvvm.DependencyInjection;
6+
using Flow.Launcher.Plugin;
67

78
namespace Flow.Launcher.Core.ExternalPlugins
89
{
@@ -17,11 +18,11 @@ public static class PluginsManifest
1718
private static readonly SemaphoreSlim manifestUpdateLock = new(1);
1819

1920
private static DateTime lastFetchedAt = DateTime.MinValue;
20-
private static TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);
21+
private static readonly TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);
2122

2223
public static List<UserPlugin> UserPlugins { get; private set; }
2324

24-
public static async Task<bool> UpdateManifestAsync(CancellationToken token = default, bool usePrimaryUrlOnly = false)
25+
public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
2526
{
2627
try
2728
{
@@ -43,7 +44,7 @@ public static async Task<bool> UpdateManifestAsync(CancellationToken token = def
4344
}
4445
catch (Exception e)
4546
{
46-
Log.Exception($"|PluginsManifest.{nameof(UpdateManifestAsync)}|Http request failed", e);
47+
Ioc.Default.GetRequiredService<IPublicAPI>().LogException(nameof(PluginsManifest), "Http request failed", e);
4748
}
4849
finally
4950
{

Flow.Launcher.Core/ExternalPlugins/UserPlugin.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -454,34 +454,23 @@ private static bool SameOrLesserPluginVersionExists(string metadataPath)
454454

455455
#region Public functions
456456

457-
public static bool PluginModified(string uuid)
457+
public static bool PluginModified(string id)
458458
{
459-
return _modifiedPlugins.Contains(uuid);
459+
return _modifiedPlugins.Contains(id);
460460
}
461461

462-
463-
/// <summary>
464-
/// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url,
465-
/// unless it's a local path installation
466-
/// </summary>
467462
public static async Task UpdatePluginAsync(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
468463
{
469464
InstallPlugin(newVersion, zipFilePath, checkModified:false);
470465
await UninstallPluginAsync(existingVersion, removePluginFromSettings:false, removePluginSettings:false, checkModified: false);
471466
_modifiedPlugins.Add(existingVersion.ID);
472467
}
473468

474-
/// <summary>
475-
/// Install a plugin. By default will remove the zip file if installation is from url, unless it's a local path installation
476-
/// </summary>
477469
public static void InstallPlugin(UserPlugin plugin, string zipFilePath)
478470
{
479471
InstallPlugin(plugin, zipFilePath, checkModified: true);
480472
}
481473

482-
/// <summary>
483-
/// Uninstall a plugin.
484-
/// </summary>
485474
public static async Task UninstallPluginAsync(PluginMetadata plugin, bool removePluginFromSettings = true, bool removePluginSettings = false)
486475
{
487476
await UninstallPluginAsync(plugin, removePluginFromSettings, removePluginSettings, true);
@@ -525,20 +514,20 @@ internal static void InstallPlugin(UserPlugin plugin, string zipFilePath, bool c
525514
var folderName = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}" : $"{plugin.Name}-{plugin.Version}";
526515

527516
var defaultPluginIDs = new List<string>
528-
{
529-
"0ECADE17459B49F587BF81DC3A125110", // BrowserBookmark
530-
"CEA0FDFC6D3B4085823D60DC76F28855", // Calculator
531-
"572be03c74c642baae319fc283e561a8", // Explorer
532-
"6A122269676E40EB86EB543B945932B9", // PluginIndicator
533-
"9f8f9b14-2518-4907-b211-35ab6290dee7", // PluginsManager
534-
"b64d0a79-329a-48b0-b53f-d658318a1bf6", // ProcessKiller
535-
"791FC278BA414111B8D1886DFE447410", // Program
536-
"D409510CD0D2481F853690A07E6DC426", // Shell
537-
"CEA08895D2544B019B2E9C5009600DF4", // Sys
538-
"0308FD86DE0A4DEE8D62B9B535370992", // URL
539-
"565B73353DBF4806919830B9202EE3BF", // WebSearch
540-
"5043CETYU6A748679OPA02D27D99677A" // WindowsSettings
541-
};
517+
{
518+
"0ECADE17459B49F587BF81DC3A125110", // BrowserBookmark
519+
"CEA0FDFC6D3B4085823D60DC76F28855", // Calculator
520+
"572be03c74c642baae319fc283e561a8", // Explorer
521+
"6A122269676E40EB86EB543B945932B9", // PluginIndicator
522+
"9f8f9b14-2518-4907-b211-35ab6290dee7", // PluginsManager
523+
"b64d0a79-329a-48b0-b53f-d658318a1bf6", // ProcessKiller
524+
"791FC278BA414111B8D1886DFE447410", // Program
525+
"D409510CD0D2481F853690A07E6DC426", // Shell
526+
"CEA08895D2544B019B2E9C5009600DF4", // Sys
527+
"0308FD86DE0A4DEE8D62B9B535370992", // URL
528+
"565B73353DBF4806919830B9202EE3BF", // WebSearch
529+
"5043CETYU6A748679OPA02D27D99677A" // WindowsSettings
530+
};
542531

543532
// Treat default plugin differently, it needs to be removable along with each flow release
544533
var installDirectory = !defaultPluginIDs.Any(x => x == plugin.ID)

Flow.Launcher.Infrastructure/Image/ImageLoader.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
using System.Linq;
66
using System.Threading;
77
using System.Threading.Tasks;
8-
using System.Windows.Documents;
98
using System.Windows.Media;
109
using System.Windows.Media.Imaging;
1110
using Flow.Launcher.Infrastructure.Logger;
1211
using Flow.Launcher.Infrastructure.Storage;
13-
using static Flow.Launcher.Infrastructure.Http.Http;
1412

1513
namespace Flow.Launcher.Infrastructure.Image
1614
{
@@ -28,7 +26,6 @@ public static class ImageLoader
2826
public const int SmallIconSize = 64;
2927
public const int FullIconSize = 256;
3028

31-
3229
private static readonly string[] ImageExtensions = { ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".ico" };
3330

3431
public static async Task InitializeAsync()
@@ -183,7 +180,7 @@ private static async ValueTask<ImageResult> LoadInternalAsync(string path, bool
183180
private static async Task<BitmapImage> LoadRemoteImageAsync(bool loadFullImage, Uri uriResult)
184181
{
185182
// Download image from url
186-
await using var resp = await GetStreamAsync(uriResult);
183+
await using var resp = await Http.Http.GetStreamAsync(uriResult);
187184
await using var buffer = new MemoryStream();
188185
await resp.CopyToAsync(buffer);
189186
buffer.Seek(0, SeekOrigin.Begin);

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,16 @@ public static bool SetForegroundWindow(nint handle)
124124
return PInvoke.SetForegroundWindow(new(handle));
125125
}
126126

127+
public static bool IsForegroundWindow(Window window)
128+
{
129+
return IsForegroundWindow(GetWindowHandle(window));
130+
}
131+
132+
internal static bool IsForegroundWindow(HWND handle)
133+
{
134+
return handle.Equals(PInvoke.GetForegroundWindow());
135+
}
136+
127137
#endregion
128138

129139
#region Task Switching
@@ -354,10 +364,20 @@ public static unsafe void SwitchToEnglishKeyboardLayout(bool backupPrevious)
354364
// No installed English layout found
355365
if (enHKL == HKL.Null) return;
356366

357-
// Get the current foreground window
358-
var hwnd = PInvoke.GetForegroundWindow();
367+
// When application is exiting, the Application.Current will be null
368+
if (Application.Current == null) return;
369+
370+
// Get the FL main window
371+
var hwnd = GetWindowHandle(Application.Current.MainWindow, true);
359372
if (hwnd == HWND.Null) return;
360373

374+
// Check if the FL main window is the current foreground window
375+
if (!IsForegroundWindow(hwnd))
376+
{
377+
var result = PInvoke.SetForegroundWindow(hwnd);
378+
if (!result) throw new Win32Exception(Marshal.GetLastWin32Error());
379+
}
380+
361381
// Get the current foreground window thread ID
362382
var threadId = PInvoke.GetWindowThreadProcessId(hwnd);
363383
if (threadId == 0) throw new Win32Exception(Marshal.GetLastWin32Error());
@@ -367,12 +387,10 @@ public static unsafe void SwitchToEnglishKeyboardLayout(bool backupPrevious)
367387
// the IME mode instead of switching to another layout.
368388
var currentLayout = PInvoke.GetKeyboardLayout(threadId);
369389
var currentLangId = (uint)currentLayout.Value & KeyboardLayoutLoWord;
370-
foreach (var langTag in ImeLanguageTags)
390+
foreach (var imeLangTag in ImeLanguageTags)
371391
{
372-
if (GetLanguageTag(currentLangId).StartsWith(langTag, StringComparison.OrdinalIgnoreCase))
373-
{
374-
return;
375-
}
392+
var langTag = GetLanguageTag(currentLangId);
393+
if (langTag.StartsWith(imeLangTag, StringComparison.OrdinalIgnoreCase)) return;
376394
}
377395

378396
// Backup current keyboard layout

Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,5 +349,62 @@ public interface IPublicAPI
349349
/// Stop the loading bar in main window
350350
/// </summary>
351351
public void StopLoadingBar();
352+
353+
/// <summary>
354+
/// Update the plugin manifest
355+
/// </summary>
356+
/// <param name="usePrimaryUrlOnly">
357+
/// FL has multiple urls to download the plugin manifest. Set this to true to only use the primary url.
358+
/// </param>
359+
/// <param name="token"></param>
360+
/// <returns>True if the manifest is updated successfully, false otherwise</returns>
361+
public Task<bool> UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default);
362+
363+
/// <summary>
364+
/// Get the plugin manifest
365+
/// </summary>
366+
/// <returns></returns>
367+
public IReadOnlyList<UserPlugin> GetPluginManifest();
368+
369+
/// <summary>
370+
/// Check if the plugin has been modified.
371+
/// If this plugin is updated, installed or uninstalled and users do not restart the app,
372+
/// it will be marked as modified
373+
/// </summary>
374+
/// <param name="id">Plugin id</param>
375+
/// <returns></returns>
376+
public bool PluginModified(string id);
377+
378+
/// <summary>
379+
/// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url,
380+
/// unless it's a local path installation
381+
/// </summary>
382+
/// <param name="pluginMetadata">The metadata of the old plugin to update</param>
383+
/// <param name="plugin">The new plugin to update</param>
384+
/// <param name="zipFilePath">
385+
/// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed.
386+
/// </param>
387+
/// <returns></returns>
388+
public Task UpdatePluginAsync(PluginMetadata pluginMetadata, UserPlugin plugin, string zipFilePath);
389+
390+
/// <summary>
391+
/// Install a plugin. By default will remove the zip file if installation is from url,
392+
/// unless it's a local path installation
393+
/// </summary>
394+
/// <param name="plugin">The plugin to install</param>
395+
/// <param name="zipFilePath">
396+
/// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed.
397+
/// </param>
398+
public void InstallPlugin(UserPlugin plugin, string zipFilePath);
399+
400+
/// <summary>
401+
/// Uninstall a plugin
402+
/// </summary>
403+
/// <param name="pluginMetadata">The metadata of the plugin to uninstall</param>
404+
/// <param name="removePluginSettings">
405+
/// Plugin has their own settings. If this is set to true, the plugin settings will be removed.
406+
/// </param>
407+
/// <returns></returns>
408+
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false);
352409
}
353410
}

Flow.Launcher.Plugin/UserPlugin.cs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
3+
namespace Flow.Launcher.Plugin
4+
{
5+
/// <summary>
6+
/// User Plugin Model for Flow Launcher
7+
/// </summary>
8+
public record UserPlugin
9+
{
10+
/// <summary>
11+
/// Unique identifier of the plugin
12+
/// </summary>
13+
public string ID { get; set; }
14+
15+
/// <summary>
16+
/// Name of the plugin
17+
/// </summary>
18+
public string Name { get; set; }
19+
20+
/// <summary>
21+
/// Description of the plugin
22+
/// </summary>
23+
public string Description { get; set; }
24+
25+
/// <summary>
26+
/// Author of the plugin
27+
/// </summary>
28+
public string Author { get; set; }
29+
30+
/// <summary>
31+
/// Version of the plugin
32+
/// </summary>
33+
public string Version { get; set; }
34+
35+
/// <summary>
36+
/// Allow language of the plugin <see cref="AllowedLanguage"/>
37+
/// </summary>
38+
public string Language { get; set; }
39+
40+
/// <summary>
41+
/// Website of the plugin
42+
/// </summary>
43+
public string Website { get; set; }
44+
45+
/// <summary>
46+
/// URL to download the plugin
47+
/// </summary>
48+
public string UrlDownload { get; set; }
49+
50+
/// <summary>
51+
/// URL to the source code of the plugin
52+
/// </summary>
53+
public string UrlSourceCode { get; set; }
54+
55+
/// <summary>
56+
/// Local path where the plugin is installed
57+
/// </summary>
58+
public string LocalInstallPath { get; set; }
59+
60+
/// <summary>
61+
/// Icon path of the plugin
62+
/// </summary>
63+
public string IcoPath { get; set; }
64+
65+
/// <summary>
66+
/// The date when the plugin was last updated
67+
/// </summary>
68+
public DateTime? LatestReleaseDate { get; set; }
69+
70+
/// <summary>
71+
/// The date when the plugin was added to the local system
72+
/// </summary>
73+
public DateTime? DateAdded { get; set; }
74+
75+
/// <summary>
76+
/// Indicates whether the plugin is installed from a local path
77+
/// </summary>
78+
public bool IsFromLocalInstallPath => !string.IsNullOrEmpty(LocalInstallPath);
79+
}
80+
}

Flow.Launcher/App.xaml.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
179179
Current.MainWindow = _mainWindow;
180180
Current.MainWindow.Title = Constant.FlowLauncher;
181181

182-
HotKeyMapper.Initialize();
183-
184182
// main windows needs initialized before theme change because of blur settings
185183
Ioc.Default.GetRequiredService<Theme>().ChangeTheme();
186184

0 commit comments

Comments
 (0)