Merge branch 'dev' into feat/reuse-tabs-in-bookmarks-plugin

This commit is contained in:
Andrzej Martyna 2025-12-28 18:08:34 +01:00 committed by GitHub
commit c8bf643c28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 170 additions and 325 deletions

View file

@ -14,4 +14,4 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Assign PR to creator
uses: toshimaru/auto-author-assign@v2.1.1
uses: toshimaru/auto-author-assign@v3.0.1

View file

@ -496,6 +496,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
await _foregroundChangeLock.WaitAsync();
try
{
@ -647,6 +649,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
// If the dialog window is moved, update the Dialog Jump window position
var dialogWindowExist = false;
lock (_dialogWindowLock)
@ -672,6 +676,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
// If the dialog window is moved or resized, update the Dialog Jump window position
if (_dragMoveTimer != null)
{
@ -697,6 +703,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
// If the dialog window is destroyed, set _dialogWindowHandle to null
var dialogWindowExist = false;
lock (_dialogWindowLock)
@ -728,6 +736,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
// If the dialog window is hidden, set _dialogWindowHandle to null
var dialogWindowExist = false;
lock (_dialogWindowLock)
@ -759,6 +769,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
if (hwnd.IsNull) return;
// If the dialog window is ended, set _dialogWindowHandle to null
var dialogWindowExist = false;
lock (_dialogWindowLock)

View file

@ -138,7 +138,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.10.1" />
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.10.2.1" />
<PackageReference Include="MdXaml" Version="1.27.0" />
<PackageReference Include="MdXaml.AnimatedGif" Version="1.27.0" />
<PackageReference Include="MdXaml.Html" Version="1.27.0" />

View file

@ -143,6 +143,8 @@ internal static class HotKeyMapper
return;
App.API.ShowMainWindow();
// Make sure to go back to the query results page first since it can cause issues if current page is context menu
App.API.BackToQueryResults();
App.API.ChangeQuery(hotkey.ActionKeyword, true);
});
}

View file

@ -64,10 +64,10 @@
<system:String x:Key="PositionReset">位置のリセット</system:String>
<system:String x:Key="PositionResetToolTip">検索ウィンドウの位置をリセット</system:String>
<system:String x:Key="queryTextBoxPlaceholder">ここに入力して検索</system:String>
<system:String x:Key="pluginStillInitializing">{0}: This plugin is still initializing...</system:String>
<system:String x:Key="pluginStillInitializingSubtitle">Select this result to requery</system:String>
<system:String x:Key="pluginFailedToRespond">{0}: Failed to respond!</system:String>
<system:String x:Key="pluginFailedToRespondSubtitle">Select this result for more info</system:String>
<system:String x:Key="pluginStillInitializing">{0}: このプラグインはまだ初期化中です…</system:String>
<system:String x:Key="pluginStillInitializingSubtitle">この結果を選択して再検索する</system:String>
<system:String x:Key="pluginFailedToRespond">{0}: 応答に失敗しました!</system:String>
<system:String x:Key="pluginFailedToRespondSubtitle">詳細については、この結果を選択してください</system:String>
<!-- Setting General -->
<system:String x:Key="flowlauncher_settings">設定</system:String>
@ -454,7 +454,7 @@
<system:String x:Key="icons">アイコン</system:String>
<system:String x:Key="about_activate_times">あなたはFlow Launcherを {0} 回利用しました</system:String>
<system:String x:Key="checkUpdates">アップデートを確認する</system:String>
<system:String x:Key="BecomeASponsor">Become a Sponsor</system:String>
<system:String x:Key="BecomeASponsor">スポンサーになる</system:String>
<system:String x:Key="newVersionTips">新しいバージョン {0} が利用可能です。Flow Launcherを再起動してください。</system:String>
<system:String x:Key="checkUpdatesFailed">アップデートの確認に失敗しました、api.github.com への接続とプロキシ設定を確認してください。</system:String>
<system:String x:Key="downloadUpdatesFailed">

View file

@ -420,13 +420,13 @@
<system:String x:Key="DialogJumpWindowPositionFollowDefault">Default search window position. Displayed when triggered by search window hotkey</system:String>
<system:String x:Key="dialogJumpResultBehaviour">Dialog Jump Result Navigation Behaviour</system:String>
<system:String x:Key="dialogJumpResultBehaviourToolTip">Behaviour to navigate Open/Save As dialog window to the selected result path</system:String>
<system:String x:Key="DialogJumpResultBehaviourLeftClick">Left click or Enter key</system:String>
<system:String x:Key="DialogJumpResultBehaviourRightClick">Right click</system:String>
<system:String x:Key="DialogJumpResultBehaviourLeftClick">Clique esquerdo ou tecla Enter</system:String>
<system:String x:Key="DialogJumpResultBehaviourRightClick">Clique direito</system:String>
<system:String x:Key="dialogJumpFileResultBehaviour">Dialog Jump File Navigation Behaviour</system:String>
<system:String x:Key="dialogJumpFileResultBehaviourToolTip">Behaviour to navigate Open/Save As dialog window when the result is a file path</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourFullPath">Fill full path in file name box</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourFullPathOpen">Fill full path in file name box and open</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourDirectory">Fill directory in path box</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourFullPath">Preencher caminho total na caixa Nome do ficheiro</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourFullPathOpen">Preencher caminho total na caixa Nome do ficheiro e abrir</system:String>
<system:String x:Key="DialogJumpFileResultBehaviourDirectory">Preencher diretório na caixa Caminho</system:String>
<!-- Setting Proxy -->
<system:String x:Key="proxy">Proxy HTTP</system:String>

View file

@ -636,7 +636,7 @@ Ak pri zadávaní skratky pred ňu pridáte &quot;@&quot;, bude sa zhodovať s
<!-- Plugin Update Window -->
<system:String x:Key="restartAfterUpdating">Po aktualizácii pluginov reštartovať Flow Launcher</system:String>
<system:String x:Key="updatePluginCheckboxContent">{0}: Aktualizované z v{1} na v{2}</system:String>
<system:String x:Key="updatePluginCheckboxContent">{0}: Aktualizácia z v{1} na v{2}</system:String>
<system:String x:Key="updatePluginNoSelected">Nie je vybraný žiaden plugin</system:String>
<!-- Welcome Window -->

View file

@ -526,7 +526,7 @@
<TextBlock
x:Name="PreviewSubTitle"
Style="{DynamicResource PreviewItemSubTitleStyle}"
Text="{Binding Result.SubTitle}" />
Text="{Binding PreviewDescription}" />
</StackPanel>
</Grid>
</Border>

View file

@ -1,253 +0,0 @@
using iNKORE.UI.WPF.Modern.Controls;
using iNKORE.UI.WPF.Modern.Controls.Helpers;
using iNKORE.UI.WPF.Modern.Controls.Primitives;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Flow.Launcher.Resources.Controls
{
// TODO: Use IsScrollAnimationEnabled property in future: https://github.com/iNKORE-NET/UI.WPF.Modern/pull/347
public class CustomScrollViewerEx : ScrollViewer
{
private double LastVerticalLocation = 0;
private double LastHorizontalLocation = 0;
public CustomScrollViewerEx()
{
Loaded += OnLoaded;
var valueSource = DependencyPropertyHelper.GetValueSource(this, AutoPanningMode.IsEnabledProperty).BaseValueSource;
if (valueSource == BaseValueSource.Default)
{
AutoPanningMode.SetIsEnabled(this, true);
}
}
#region Orientation
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(
nameof(Orientation),
typeof(Orientation),
typeof(CustomScrollViewerEx),
new PropertyMetadata(Orientation.Vertical));
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
#endregion
#region AutoHideScrollBars
public static readonly DependencyProperty AutoHideScrollBarsProperty =
ScrollViewerHelper.AutoHideScrollBarsProperty
.AddOwner(
typeof(CustomScrollViewerEx),
new PropertyMetadata(true, OnAutoHideScrollBarsChanged));
public bool AutoHideScrollBars
{
get => (bool)GetValue(AutoHideScrollBarsProperty);
set => SetValue(AutoHideScrollBarsProperty, value);
}
private static void OnAutoHideScrollBarsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is CustomScrollViewerEx sv)
{
sv.UpdateVisualState();
}
}
#endregion
private void OnLoaded(object sender, RoutedEventArgs e)
{
LastVerticalLocation = VerticalOffset;
LastHorizontalLocation = HorizontalOffset;
UpdateVisualState(false);
}
/// <inheritdoc/>
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
if (Style == null && ReadLocalValue(StyleProperty) == DependencyProperty.UnsetValue)
{
SetResourceReference(StyleProperty, typeof(ScrollViewer));
}
}
/// <inheritdoc/>
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
var Direction = GetDirection();
ScrollViewerBehavior.SetIsAnimating(this, true);
if (Direction == Orientation.Vertical)
{
if (ScrollableHeight > 0)
{
e.Handled = true;
}
var WheelChange = e.Delta * (ViewportHeight / 1.5) / ActualHeight;
var newOffset = LastVerticalLocation - WheelChange;
if (newOffset < 0)
{
newOffset = 0;
}
if (newOffset > ScrollableHeight)
{
newOffset = ScrollableHeight;
}
if (newOffset == LastVerticalLocation)
{
return;
}
ScrollToVerticalOffset(LastVerticalLocation);
ScrollToValue(newOffset, Direction);
LastVerticalLocation = newOffset;
}
else
{
if (ScrollableWidth > 0)
{
e.Handled = true;
}
var WheelChange = e.Delta * (ViewportWidth / 1.5) / ActualWidth;
var newOffset = LastHorizontalLocation - WheelChange;
if (newOffset < 0)
{
newOffset = 0;
}
if (newOffset > ScrollableWidth)
{
newOffset = ScrollableWidth;
}
if (newOffset == LastHorizontalLocation)
{
return;
}
ScrollToHorizontalOffset(LastHorizontalLocation);
ScrollToValue(newOffset, Direction);
LastHorizontalLocation = newOffset;
}
}
/// <inheritdoc/>
protected override void OnScrollChanged(ScrollChangedEventArgs e)
{
base.OnScrollChanged(e);
if (!ScrollViewerBehavior.GetIsAnimating(this))
{
LastVerticalLocation = VerticalOffset;
LastHorizontalLocation = HorizontalOffset;
}
}
private Orientation GetDirection()
{
var isShiftDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
if (Orientation == Orientation.Horizontal)
{
return isShiftDown ? Orientation.Vertical : Orientation.Horizontal;
}
else
{
return isShiftDown ? Orientation.Horizontal : Orientation.Vertical;
}
}
/// <summary>
/// Causes the <see cref="ScrollViewerEx"/> to load a new view into the viewport using the specified offsets and zoom factor.
/// </summary>
/// <param name="horizontalOffset">A value between 0 and <see cref="ScrollViewer.ScrollableWidth"/> that specifies the distance the content should be scrolled horizontally.</param>
/// <param name="verticalOffset">A value between 0 and <see cref="ScrollViewer.ScrollableHeight"/> that specifies the distance the content should be scrolled vertically.</param>
/// <param name="zoomFactor">A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor.</param>
/// <returns><see langword="true"/> if the view is changed; otherwise, <see langword="false"/>.</returns>
public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor)
{
return ChangeView(horizontalOffset, verticalOffset, zoomFactor, false);
}
/// <summary>
/// Causes the <see cref="ScrollViewerEx"/> to load a new view into the viewport using the specified offsets and zoom factor, and optionally disables scrolling animation.
/// </summary>
/// <param name="horizontalOffset">A value between 0 and <see cref="ScrollViewer.ScrollableWidth"/> that specifies the distance the content should be scrolled horizontally.</param>
/// <param name="verticalOffset">A value between 0 and <see cref="ScrollViewer.ScrollableHeight"/> that specifies the distance the content should be scrolled vertically.</param>
/// <param name="zoomFactor">A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor.</param>
/// <param name="disableAnimation"><see langword="true"/> to disable zoom/pan animations while changing the view; otherwise, <see langword="false"/>. The default is false.</param>
/// <returns><see langword="true"/> if the view is changed; otherwise, <see langword="false"/>.</returns>
public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation)
{
if (disableAnimation)
{
if (horizontalOffset.HasValue)
{
ScrollToHorizontalOffset(horizontalOffset.Value);
}
if (verticalOffset.HasValue)
{
ScrollToVerticalOffset(verticalOffset.Value);
}
}
else
{
if (horizontalOffset.HasValue)
{
ScrollToHorizontalOffset(LastHorizontalLocation);
ScrollToValue(Math.Min(ScrollableWidth, horizontalOffset.Value), Orientation.Horizontal);
LastHorizontalLocation = horizontalOffset.Value;
}
if (verticalOffset.HasValue)
{
ScrollToVerticalOffset(LastVerticalLocation);
ScrollToValue(Math.Min(ScrollableHeight, verticalOffset.Value), Orientation.Vertical);
LastVerticalLocation = verticalOffset.Value;
}
}
return true;
}
private void ScrollToValue(double value, Orientation Direction)
{
if (Direction == Orientation.Vertical)
{
ScrollToVerticalOffset(value);
}
else
{
ScrollToHorizontalOffset(value);
}
ScrollViewerBehavior.SetIsAnimating(this, false);
}
private void UpdateVisualState(bool useTransitions = true)
{
var stateName = AutoHideScrollBars ? "NoIndicator" : "MouseIndicator";
VisualStateManager.GoToState(this, stateName, useTransitions);
}
}
}

View file

@ -252,12 +252,14 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<cc:CustomScrollViewerEx
<ui:ScrollViewerEx
x:Name="ListBoxScrollViewer"
Focusable="False"
IsScrollAnimationEnabled="False"
RewriteWheelChange="True"
Template="{DynamicResource ScrollViewerControlTemplate}">
<cc:CustomScrollViewerEx.Style>
<Style TargetType="cc:CustomScrollViewerEx">
<ui:ScrollViewerEx.Style>
<Style TargetType="ui:ScrollViewerEx">
<Style.Triggers>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Visible">
<Setter Property="Margin" Value="0 0 0 0" />
@ -269,9 +271,9 @@
</Trigger>
</Style.Triggers>
</Style>
</cc:CustomScrollViewerEx.Style>
</ui:ScrollViewerEx.Style>
<VirtualizingStackPanel IsItemsHost="True" />
</cc:CustomScrollViewerEx>
</ui:ScrollViewerEx>
</ControlTemplate>
</Setter.Value>
</Setter>

View file

@ -288,6 +288,8 @@ namespace Flow.Launcher.ViewModel
}
}
public string PreviewDescription => Result.Preview?.Description ?? Result.SubTitle;
public Result Result { get; }
public int ResultProgress
{

View file

@ -28,9 +28,9 @@
},
"iNKORE.UI.WPF.Modern": {
"type": "Direct",
"requested": "[0.10.1, )",
"resolved": "0.10.1",
"contentHash": "nRYmBosiL+42eUpLbHeqP7qJqtp5EpzuIMZTpvq4mFV33VB/JjkFg1y82gk50pjkXlAQWDvRyrfSAmPR5AM+3g==",
"requested": "[0.10.2.1, )",
"resolved": "0.10.2.1",
"contentHash": "nGwuuVul+TcLCTgPmaAZCc0fYFqUpCNZ8PiulVT3gZnsWt/AvxMZ0DSPpuyI/iRPc/NhFIg9lSIR7uaHWV0I/Q==",
"dependencies": {
"iNKORE.UI.WPF": "1.2.8"
}
@ -1619,7 +1619,7 @@
"FSharp.Core": "[9.0.303, )",
"Flow.Launcher.Infrastructure": "[1.0.0, )",
"Flow.Launcher.Localization": "[0.0.6, )",
"Flow.Launcher.Plugin": "[5.0.0, )",
"Flow.Launcher.Plugin": "[5.1.0, )",
"Meziantou.Framework.Win32.Jobs": "[3.4.5, )",
"Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )",
"SemanticVersioning": "[3.0.0, )",
@ -1634,7 +1634,7 @@
"BitFaster.Caching": "[2.5.4, )",
"CommunityToolkit.Mvvm": "[8.4.0, )",
"Flow.Launcher.Localization": "[0.0.6, )",
"Flow.Launcher.Plugin": "[5.0.0, )",
"Flow.Launcher.Plugin": "[5.1.0, )",
"InputSimulator": "[1.0.4, )",
"MemoryPack": "[1.21.4, )",
"Microsoft.VisualStudio.Threading": "[17.14.15, )",

View file

@ -106,7 +106,7 @@
<PackageReference Include="BrowserTabs" Version="0.2.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.0" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.1" />
<PackageReference Include="Svg.Skia" Version="3.2.1" />
<PackageReference Include="SkiaSharp" Version="3.119.1" />
</ItemGroup>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">بحث في محتوى الملفات:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">بحث مفهرس:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">وصول سريع:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">الكلمة المفتاحية الحالية للإجراء</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">تم</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">مفعّل</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Vyhledávání obsahu souborů:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Vyhledávání v indexu:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Rychlý přístup:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Aktuální aktivační příkaz</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Hotovo</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Povoleno</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Færdig</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Suche nach Dateiinhalten:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index-Suche:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Schnellzugriff:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Aktuelles Aktions-Schlüsselwort</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Fertig</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Aktiviert</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Hecho</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Búsqueda de contenido de archivo:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Buscar índice:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Acceso rápido:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Palabra clave de acción actual</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Aceptar</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Activado</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Recherche de contenu de fichier :</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Recherche dans l'index :</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Accès rapide :</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Recherche de dossier :</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">Recherche de fichier :</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Mot-clé de l'action en cours</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Terminer</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Activé</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">חיפוש תוכן קובץ:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">חיפוש אינדקס:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">גישה מהירה:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">מילת פעולה נוכחית</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">בוצע</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">מופעל</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Ricerca Contenuto File:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Ricerca in Indice:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Accesso Rapido:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Parola Chiave Corrente</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Conferma</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Abilitato</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">完了</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">파일 내용 검색:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">색인 검색:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">빠른 접근:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">현재 액션 키워드</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">완료</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">켬</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Søk etter filinnhold:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Indekssøk:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Hurtigtilgang:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Nåværende nøkkelord for handling</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Utført</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Aktivert</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Klaar</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Przeszukiwanie zawartości plików:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Wyszukiwanie indeksowe:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Szybki dostęp:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Bieżące słowo kluczowe akcji</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Zapisz</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Aktywny</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Finalizado</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Pesquisa no conteúdo dos ficheiros:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Pesquisa no índice:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Acesso rápido:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Pesquisar pasta:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">Pesquisar ficheiro:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Palavra-chave atual</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">OK</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Ativo</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Подтвердить</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Включено</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Vyhľadávanie obsahu súborov:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Vyhľadávanie v indexe:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Rýchly prístup:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Vyhľadávanie priečinkov:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">Vyhľadávanie súborov:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Aktuálny aktivačný príkaz</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Hotovo</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Povolené</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Done</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Quick Access:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Gotovo</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Enabled</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Dosya İçeriğini Ara:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Dizin Araması:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Hızlı Erişim:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Geçerli Anahtar Kelime</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Tamam</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Etkin</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Пошук вмісту файлу:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Індексний пошук:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Швидкий доступ:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Пошук теки:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">Пошук файлу:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Поточне ключове слово дії</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Готово</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Увімкнено</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">Tìm kiếm nội dung tệp:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Tìm kiếm chỉ mục:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">Truy cập nhanh</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Từ hành động hiện tại</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">Xong</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">Đã bật</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">文件内容搜索:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">索引搜索:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">快速访问:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">目录搜索:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">文件搜索:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">当前触发关键字</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">确认</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">已启用</system:String>

View file

@ -56,6 +56,8 @@
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_indexsearch">Index Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_quickaccess">快速存取:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_foldersearch">Folder Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeywordview_filesearch">File Search:</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_current">Current Action Keyword</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_done">確</system:String>
<system:String x:Key="plugin_explorer_actionkeyword_enabled">已啟用</system:String>

View file

@ -334,7 +334,7 @@ namespace Flow.Launcher.Plugin.Program
}
}
public static async Task IndexWin32ProgramsAsync()
public static async Task IndexWin32ProgramsAsync(bool resetCache)
{
await _win32sLock.WaitAsync();
try
@ -345,7 +345,10 @@ namespace Flow.Launcher.Plugin.Program
{
_win32s.Add(win32);
}
ResetCache();
if (resetCache)
{
ResetCache();
}
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
lock (_lastIndexTimeLock)
{
@ -362,7 +365,7 @@ namespace Flow.Launcher.Plugin.Program
}
}
public static async Task IndexUwpProgramsAsync()
public static async Task IndexUwpProgramsAsync(bool resetCache)
{
await _uwpsLock.WaitAsync();
try
@ -373,7 +376,10 @@ namespace Flow.Launcher.Plugin.Program
{
_uwps.Add(uwp);
}
ResetCache();
if (resetCache)
{
ResetCache();
}
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
lock (_lastIndexTimeLock)
{
@ -394,12 +400,12 @@ namespace Flow.Launcher.Plugin.Program
{
var win32Task = Task.Run(async () =>
{
await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", IndexWin32ProgramsAsync);
await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", () => IndexWin32ProgramsAsync(resetCache: true));
});
var uwpTask = Task.Run(async () =>
{
await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", IndexUwpProgramsAsync);
await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", () => IndexUwpProgramsAsync(resetCache: true));
});
await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false);
@ -407,9 +413,21 @@ namespace Flow.Launcher.Plugin.Program
internal static void ResetCache()
{
var oldCache = cache;
cache = new MemoryCache(cacheOptions);
oldCache.Dispose();
var newCache = new MemoryCache(cacheOptions);
// Atomically swap and get the previous cache instance, avoids double-dispose/lost-assignment race
// where each caller receives a distinct prior instance to dispose.
var oldCache = Interlocked.Exchange(ref cache, newCache);
// Dispose the previous instance (if any)- each caller gets a unique prior instance from above
try
{
oldCache?.Dispose();
}
catch (Exception e)
{
Context.API.LogException(ClassName, "Failed to dispose old program cache", e);
}
}
public Control CreateSettingPanel()
@ -442,12 +460,26 @@ namespace Flow.Launcher.Plugin.Program
Title = Context.API.GetTranslation("flowlauncher_plugin_program_disable_program"),
Action = c =>
{
_ = DisableProgramAsync(program);
Context.API.ShowMsg(
Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
Context.API.GetTranslation(
"flowlauncher_plugin_program_disable_dlgtitle_success_message"));
Context.API.ReQuery();
_ = Task.Run(async () =>
{
try
{
var disabled = await DisableProgramAsync(program);
if (disabled)
{
ResetCache();
Context.API.ShowMsg(
Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
Context.API.GetTranslation(
"flowlauncher_plugin_program_disable_dlgtitle_success_message"));
}
Context.API.ReQuery();
}
catch (Exception e)
{
Context.API.LogException(ClassName, "Failed to disable program", e);
}
});
return false;
},
IcoPath = "Images/disable.png",
@ -458,52 +490,50 @@ namespace Flow.Launcher.Plugin.Program
return menuOptions;
}
private static async Task DisableProgramAsync(IProgram programToDelete)
private static async Task<bool> DisableProgramAsync(IProgram programToDelete)
{
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
return;
{
return false;
}
await _uwpsLock.WaitAsync();
var reindexUwps = true;
try
{
reindexUwps = _uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
var program = _uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
if (program != null)
{
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
// Reindex UWP programs
_ = Task.Run(() => IndexUwpProgramsAsync(resetCache: false));
return true;
}
}
finally
{
_uwpsLock.Release();
}
// Reindex UWP programs
if (reindexUwps)
{
_ = Task.Run(IndexUwpProgramsAsync);
return;
}
await _win32sLock.WaitAsync();
var reindexWin32s = true;
try
{
reindexWin32s = _win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
var program = _win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
if (program != null)
{
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
// Reindex Win32 programs
_ = Task.Run(() => IndexWin32ProgramsAsync(resetCache: false));
return true;
}
}
finally
{
_win32sLock.Release();
}
// Reindex Win32 programs
if (reindexWin32s)
{
_ = Task.Run(IndexWin32ProgramsAsync);
return;
}
return false;
}
public static void StartProcess(Func<ProcessStartInfo, Process> runProcess, ProcessStartInfo info)

View file

@ -290,7 +290,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
private static readonly Channel<byte> PackageChangeChannel = Channel.CreateBounded<byte>(1);
private static PackageCatalog? catalog;
private static PackageCatalog catalog;
public static async Task WatchPackageChangeAsync()
{
@ -317,7 +317,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
await Task.Delay(3000).ConfigureAwait(false);
PackageChangeChannel.Reader.TryRead(out _);
await Task.Run(Main.IndexUwpProgramsAsync);
await Main.IndexUwpProgramsAsync(resetCache: true).ConfigureAwait(false);
}
}
}

View file

@ -796,7 +796,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
}
await Task.Run(Main.IndexWin32ProgramsAsync);
await Main.IndexWin32ProgramsAsync(resetCache: true).ConfigureAwait(false);
}
}

View file

@ -246,9 +246,9 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
<img src="https://user-images.githubusercontent.com/6903107/144533523-afd79dca-a444-40e5-b2d9-6d3fe3aaece1.png" width="400">
### [Clipboard History](https://github.com/liberize/Flow.Launcher.Plugin.ClipboardHistory)
### [Clipboard+](https://github.com/Jack251970/Flow.Launcher.Plugin.ClipboardPlus)
<img src="https://user-images.githubusercontent.com/6903107/144533481-58e473fd-38d9-4604-861f-ad870770967d.png" width="400">
<img src="https://github.com/user-attachments/assets/4a001dc9-0895-4670-a911-e5b81c70f571" width="400">
### [Home Assistant Commander](https://github.com/Garulf/HA-Commander)
@ -348,8 +348,8 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
<a href="https://github.com/TheBestPessimist">
<img src='https://avatars.githubusercontent.com/u/4482210?v=4' width="10%"/>
</a>
<a href="https://github.com/AjmalParkar006">
<img src='https://avatars.githubusercontent.com/u/76547256?v=4' width="10%"/>
<a href="https://github.com/Calapine">
<img src='https://avatars.githubusercontent.com/u/76205879?v=4' width="10%"/>
</a>
</p>
<p align="center">