mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into dev4
This commit is contained in:
commit
25684a92ae
36 changed files with 528 additions and 125 deletions
|
|
@ -1,4 +1,4 @@
|
|||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
|
@ -21,7 +21,7 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
|
||||
public static List<UserPlugin> UserPlugins { get; private set; }
|
||||
|
||||
public static async Task UpdateManifestAsync(CancellationToken token = default, bool usePrimaryUrlOnly = false)
|
||||
public static async Task<bool> UpdateManifestAsync(CancellationToken token = default, bool usePrimaryUrlOnly = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -31,8 +31,14 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
{
|
||||
var results = await mainPluginStore.FetchAsync(token, usePrimaryUrlOnly).ConfigureAwait(false);
|
||||
|
||||
UserPlugins = results;
|
||||
lastFetchedAt = DateTime.Now;
|
||||
// If the results are empty, we shouldn't update the manifest because the results are invalid.
|
||||
if (results.Count != 0)
|
||||
{
|
||||
UserPlugins = results;
|
||||
lastFetchedAt = DateTime.Now;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -43,6 +49,8 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
{
|
||||
manifestUpdateLock.Release();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Droplex" Version="1.7.0" />
|
||||
<PackageReference Include="FSharp.Core" Version="9.0.100" />
|
||||
<PackageReference Include="FSharp.Core" Version="9.0.101" />
|
||||
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.4.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
|
||||
|
|
|
|||
|
|
@ -26,54 +26,33 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
protected override async Task<bool> ExecuteResultAsync(JsonRPCResult result)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = await RPC.InvokeAsync<JsonRPCExecuteResponse>(result.JsonRPCAction.Method,
|
||||
argument: result.JsonRPCAction.Parameters);
|
||||
var res = await RPC.InvokeAsync<JsonRPCExecuteResponse>(result.JsonRPCAction.Method,
|
||||
argument: result.JsonRPCAction.Parameters);
|
||||
|
||||
return res.Hide;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return res.Hide;
|
||||
}
|
||||
|
||||
private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());
|
||||
|
||||
public override List<Result> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = JTF.Run(() => RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("context_menu",
|
||||
new object[] { selectedResult.ContextData }));
|
||||
var res = JTF.Run(() => RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("context_menu",
|
||||
new object[] { selectedResult.ContextData }));
|
||||
|
||||
var results = ParseResults(res);
|
||||
var results = ParseResults(res);
|
||||
|
||||
return results;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<Result>();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public override async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = await RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("query",
|
||||
new object[] { query, Settings.Inner },
|
||||
token);
|
||||
var res = await RPC.InvokeWithCancellationAsync<JsonRPCQueryResponseModel>("query",
|
||||
new object[] { query, Settings.Inner },
|
||||
token);
|
||||
|
||||
var results = ParseResults(res);
|
||||
var results = ParseResults(res);
|
||||
|
||||
return results;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new List<Result>();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
|
@ -121,10 +120,10 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models
|
|||
return _api.HttpGetStreamAsync(url, token);
|
||||
}
|
||||
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath,
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return _api.HttpDownloadAsync(url, filePath, token);
|
||||
return _api.HttpDownloadAsync(url, filePath, reportProgress, token);
|
||||
}
|
||||
|
||||
public void AddActionKeyword(string pluginId, string newActionKeyword)
|
||||
|
|
@ -162,16 +161,19 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models
|
|||
_api.OpenDirectory(DirectoryPath, FileNameOrFilePath);
|
||||
}
|
||||
|
||||
|
||||
public void OpenUrl(string url, bool? inPrivate = null)
|
||||
{
|
||||
_api.OpenUrl(url, inPrivate);
|
||||
}
|
||||
|
||||
|
||||
public void OpenAppUri(string appUri)
|
||||
{
|
||||
_api.OpenAppUri(appUri);
|
||||
}
|
||||
|
||||
public void BackToQueryResults()
|
||||
{
|
||||
_api.BackToQueryResults();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,15 +82,50 @@ namespace Flow.Launcher.Infrastructure.Http
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default)
|
||||
public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fileStream, token);
|
||||
var totalBytes = response.Content.Headers.ContentLength ?? -1L;
|
||||
var canReportProgress = totalBytes != -1;
|
||||
|
||||
if (canReportProgress && reportProgress != null)
|
||||
{
|
||||
await using var contentStream = await response.Content.ReadAsStreamAsync(token);
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8192, true);
|
||||
|
||||
var buffer = new byte[8192];
|
||||
long totalRead = 0;
|
||||
int read;
|
||||
double progressValue = 0;
|
||||
|
||||
reportProgress(0);
|
||||
|
||||
while ((read = await contentStream.ReadAsync(buffer, token)) > 0)
|
||||
{
|
||||
await fileStream.WriteAsync(buffer.AsMemory(0, read), token);
|
||||
totalRead += read;
|
||||
|
||||
progressValue = totalRead * 100.0 / totalBytes;
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
else
|
||||
reportProgress(progressValue);
|
||||
}
|
||||
|
||||
if (progressValue < 100)
|
||||
reportProgress(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fileStream, token);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Flow.Launcher.Plugin.SharedModels;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -181,9 +181,13 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
/// <param name="url">URL to download file</param>
|
||||
/// <param name="filePath">path to save downloaded file</param>
|
||||
/// <param name="reportProgress">
|
||||
/// Action to report progress. The input of the action is the progress value which is a double value between 0 and 100.
|
||||
/// It will be called if url support range request and the reportProgress is not null.
|
||||
/// </param>
|
||||
/// <param name="token">place to store file</param>
|
||||
/// <returns>Task showing the progress</returns>
|
||||
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default);
|
||||
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// Add ActionKeyword for specific plugin
|
||||
|
|
@ -316,5 +320,19 @@ namespace Flow.Launcher.Plugin
|
|||
/// <param name="defaultResult">Specifies the default result of the message box.</param>
|
||||
/// <returns>Specifies which message box button is clicked by the user.</returns>
|
||||
public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "", MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.OK);
|
||||
|
||||
/// <summary>
|
||||
/// Displays a standardised Flow message box.
|
||||
/// If there is issue when showing the message box, it will return null.
|
||||
/// </summary>
|
||||
/// <param name="caption">The caption of the message box.</param>
|
||||
/// <param name="reportProgressAsync">
|
||||
/// Time-consuming task function, whose input is the action to report progress.
|
||||
/// The input of the action is the progress value which is a double value between 0 and 100.
|
||||
/// If there are any exceptions, this action will be null.
|
||||
/// </param>
|
||||
/// <param name="forceClosed">When user closes the progress box manually by button or esc key, this action will be called.</param>
|
||||
/// <returns>A progress box interface.</returns>
|
||||
public Task ShowProgressBoxAsync(string caption, Func<Action<double>, Task> reportProgressAsync, Action forceClosed = null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@
|
|||
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
|
||||
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.0" />
|
||||
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -10,16 +10,29 @@ public static class SingletonWindowOpener
|
|||
{
|
||||
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.GetType() == typeof(T))
|
||||
?? (T)Activator.CreateInstance(typeof(T), args);
|
||||
|
||||
|
||||
// Fix UI bug
|
||||
// Add `window.WindowState = WindowState.Normal`
|
||||
// If only use `window.Show()`, Settings-window doesn't show when minimized in taskbar
|
||||
// Not sure why this works tho
|
||||
// Probably because, when `.Show()` fails, `window.WindowState == Minimized` (not `Normal`)
|
||||
// https://stackoverflow.com/a/59719760/4230390
|
||||
window.WindowState = WindowState.Normal;
|
||||
window.Show();
|
||||
|
||||
// Ensure the window is not minimized before showing it
|
||||
if (window.WindowState == WindowState.Minimized)
|
||||
{
|
||||
window.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
// Ensure the window is visible
|
||||
if (!window.IsVisible)
|
||||
{
|
||||
window.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
window.Activate(); // Bring the window to the foreground if already open
|
||||
}
|
||||
|
||||
window.Focus();
|
||||
|
||||
return (T)window;
|
||||
|
|
|
|||
|
|
@ -148,4 +148,64 @@ public class WindowsInteropHelper
|
|||
|
||||
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
||||
}
|
||||
|
||||
#region Alt Tab
|
||||
|
||||
private static int SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong)
|
||||
{
|
||||
PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error
|
||||
|
||||
var result = PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong);
|
||||
if (result == 0 && Marshal.GetLastPInvokeError() != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide windows in the Alt+Tab window list
|
||||
/// </summary>
|
||||
/// <param name="window">To hide a window</param>
|
||||
public static void HideFromAltTab(Window window)
|
||||
{
|
||||
var exStyle = GetCurrentWindowStyle(window);
|
||||
|
||||
// Add TOOLWINDOW style, remove APPWINDOW style
|
||||
var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
||||
|
||||
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore window display in the Alt+Tab window list.
|
||||
/// </summary>
|
||||
/// <param name="window">To restore the displayed window</param>
|
||||
public static void ShowInAltTab(Window window)
|
||||
{
|
||||
var exStyle = GetCurrentWindowStyle(window);
|
||||
|
||||
// Remove the TOOLWINDOW style and add the APPWINDOW style.
|
||||
var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
||||
|
||||
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To obtain the current overridden style of a window.
|
||||
/// </summary>
|
||||
/// <param name="window">To obtain the style dialog window</param>
|
||||
/// <returns>current extension style value</returns>
|
||||
private static int GetCurrentWindowStyle(Window window)
|
||||
{
|
||||
var style = PInvoke.GetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||
if (style == 0 && Marshal.GetLastPInvokeError() != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
Closing="OnClosing"
|
||||
Deactivated="OnDeactivated"
|
||||
Icon="Images/app.png"
|
||||
SourceInitialized="OnSourceInitialized"
|
||||
Initialized="OnInitialized"
|
||||
Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Loaded="OnLoaded"
|
||||
|
|
|
|||
|
|
@ -171,6 +171,11 @@ namespace Flow.Launcher
|
|||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
private void OnSourceInitialized(object sender, EventArgs e)
|
||||
{
|
||||
WindowsInteropHelper.HideFromAltTab(this);
|
||||
}
|
||||
|
||||
private void OnInitialized(object sender, EventArgs e)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,4 +14,7 @@ FindWindowEx
|
|||
WINDOW_STYLE
|
||||
|
||||
WM_ENTERSIZEMOVE
|
||||
WM_EXITSIZEMOVE
|
||||
WM_EXITSIZEMOVE
|
||||
|
||||
SetLastError
|
||||
WINDOW_EX_STYLE
|
||||
106
Flow.Launcher/ProgressBoxEx.xaml
Normal file
106
Flow.Launcher/ProgressBoxEx.xaml
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<Window
|
||||
x:Class="Flow.Launcher.ProgressBoxEx"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Flow.Launcher"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Name="MessageBoxWindow"
|
||||
Width="420"
|
||||
Height="Auto"
|
||||
Background="{DynamicResource PopuBGColor}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
ResizeMode="NoResize"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
mc:Ignorable="d">
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
||||
</WindowChrome.WindowChrome>
|
||||
<Window.InputBindings>
|
||||
<KeyBinding Key="Escape" Command="Close" />
|
||||
</Window.InputBindings>
|
||||
<Window.CommandBindings>
|
||||
<CommandBinding Command="Close" Executed="KeyEsc_OnPress" />
|
||||
</Window.CommandBindings>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition MinHeight="68" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Click="Button_Cancel"
|
||||
Style="{StaticResource TitleBarCloseButtonStyle}">
|
||||
<Path
|
||||
Width="46"
|
||||
Height="32"
|
||||
Data="M 18,11 27,20 M 18,20 27,11"
|
||||
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
|
||||
StrokeThickness="1">
|
||||
<Path.Style>
|
||||
<Style TargetType="Path">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
|
||||
<Setter Property="Opacity" Value="0.5" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Path.Style>
|
||||
</Path>
|
||||
</Button>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="1" Margin="30 0 30 24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
x:Name="TitleTextBlock"
|
||||
Grid.Row="0"
|
||||
MaxWidth="400"
|
||||
Margin="0 0 26 12"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<ProgressBar
|
||||
x:Name="ProgressBar"
|
||||
Grid.Row="1"
|
||||
Margin="0 0 26 0"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
Value="0" />
|
||||
</Grid>
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
Margin="0 0 0 0"
|
||||
Background="{DynamicResource PopupButtonAreaBGColor}"
|
||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||
BorderThickness="0 1 0 0">
|
||||
<WrapPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
x:Name="btnCancel"
|
||||
MinWidth="120"
|
||||
Margin="5 0 5 0"
|
||||
Click="Button_Click"
|
||||
Content="{DynamicResource commonCancel}" />
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
114
Flow.Launcher/ProgressBoxEx.xaml.cs
Normal file
114
Flow.Launcher/ProgressBoxEx.xaml.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
public partial class ProgressBoxEx : Window
|
||||
{
|
||||
private readonly Action _forceClosed;
|
||||
|
||||
private ProgressBoxEx(Action forceClosed)
|
||||
{
|
||||
_forceClosed = forceClosed;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static async Task ShowAsync(string caption, Func<Action<double>, Task> reportProgressAsync, Action forceClosed = null)
|
||||
{
|
||||
ProgressBoxEx prgBox = null;
|
||||
try
|
||||
{
|
||||
if (!Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
prgBox = new ProgressBoxEx(forceClosed)
|
||||
{
|
||||
Title = caption
|
||||
};
|
||||
prgBox.TitleTextBlock.Text = caption;
|
||||
prgBox.Show();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
prgBox = new ProgressBoxEx(forceClosed)
|
||||
{
|
||||
Title = caption
|
||||
};
|
||||
prgBox.TitleTextBlock.Text = caption;
|
||||
prgBox.Show();
|
||||
}
|
||||
|
||||
await reportProgressAsync(prgBox.ReportProgress).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"|ProgressBoxEx.Show|An error occurred: {e.Message}");
|
||||
|
||||
await reportProgressAsync(null).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
prgBox?.Close();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
prgBox?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReportProgress(double progress)
|
||||
{
|
||||
if (!Application.Current.Dispatcher.CheckAccess())
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => ReportProgress(progress));
|
||||
return;
|
||||
}
|
||||
|
||||
if (progress < 0)
|
||||
{
|
||||
ProgressBar.Value = 0;
|
||||
}
|
||||
else if (progress >= 100)
|
||||
{
|
||||
ProgressBar.Value = 100;
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgressBar.Value = progress;
|
||||
}
|
||||
}
|
||||
|
||||
private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
ForceClose();
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ForceClose();
|
||||
}
|
||||
|
||||
private void Button_Cancel(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ForceClose();
|
||||
}
|
||||
|
||||
private void ForceClose()
|
||||
{
|
||||
Close();
|
||||
_forceClosed?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,8 +163,8 @@ namespace Flow.Launcher
|
|||
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
|
||||
Http.GetStreamAsync(url);
|
||||
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath,
|
||||
CancellationToken token = default) => Http.DownloadAsync(url, filePath, token);
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
||||
CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token);
|
||||
|
||||
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
|
||||
PluginManager.AddActionKeyword(pluginId, newActionKeyword);
|
||||
|
|
@ -323,6 +323,8 @@ namespace Flow.Launcher
|
|||
public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "", MessageBoxButton button = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.OK) =>
|
||||
MessageBoxEx.Show(messageBoxText, caption, button, icon, defaultResult);
|
||||
|
||||
public Task ShowProgressBoxAsync(string caption, Func<Action<double>, Task> reportProgressAsync, Action forceClosed = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, forceClosed);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
|
|||
{
|
||||
public string FilterText { get; set; } = string.Empty;
|
||||
|
||||
public IList<PluginStoreItemViewModel> ExternalPlugins => PluginsManifest.UserPlugins
|
||||
.Select(p => new PluginStoreItemViewModel(p))
|
||||
public IList<PluginStoreItemViewModel> ExternalPlugins =>
|
||||
PluginsManifest.UserPlugins?.Select(p => new PluginStoreItemViewModel(p))
|
||||
.OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.None)
|
||||
|
|
@ -24,8 +24,10 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
|
|||
[RelayCommand]
|
||||
private async Task RefreshExternalPluginsAsync()
|
||||
{
|
||||
await PluginsManifest.UpdateManifestAsync();
|
||||
OnPropertyChanged(nameof(ExternalPlugins));
|
||||
if (await PluginsManifest.UpdateManifestAsync())
|
||||
{
|
||||
OnPropertyChanged(nameof(ExternalPlugins));
|
||||
}
|
||||
}
|
||||
|
||||
public bool SatisfiesFilter(PluginStoreItemViewModel plugin)
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ public partial class SettingWindow
|
|||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L)
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L) or sleep
|
||||
// https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
|
||||
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
|
||||
HwndTarget hwndTarget = hwndSource.CompositionTarget;
|
||||
hwndTarget.RenderMode = RenderMode.Default;
|
||||
hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here
|
||||
|
||||
InitializePosition();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.0" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Browser Bookmarks",
|
||||
"Description": "Search your browser bookmarks",
|
||||
"Author": "qianlifeng, Ioannis G.",
|
||||
"Version": "3.3.3",
|
||||
"Version": "3.3.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Calculator",
|
||||
"Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)",
|
||||
"Author": "cxfksword",
|
||||
"Version": "3.1.4",
|
||||
"Version": "3.1.5",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Calculator.dll",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
internal const string WindowsIndexErrorImagePath = "Images\\index_error2.png";
|
||||
internal const string GeneralSearchErrorImagePath = "Images\\robot_error.png";
|
||||
|
||||
|
||||
internal const string ToolTipOpenDirectory = "Ctrl + Enter to open the directory";
|
||||
|
||||
internal const string ToolTipOpenContainingFolder = "Ctrl + Enter to open the containing folder";
|
||||
|
|
@ -31,6 +30,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
internal const string DefaultContentSearchActionKeyword = "doc:";
|
||||
|
||||
internal const char UnixDirectorySeparator = '/';
|
||||
|
||||
internal const char DirectorySeparator = '\\';
|
||||
|
||||
internal const string WindowsIndexingOptions = "srchadmin.dll";
|
||||
|
|
|
|||
|
|
@ -187,6 +187,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
var needToExpand = EnvironmentVariables.HasEnvironmentVar(querySearch);
|
||||
var path = needToExpand ? Environment.ExpandEnvironmentVariables(querySearch) : querySearch;
|
||||
|
||||
// if user uses the unix directory separator, we need to convert it to windows directory separator
|
||||
path = path.Replace(Constants.UnixDirectorySeparator, Constants.DirectorySeparator);
|
||||
|
||||
// Check that actual location exists, otherwise directory search will throw directory not found exception
|
||||
if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path).LocationExists())
|
||||
return results.ToList();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
"Name": "Explorer",
|
||||
"Description": "Find and manage files and folders via Windows Search or Everything",
|
||||
"Author": "Jeremy Wu",
|
||||
"Version": "3.2.3",
|
||||
"Version": "3.2.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Plugin Indicator",
|
||||
"Description": "Provides plugin action keyword suggestions",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.0.6",
|
||||
"Version": "3.0.7",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.PluginIndicator.dll",
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
return query.FirstSearch.ToLower() switch
|
||||
{
|
||||
//search could be url, no need ToLower() when passed in
|
||||
Settings.InstallCommand => await pluginManager.RequestInstallOrUpdate(query.SecondToEndSearch, token, query.IsReQuery),
|
||||
Settings.InstallCommand => await pluginManager.RequestInstallOrUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery),
|
||||
Settings.UninstallCommand => pluginManager.RequestUninstall(query.SecondToEndSearch),
|
||||
Settings.UpdateCommand => await pluginManager.RequestUpdateAsync(query.SecondToEndSearch, token, query.IsReQuery),
|
||||
_ => pluginManager.GetDefaultHotKeys().Where(hotkey =>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
{
|
||||
internal class PluginsManager
|
||||
{
|
||||
const string zip = "zip";
|
||||
private const string zip = "zip";
|
||||
|
||||
private PluginInitContext Context { get; set; }
|
||||
|
||||
|
|
@ -144,34 +144,43 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
try
|
||||
{
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!plugin.IsFromLocalInstallPath)
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
|
||||
await DownloadFileAsync(
|
||||
$"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}",
|
||||
plugin.UrlDownload, filePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = plugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
Install(plugin, filePath);
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
return;
|
||||
else
|
||||
Install(plugin, filePath);
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
// show error message
|
||||
Context.API.ShowMsgError(
|
||||
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), plugin.Name),
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_download_error"));
|
||||
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// show error message
|
||||
Context.API.ShowMsgError(Context.API.GetTranslation("plugin_pluginsmanager_install_error_title"),
|
||||
string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),
|
||||
plugin.Name));
|
||||
Log.Exception("PluginsManager", "An error occurred while downloading plugin", e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -190,6 +199,41 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
}
|
||||
}
|
||||
|
||||
private async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true)
|
||||
{
|
||||
if (deleteFile && File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
if (showProgress)
|
||||
{
|
||||
var exceptionHappened = false;
|
||||
await Context.API.ShowProgressBoxAsync(prgBoxTitle,
|
||||
async (reportProgress) =>
|
||||
{
|
||||
if (reportProgress == null)
|
||||
{
|
||||
// when reportProgress is null, it means there is expcetion with the progress box
|
||||
// so we record it with exceptionHappened and return so that progress box will close instantly
|
||||
exceptionHappened = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}, cts.Cancel);
|
||||
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!cts.IsCancellationRequested))
|
||||
await Context.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Context.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
internal async ValueTask<List<Result>> RequestUpdateAsync(string search, CancellationToken token,
|
||||
bool usePrimaryUrlOnly = false)
|
||||
{
|
||||
|
|
@ -277,43 +321,48 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
_ = Task.Run(async delegate
|
||||
{
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!x.PluginNewUserPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
if (File.Exists(downloadToFilePath))
|
||||
{
|
||||
File.Delete(downloadToFilePath);
|
||||
}
|
||||
|
||||
await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath)
|
||||
.ConfigureAwait(false);
|
||||
await DownloadFileAsync(
|
||||
$"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {x.PluginNewUserPlugin.Name}",
|
||||
x.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
downloadToFilePath = x.PluginNewUserPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
|
||||
PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin,
|
||||
downloadToFilePath);
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
{
|
||||
Context.API.ShowMsg(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation(
|
||||
"plugin_pluginsmanager_update_success_restart"),
|
||||
x.Name));
|
||||
Context.API.RestartApp();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.API.ShowMsg(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation(
|
||||
"plugin_pluginsmanager_update_success_no_restart"),
|
||||
x.Name));
|
||||
PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin,
|
||||
downloadToFilePath);
|
||||
|
||||
if (Settings.AutoRestartAfterChanging)
|
||||
{
|
||||
Context.API.ShowMsg(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation(
|
||||
"plugin_pluginsmanager_update_success_restart"),
|
||||
x.Name));
|
||||
Context.API.RestartApp();
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.API.ShowMsg(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation(
|
||||
"plugin_pluginsmanager_update_success_no_restart"),
|
||||
x.Name));
|
||||
}
|
||||
}
|
||||
}).ContinueWith(t =>
|
||||
{
|
||||
|
|
@ -324,7 +373,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"),
|
||||
x.Name));
|
||||
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||
}, token, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
|
@ -337,7 +386,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
});
|
||||
|
||||
// Update all result
|
||||
if (resultsForUpdate.Count() > 1)
|
||||
if (resultsForUpdate.Count > 1)
|
||||
{
|
||||
var updateAllResult = new Result
|
||||
{
|
||||
|
|
@ -351,13 +400,13 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
{
|
||||
message = string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt"),
|
||||
resultsForUpdate.Count(), Environment.NewLine);
|
||||
resultsForUpdate.Count, Environment.NewLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
message = string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_all_prompt_no_restart"),
|
||||
resultsForUpdate.Count());
|
||||
resultsForUpdate.Count);
|
||||
}
|
||||
|
||||
if (Context.API.ShowMsgBox(message,
|
||||
|
|
@ -374,16 +423,18 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
try
|
||||
{
|
||||
if (File.Exists(downloadToFilePath))
|
||||
{
|
||||
File.Delete(downloadToFilePath);
|
||||
}
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
await Http.DownloadAsync(plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath)
|
||||
.ConfigureAwait(false);
|
||||
await DownloadFileAsync(
|
||||
$"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.PluginNewUserPlugin.Name}",
|
||||
plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
|
||||
|
||||
PluginManager.UpdatePlugin(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin,
|
||||
downloadToFilePath);
|
||||
// check if user cancelled download before installing plugin
|
||||
if (cts.IsCancellationRequested)
|
||||
return;
|
||||
else
|
||||
PluginManager.UpdatePlugin(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin,
|
||||
downloadToFilePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -401,7 +452,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_restart"),
|
||||
resultsForUpdate.Count()));
|
||||
resultsForUpdate.Count));
|
||||
Context.API.RestartApp();
|
||||
}
|
||||
else
|
||||
|
|
@ -409,7 +460,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_all_success_no_restart"),
|
||||
resultsForUpdate.Count()));
|
||||
resultsForUpdate.Count));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -545,7 +596,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
Context.API.GetAllPlugins().Any(x => x.Metadata.Website.StartsWith(constructedUrlPart));
|
||||
}
|
||||
|
||||
internal async ValueTask<List<Result>> RequestInstallOrUpdate(string search, CancellationToken token,
|
||||
internal async ValueTask<List<Result>> RequestInstallOrUpdateAsync(string search, CancellationToken token,
|
||||
bool usePrimaryUrlOnly = false)
|
||||
{
|
||||
await PluginsManifest.UpdateManifestAsync(token, usePrimaryUrlOnly);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
"Name": "Plugins Manager",
|
||||
"Description": "Management of installing, uninstalling or updating Flow Launcher plugins",
|
||||
"Author": "Jeremy Wu",
|
||||
"Version": "3.2.3",
|
||||
"Version": "3.2.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name":"Process Killer",
|
||||
"Description":"Kill running processes from Flow",
|
||||
"Author":"Flow-Launcher",
|
||||
"Version":"3.0.7",
|
||||
"Version":"3.0.8",
|
||||
"Language":"csharp",
|
||||
"Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller",
|
||||
"IcoPath":"Images\\app.png",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Program",
|
||||
"Description": "Search programs in Flow.Launcher",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.3.3",
|
||||
"Version": "3.3.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Shell",
|
||||
"Description": "Provide executing commands from Flow Launcher",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.2.4",
|
||||
"Version": "3.2.5",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "System Commands",
|
||||
"Description": "Provide System related commands. e.g. shutdown,lock, setting etc.",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.1.6",
|
||||
"Version": "3.1.7",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "URL",
|
||||
"Description": "Open the typed URL from Flow Launcher",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.0.7",
|
||||
"Version": "3.0.8",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Url.dll",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml version="1.0"?>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_window_title">Search Source Setting</system:String>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
"Name": "Web Searches",
|
||||
"Description": "Provide the web search ability",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "3.1.3",
|
||||
"Version": "3.1.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Description": "Search settings inside Control Panel and Settings App",
|
||||
"Name": "Windows Settings",
|
||||
"Author": "TobiasSekan",
|
||||
"Version": "4.0.11",
|
||||
"Version": "4.0.12",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
version: '1.19.4.{build}'
|
||||
version: '1.19.5.{build}'
|
||||
|
||||
init:
|
||||
- ps: |
|
||||
|
|
|
|||
Loading…
Reference in a new issue