Skip to content

Commit 6af79a1

Browse files
authored
Merge branch 'dev' into load_image_async
2 parents 46109a2 + 6ebb73b commit 6af79a1

File tree

15 files changed

+222
-109
lines changed

15 files changed

+222
-109
lines changed

Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs

+1
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

+1
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

+6-5
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

-23
This file was deleted.

Flow.Launcher.Core/Plugin/PluginManager.cs

+16-27
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.Plugin/Interfaces/IPublicAPI.cs

+56
Original file line numberDiff line numberDiff line change
@@ -360,5 +360,61 @@ public interface IPublicAPI
360360
/// </param>
361361
/// <returns></returns>
362362
ValueTask<ImageSource> LoadImageAsync(string path, bool loadFullImage = false, bool cacheImage = true);
363+
364+
/// Update the plugin manifest
365+
/// </summary>
366+
/// <param name="usePrimaryUrlOnly">
367+
/// FL has multiple urls to download the plugin manifest. Set this to true to only use the primary url.
368+
/// </param>
369+
/// <param name="token"></param>
370+
/// <returns>True if the manifest is updated successfully, false otherwise</returns>
371+
public Task<bool> UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default);
372+
373+
/// <summary>
374+
/// Get the plugin manifest
375+
/// </summary>
376+
/// <returns></returns>
377+
public IReadOnlyList<UserPlugin> GetPluginManifest();
378+
379+
/// <summary>
380+
/// Check if the plugin has been modified.
381+
/// If this plugin is updated, installed or uninstalled and users do not restart the app,
382+
/// it will be marked as modified
383+
/// </summary>
384+
/// <param name="id">Plugin id</param>
385+
/// <returns></returns>
386+
public bool PluginModified(string id);
387+
388+
/// <summary>
389+
/// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url,
390+
/// unless it's a local path installation
391+
/// </summary>
392+
/// <param name="pluginMetadata">The metadata of the old plugin to update</param>
393+
/// <param name="plugin">The new plugin to update</param>
394+
/// <param name="zipFilePath">
395+
/// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed.
396+
/// </param>
397+
/// <returns></returns>
398+
public Task UpdatePluginAsync(PluginMetadata pluginMetadata, UserPlugin plugin, string zipFilePath);
399+
400+
/// <summary>
401+
/// Install a plugin. By default will remove the zip file if installation is from url,
402+
/// unless it's a local path installation
403+
/// </summary>
404+
/// <param name="plugin">The plugin to install</param>
405+
/// <param name="zipFilePath">
406+
/// Path to the zip file containing the plugin. It will be unzipped to the temporary directory, removed and installed.
407+
/// </param>
408+
public void InstallPlugin(UserPlugin plugin, string zipFilePath);
409+
410+
/// <summary>
411+
/// Uninstall a plugin
412+
/// </summary>
413+
/// <param name="pluginMetadata">The metadata of the plugin to uninstall</param>
414+
/// <param name="removePluginSettings">
415+
/// Plugin has their own settings. If this is set to true, the plugin settings will be removed.
416+
/// </param>
417+
/// <returns></returns>
418+
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false);
363419
}
364420
}

Flow.Launcher.Plugin/UserPlugin.cs

+80
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/PublicAPIInstance.cs

+17
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
using Flow.Launcher.ViewModel;
3030
using JetBrains.Annotations;
3131
using Flow.Launcher.Core.Resource;
32+
using Flow.Launcher.Core.ExternalPlugins;
3233

3334
namespace Flow.Launcher
3435
{
@@ -358,6 +359,22 @@ public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "", M
358359
public ValueTask<ImageSource> LoadImageAsync(string path, bool loadFullImage = false, bool cacheImage = true) =>
359360
ImageLoader.LoadAsync(path, loadFullImage, cacheImage);
360361

362+
public Task<bool> UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default) =>
363+
PluginsManifest.UpdateManifestAsync(usePrimaryUrlOnly, token);
364+
365+
public IReadOnlyList<UserPlugin> GetPluginManifest() => PluginsManifest.UserPlugins;
366+
367+
public bool PluginModified(string id) => PluginManager.PluginModified(id);
368+
369+
public Task UpdatePluginAsync(PluginMetadata pluginMetadata, UserPlugin plugin, string zipFilePath) =>
370+
PluginManager.UpdatePluginAsync(pluginMetadata, plugin, zipFilePath);
371+
372+
public void InstallPlugin(UserPlugin plugin, string zipFilePath) =>
373+
PluginManager.InstallPlugin(plugin, zipFilePath);
374+
375+
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false) =>
376+
PluginManager.UninstallPluginAsync(pluginMetadata, removePluginSettings);
377+
361378
#endregion
362379

363380
#region Private Methods

Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Linq;
33
using System.Threading.Tasks;
44
using CommunityToolkit.Mvvm.Input;
5-
using Flow.Launcher.Core.ExternalPlugins;
65
using Flow.Launcher.Infrastructure;
76
using Flow.Launcher.Plugin;
87
using Flow.Launcher.ViewModel;
@@ -14,7 +13,7 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
1413
public string FilterText { get; set; } = string.Empty;
1514

1615
public IList<PluginStoreItemViewModel> ExternalPlugins =>
17-
PluginsManifest.UserPlugins?.Select(p => new PluginStoreItemViewModel(p))
16+
App.API.GetPluginManifest()?.Select(p => new PluginStoreItemViewModel(p))
1817
.OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease)
1918
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated)
2019
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.None)
@@ -24,7 +23,7 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
2423
[RelayCommand]
2524
private async Task RefreshExternalPluginsAsync()
2625
{
27-
if (await PluginsManifest.UpdateManifestAsync())
26+
if (await App.API.UpdatePluginManifestAsync())
2827
{
2928
OnPropertyChanged(nameof(ExternalPlugins));
3029
}

Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs

-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
using System;
22
using System.Linq;
33
using CommunityToolkit.Mvvm.Input;
4-
using Flow.Launcher.Core.ExternalPlugins;
54
using Flow.Launcher.Core.Plugin;
65
using Flow.Launcher.Plugin;
7-
using SemanticVersioning;
86
using Version = SemanticVersioning.Version;
97

108
namespace Flow.Launcher.ViewModel

Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Flow.Launcher.Core.ExternalPlugins;
2-
using System.Collections.Generic;
1+
using System.Collections.Generic;
32
using System.Text.RegularExpressions;
43

54
namespace Flow.Launcher.Plugin.PluginsManager

Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
</PropertyGroup>
1919

2020
<ItemGroup>
21-
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
22-
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
2321
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
2422
</ItemGroup>
2523

@@ -37,4 +35,8 @@
3735
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3836
</Content>
3937
</ItemGroup>
38+
39+
<ItemGroup>
40+
<PackageReference Include="SharpZipLib" Version="1.4.2" />
41+
</ItemGroup>
4042
</Project>

0 commit comments

Comments
 (0)