Skip to content

Commit 70e530b

Browse files
committed
add QuickLook plugin for testing
1 parent b345944 commit 70e530b

File tree

9 files changed

+493
-21
lines changed

9 files changed

+493
-21
lines changed

Flow.Launcher.sln

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@ MinimumVisualStudioVersion = 10.0.40219.1
55
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launcher\Flow.Launcher.csproj", "{DB90F671-D861-46BB-93A3-F1304F5BA1C5}"
66
ProjectSection(ProjectDependencies) = postProject
77
{0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {0B9DE348-9361-4940-ADB6-F5953BFFCCEC}
8+
{403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E}
89
{4792A74A-0CEA-4173-A8B2-30E6764C6217} = {4792A74A-0CEA-4173-A8B2-30E6764C6217}
9-
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
10-
{F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}
10+
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {5043CECE-E6A7-4867-9CBE-02D27D83747A}
11+
{588088F4-3262-4F9F-9663-A05DE12534C3} = {588088F4-3262-4F9F-9663-A05DE12534C3}
1112
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
12-
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
13+
{758F3331-8D38-49F9-913C-60A18A8AEF3B} = {758F3331-8D38-49F9-913C-60A18A8AEF3B}
1314
{9B130CC5-14FB-41FF-B310-0A95B6894C37} = {9B130CC5-14FB-41FF-B310-0A95B6894C37}
14-
{FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A}
1515
{A3DCCBCA-ACC1-421D-B16E-210896234C26} = {A3DCCBCA-ACC1-421D-B16E-210896234C26}
16-
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {5043CECE-E6A7-4867-9CBE-02D27D83747A}
17-
{403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E}
18-
{588088F4-3262-4F9F-9663-A05DE12534C3} = {588088F4-3262-4F9F-9663-A05DE12534C3}
16+
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
17+
{F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}
18+
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
19+
{FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A}
1920
EndProjectSection
2021
EndProject
2122
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Test", "Flow.Launcher.Test\Flow.Launcher.Test.csproj", "{FF742965-9A80-41A5-B042-D6C7D3A21708}"
@@ -70,6 +71,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Plugin
7071
EndProject
7172
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.WindowsSettings", "Plugins\Flow.Launcher.Plugin.WindowsSettings\Flow.Launcher.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}"
7273
EndProject
74+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flow.Launcher.Plugin.QuickLook", "plugins\Flow.Launcher.Plugin.QuickLook\Flow.Launcher.Plugin.QuickLook.csproj", "{758F3331-8D38-49F9-913C-60A18A8AEF3B}"
75+
EndProject
7376
Global
7477
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7578
Debug|Any CPU = Debug|Any CPU
@@ -80,8 +83,19 @@ Global
8083
Release|x86 = Release|x86
8184
EndGlobalSection
8285
GlobalSection(ProjectConfigurationPlatforms) = postSolution
86+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
87+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
88+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x64.ActiveCfg = Debug|Any CPU
89+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x64.Build.0 = Debug|Any CPU
90+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x86.ActiveCfg = Debug|Any CPU
91+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x86.Build.0 = Debug|Any CPU
92+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
93+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|Any CPU.Build.0 = Release|Any CPU
94+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x64.ActiveCfg = Release|Any CPU
95+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x64.Build.0 = Release|Any CPU
96+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x86.ActiveCfg = Release|Any CPU
97+
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x86.Build.0 = Release|Any CPU
8398
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
84-
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|Any CPU.Build.0 = Debug|Any CPU
8599
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|Any CPU
86100
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|Any CPU
87101
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x86.ActiveCfg = Debug|Any CPU
@@ -104,18 +118,6 @@ Global
104118
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x64.Build.0 = Release|Any CPU
105119
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.ActiveCfg = Release|Any CPU
106120
{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}.Release|x86.Build.0 = Release|Any CPU
107-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
108-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
109-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x64.ActiveCfg = Debug|Any CPU
110-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x64.Build.0 = Debug|Any CPU
111-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x86.ActiveCfg = Debug|Any CPU
112-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Debug|x86.Build.0 = Debug|Any CPU
113-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
114-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|Any CPU.Build.0 = Release|Any CPU
115-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x64.ActiveCfg = Release|Any CPU
116-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x64.Build.0 = Release|Any CPU
117-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x86.ActiveCfg = Release|Any CPU
118-
{DB90F671-D861-46BB-93A3-F1304F5BA1C5}.Release|x86.Build.0 = Release|Any CPU
119121
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
120122
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
121123
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -285,6 +287,18 @@ Global
285287
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.Build.0 = Release|Any CPU
286288
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.ActiveCfg = Release|Any CPU
287289
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x86.Build.0 = Release|Any CPU
290+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
291+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
292+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|x64.ActiveCfg = Debug|Any CPU
293+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|x64.Build.0 = Debug|Any CPU
294+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|x86.ActiveCfg = Debug|Any CPU
295+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Debug|x86.Build.0 = Debug|Any CPU
296+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
297+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|Any CPU.Build.0 = Release|Any CPU
298+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|x64.ActiveCfg = Release|Any CPU
299+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|x64.Build.0 = Release|Any CPU
300+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|x86.ActiveCfg = Release|Any CPU
301+
{758F3331-8D38-49F9-913C-60A18A8AEF3B}.Release|x86.Build.0 = Release|Any CPU
288302
EndGlobalSection
289303
GlobalSection(SolutionProperties) = preSolution
290304
HideSolutionNode = FALSE
@@ -302,6 +316,7 @@ Global
302316
{588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
303317
{4792A74A-0CEA-4173-A8B2-30E6764C6217} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
304318
{5043CECE-E6A7-4867-9CBE-02D27D83747A} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
319+
{758F3331-8D38-49F9-913C-60A18A8AEF3B} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
305320
EndGlobalSection
306321
GlobalSection(ExtensibilityGlobals) = postSolution
307322
SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Adapted from Files
2+
// https://github.com/files-community/Files/blob/ad33c75c53382fcb9b16fa9cd66ae5399f3dff0b/src/Files.App/Helpers/QuickLookHelpers.cs
3+
using System;
4+
using System.IO.Pipes;
5+
using System.IO;
6+
using System.Security.Principal;
7+
using System.Threading.Tasks;
8+
using Flow.Launcher.Infrastructure.Logger;
9+
using Flow.Launcher.Core.Resource;
10+
11+
namespace Flow.Launcher.Plugin.Explorer.Helper
12+
{
13+
internal static class QuickLookHelper
14+
{
15+
private const int TIMEOUT = 500;
16+
private static DateTime lastNotificationTime = DateTime.MinValue;
17+
18+
private static readonly string pipeName = $"QuickLook.App.Pipe.{WindowsIdentity.GetCurrent().User?.Value}";
19+
private static readonly string pipeMessageSwitch = "QuickLook.App.PipeMessages.Switch";
20+
private static readonly string pipeMessageToggle = "QuickLook.App.PipeMessages.Toggle";
21+
private static readonly string pipeMessageClose = "QuickLook.App.PipeMessages.Close";
22+
private static readonly string pipeMessageInvoke = "QuickLook.App.PipeMessages.Invoke";
23+
24+
25+
/// <summary>
26+
/// Toggle QuickLook
27+
/// </summary>
28+
/// <param name="path">File path to preview</param>
29+
/// <param name="sendFailToast">Send toast when fails.</param>
30+
/// <returns></returns>
31+
public static async Task<bool> ToggleQuickLookAsync(string path, bool sendFailToast = true)
32+
{
33+
if (string.IsNullOrEmpty(path))
34+
return false;
35+
36+
bool success = await SendQuickLookPipeMsgAsync(pipeMessageToggle, path);
37+
if (sendFailToast && !success)
38+
{
39+
//ShowQuickLookUnavailableToast();
40+
}
41+
return success;
42+
}
43+
44+
public static async Task<bool> CloseQuickLookAsync()
45+
{
46+
bool success = await SendQuickLookPipeMsgAsync(pipeMessageClose);
47+
return success;
48+
}
49+
50+
public static async Task<bool> OpenQuickLookAsync(string path, bool sendFailToast = true)
51+
{
52+
if (string.IsNullOrEmpty(path))
53+
return false;
54+
55+
bool success = await SendQuickLookPipeMsgAsync(pipeMessageInvoke, path);
56+
if (sendFailToast && !success)
57+
{
58+
//ShowQuickLookUnavailableToast();
59+
}
60+
return success;
61+
}
62+
63+
/// <summary>
64+
/// Switch QuickLook to preview another file if it's on
65+
/// </summary>
66+
/// <param name="path">File path to preview</param>
67+
/// <param name="sendFailToast">Send notification if fail</param>
68+
/// <returns></returns>
69+
public static async Task<bool> SwitchQuickLookAsync(string path, bool sendFailToast = true)
70+
{
71+
if (string.IsNullOrEmpty(path))
72+
return false;
73+
74+
bool success = await SendQuickLookPipeMsgAsync(pipeMessageSwitch, path);
75+
if (sendFailToast && !success)
76+
{
77+
//ShowQuickLookUnavailableToast();
78+
}
79+
return success;
80+
}
81+
82+
private static async Task<bool> SendQuickLookPipeMsgAsync(string message, string arg = "")
83+
{
84+
await using var client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
85+
try
86+
{
87+
await client.ConnectAsync(TIMEOUT);
88+
89+
await using var writer = new StreamWriter(client);
90+
await writer.WriteLineAsync($"{message}|{arg}");
91+
await writer.FlushAsync();
92+
}
93+
catch (TimeoutException)
94+
{
95+
client.Close();
96+
Log.Error($"{nameof(QuickLookHelper)}", "QuickLook timeout");
97+
return false;
98+
}
99+
catch (Exception e)
100+
{
101+
Log.Exception($"{nameof(QuickLookHelper)}", "QuickLook error", e);
102+
return false;
103+
}
104+
return true;
105+
}
106+
107+
public static async Task<bool> DetectQuickLookAvailabilityAsync()
108+
{
109+
static async Task<int> QuickLookServerAvailable()
110+
{
111+
await using var client = new NamedPipeClientStream(".", pipeName, PipeDirection.Out);
112+
try
113+
{
114+
await client.ConnectAsync(TIMEOUT);
115+
var serverInstances = client.NumberOfServerInstances;
116+
117+
await using var writer = new StreamWriter(client);
118+
await writer.WriteLineAsync($"{pipeMessageSwitch}|");
119+
await writer.FlushAsync();
120+
121+
return serverInstances;
122+
}
123+
catch (TimeoutException e)
124+
{
125+
client.Close();
126+
Log.Exception($"{nameof(QuickLookHelper)}", "QuickLook connection timeout", e);
127+
return 0;
128+
}
129+
}
130+
131+
try
132+
{
133+
var result = await QuickLookServerAvailable();
134+
return result != 0;
135+
}
136+
catch (Exception e)
137+
{
138+
Log.Exception($"{nameof(QuickLookHelper)}", "QuickLook unavailable", e);
139+
return false;
140+
}
141+
}
142+
143+
private static void ShowQuickLookUnavailableToast()
144+
{
145+
if (lastNotificationTime.AddSeconds(10) < DateTime.Now)
146+
{
147+
//Notification.Show(InternationalizationManager.Instance.GetTranslation("QuickLookFail"),
148+
// InternationalizationManager.Instance.GetTranslation("QuickLookFailTips"));
149+
lastNotificationTime = DateTime.Now;
150+
}
151+
}
152+
}
153+
}

Plugins/Flow.Launcher.Plugin.Explorer/Main.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace Flow.Launcher.Plugin.Explorer
1616
{
17-
public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n
17+
public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n, IAsyncExternalPreview
1818
{
1919
internal static PluginInitContext Context { get; set; }
2020

@@ -87,6 +87,27 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
8787
}
8888
}
8989

90+
public async Task TogglePreviewAsync(string path)
91+
{
92+
bool success = await QuickLookHelper.ToggleQuickLookAsync(path).ConfigureAwait(false);
93+
}
94+
public async Task ClosePreviewAsync()
95+
{
96+
bool success = await QuickLookHelper.CloseQuickLookAsync().ConfigureAwait(false);
97+
}
98+
99+
public async Task SwitchPreviewAsync(string path, bool sendFailToast = true)
100+
{
101+
// Switches preview content
102+
// When external is off, do nothing
103+
_ = QuickLookHelper.SwitchQuickLookAsync(path, sendFailToast).ConfigureAwait(false);
104+
}
105+
106+
public async Task OpenPreviewAsync(string path, bool sendFailToast = true)
107+
{
108+
bool success = await QuickLookHelper.OpenQuickLookAsync(path, sendFailToast).ConfigureAwait(false);
109+
}
110+
90111
public string GetTranslatedPluginTitle()
91112
{
92113
return Context.API.GetTranslation("plugin_explorer_plugin_name");
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Library</OutputType>
5+
<TargetFramework>net7.0-windows</TargetFramework>
6+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
7+
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
8+
<Nullable>warnings</Nullable>
9+
</PropertyGroup>
10+
11+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
12+
<!--<OutputPath>\Output\Debug\Plugins\Flow.Launcher.Plugin.QuickLook</OutputPath>-->
13+
<OutputPath>..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.QuickLook</OutputPath>
14+
</PropertyGroup>
15+
16+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
17+
<!--<OutputPath>\Output\Release\Plugins\Flow.Launcher.Plugin.QuickLook</OutputPath>-->
18+
<OutputPath>..\..\Output\Release\Plugins\Flow.Launcher.Plugin.QuickLook</OutputPath>
19+
</PropertyGroup>
20+
21+
<ItemGroup>
22+
<!--<PackageReference Include="Flow.Launcher.Plugin" Version="4.3.0" />-->
23+
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<None Include="plugin.json">
28+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
29+
</None>
30+
<Content Include="Images\*.png">
31+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
32+
</Content>
33+
</ItemGroup>
34+
35+
<ItemGroup>
36+
<None Remove="Languages\en.xaml" />
37+
</ItemGroup>
38+
39+
<ItemGroup>
40+
<Content Include="Languages\en.xaml">
41+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
42+
<SubType>Designer</SubType>
43+
<Generator>MSBuild:Compile</Generator>
44+
</Content>
45+
</ItemGroup>
46+
47+
<ItemGroup>
48+
<Folder Include="Images\" />
49+
</ItemGroup>
50+
51+
</Project>

0 commit comments

Comments
 (0)