Support installing from local path

This commit is contained in:
Jack251970 2025-06-09 20:28:18 +08:00
parent f9e7b82b15
commit 248b098e54
4 changed files with 102 additions and 1 deletions

View file

@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.Json;
using System.Threading;
@ -633,6 +634,42 @@ namespace Flow.Launcher.Core.Plugin
}
}
public static async Task InstallPluginAndCheckRestartAsync(string filePath)
{
UserPlugin plugin;
try
{
using ZipArchive archive = ZipFile.OpenRead(filePath);
var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json") ??
throw new FileNotFoundException("The zip file does not contain a plugin.json file.");
var pluginJsonEntry = archive.GetEntry(pluginJsonPath.ToString()) ??
throw new FileNotFoundException("The zip file does not contain a plugin.json file.");
using Stream stream = pluginJsonEntry.Open();
plugin = JsonSerializer.Deserialize<UserPlugin>(stream);
plugin.IcoPath = "Images\\zipfolder.png";
plugin.LocalInstallPath = filePath;
}
catch (Exception e)
{
API.LogException(ClassName, "Failed to validate zip file", e);
API.ShowMsgError(API.GetTranslation("ZipFileNotHavePluginJson"));
return;
}
if (FlowSettings.ShowUnknownSourceWarning)
{
if (!InstallSourceKnown(plugin.Website)
&& API.ShowMsgBox(string.Format(
API.GetTranslation("InstallFromUnknownSourceSubtitle"), Environment.NewLine),
API.GetTranslation("InstallFromUnknownSourceTitle"),
MessageBoxButton.YesNo) == MessageBoxResult.No)
return;
}
await InstallPluginAndCheckRestartAsync(plugin);
}
public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin)
{
if (API.ShowMsgBox(
@ -913,6 +950,24 @@ namespace Flow.Launcher.Core.Plugin
}
}
private static bool InstallSourceKnown(string url)
{
var pieces = url.Split('/');
if (pieces.Length < 4)
return false;
var author = pieces[3];
var acceptedSource = "https://github.com";
var constructedUrlPart = string.Format("{0}/{1}/", acceptedSource, author);
return url.StartsWith(acceptedSource) &&
API.GetAllPlugins().Any(x =>
!string.IsNullOrEmpty(x.Metadata.Website) &&
x.Metadata.Website.StartsWith(constructedUrlPart)
);
}
#endregion
}
}

View file

@ -204,6 +204,12 @@
<system:String x:Key="UpdatePromptSubtitle">{0} by {1} {2}{2}Would you like to update this plugin?</system:String>
<system:String x:Key="DownloadingPlugin">Downloading plugin</system:String>
<system:String x:Key="AutoRestartAfterChange">Automatically restart after installing/uninstalling/updating plugins in plugin store</system:String>
<system:String x:Key="ZipFileNotHavePluginJson">Zip file does not have a valid plugin.json configuration</system:String>
<system:String x:Key="InstallFromUnknownSourceTitle">Installing from an unknown source</system:String>
<system:String x:Key="InstallFromUnknownSourceSubtitle">This plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window)</system:String>
<system:String x:Key="ZipFiles">Zip files</system:String>
<system:String x:Key="SelectZipFile">Please select zip file</system:String>
<system:String x:Key="installLocalPluginTooltip">Install plugin from local path</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Theme</system:String>

View file

@ -1,7 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
@ -96,6 +99,36 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
}
}
[RelayCommand]
private async Task InstallPluginAsync()
{
var file = GetFileFromDialog(
App.API.GetTranslation("SelectZipFile"),
$"{App.API.GetTranslation("ZipFiles")} (*.zip)|*.zip");
if (!string.IsNullOrEmpty(file))
await PluginManager.InstallPluginAndCheckRestartAsync(file);
}
private static string GetFileFromDialog(string title, string filter = "")
{
var dlg = new OpenFileDialog
{
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads",
Multiselect = false,
CheckFileExists = true,
CheckPathExists = true,
Title = title,
Filter = filter
};
return dlg.ShowDialog() switch
{
DialogResult.OK => dlg.FileName,
_ => string.Empty
};
}
public bool SatisfiesFilter(PluginStoreItemViewModel plugin)
{
// Check plugin language

View file

@ -92,6 +92,13 @@
</ui:MenuFlyout>
</ui:FlyoutService.Flyout>
</Button>
<Button
Height="34"
Margin="0 0 10 0"
Command="{Binding InstallPluginCommand}"
ToolTip="{DynamicResource installLocalPluginTooltip}">
<ui:FontIcon FontSize="14" Glyph="&#xE8DA;" />
</Button>
<TextBox
Name="PluginStoreFilterTextbox"
Width="150"