Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 12 additions & 17 deletions Flow.Launcher.Core/Configuration/Portable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
using System.Linq;
using System.Reflection;
using System.Windows;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Microsoft.Win32;
using Squirrel;
Expand All @@ -17,8 +15,6 @@
{
private static readonly string ClassName = nameof(Portable);

private readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();

/// <summary>
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
/// </summary>
Expand All @@ -45,13 +41,13 @@
#endif
IndicateDeletion(DataLocation.PortableDataPath);

API.ShowMsgBox(API.GetTranslation("restartToDisablePortableMode"));
PublicApi.Instance.ShowMsgBox(Localize.restartToDisablePortableMode());

UpdateManager.RestartApp(Constant.ApplicationFileName);
}
catch (Exception e)
{
API.LogException(ClassName, "Error occurred while disabling portable mode", e);
PublicApi.Instance.LogException(ClassName, "Error occurred while disabling portable mode", e);
}
}

Expand All @@ -61,20 +57,20 @@
{
MoveUserDataFolder(DataLocation.RoamingDataPath, DataLocation.PortableDataPath);
#if !DEBUG
// Remove shortcuts and uninstaller are not required in debug mode,

Check warning on line 60 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`uninstaller` is not a recognized word. (unrecognized-spelling)
// otherwise will delete the actual installed production version
RemoveShortcuts();
RemoveUninstallerEntry();

Check warning on line 63 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Uninstaller` is not a recognized word. (unrecognized-spelling)
#endif
IndicateDeletion(DataLocation.RoamingDataPath);

API.ShowMsgBox(API.GetTranslation("restartToEnablePortableMode"));
PublicApi.Instance.ShowMsgBox(Localize.restartToEnablePortableMode());

UpdateManager.RestartApp(Constant.ApplicationFileName);
}
catch (Exception e)
{
API.LogException(ClassName, "Error occurred while enabling portable mode", e);
PublicApi.Instance.LogException(ClassName, "Error occurred while enabling portable mode", e);
}
}

Expand All @@ -86,21 +82,21 @@
portabilityUpdater.RemoveShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup);
}

public void RemoveUninstallerEntry()

Check warning on line 85 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Uninstaller` is not a recognized word. (unrecognized-spelling)
{
using var portabilityUpdater = NewUpdateManager();
portabilityUpdater.RemoveUninstallerRegistryEntry();

Check warning on line 88 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Uninstaller` is not a recognized word. (unrecognized-spelling)
}

public void MoveUserDataFolder(string fromLocation, string toLocation)
{
FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
FilesFolders.CopyAll(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
VerifyUserDataAfterMove(fromLocation, toLocation);
}

public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
{
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
}

public void CreateShortcuts()
Expand All @@ -111,7 +107,7 @@
portabilityUpdater.CreateShortcutsForExecutable(Constant.ApplicationFileName, ShortcutLocation.Startup, false);
}

public void CreateUninstallerEntry()

Check warning on line 110 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Uninstaller` is not a recognized word. (unrecognized-spelling)
{
var uninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";

Expand All @@ -128,7 +124,7 @@

private static void IndicateDeletion(string filePathTodelete)
{
var deleteFilePath = Path.Combine(filePathTodelete, DataLocation.DeletionIndicatorFile);

Check warning on line 127 in Flow.Launcher.Core/Configuration/Portable.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`Todelete` is not a recognized word. (unrecognized-spelling)
using var _ = File.CreateText(deleteFilePath);
}

Expand All @@ -150,12 +146,12 @@
// delete it and prompt the user to pick the portable data location
if (File.Exists(roamingDataDeleteFilePath))
{
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s));
FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));

if (API.ShowMsgBox(API.GetTranslation("moveToDifferentLocation"),
if (PublicApi.Instance.ShowMsgBox(Localize.moveToDifferentLocation(),
string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s));
FilesFolders.OpenPath(Constant.RootDirectory, (s) => PublicApi.Instance.ShowMsgBox(s));

Environment.Exit(0);
}
Expand All @@ -164,9 +160,9 @@
// delete it and notify the user about it.
else if (File.Exists(portableDataDeleteFilePath))
{
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s));
FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));

API.ShowMsgBox(API.GetTranslation("shortcutsUninstallerCreated"));
PublicApi.Instance.ShowMsgBox(Localize.shortcutsUninstallerCreated());
}
}

Expand All @@ -177,8 +173,7 @@

if (roamingLocationExists && portableLocationExists)
{
API.ShowMsgBox(string.Format(API.GetTranslation("userDataDuplicated"),
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
PublicApi.Instance.ShowMsgBox(Localize.userDataDuplicated(DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));

return false;
}
Expand Down
23 changes: 9 additions & 14 deletions Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Plugin;

Expand All @@ -18,13 +17,9 @@ public record CommunityPluginSource(string ManifestFileUrl)
{
private static readonly string ClassName = nameof(CommunityPluginSource);

// We should not initialize API in static constructor because it will create another API instance
private static IPublicAPI api = null;
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();

private string latestEtag = "";

private List<UserPlugin> plugins = new();
private List<UserPlugin> plugins = [];

private static readonly JsonSerializerOptions PluginStoreItemSerializationOption = new()
{
Expand All @@ -41,7 +36,7 @@ public record CommunityPluginSource(string ManifestFileUrl)
/// </remarks>
public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
{
API.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
PublicApi.Instance.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");

var request = new HttpRequestMessage(HttpMethod.Get, ManifestFileUrl);

Expand All @@ -59,40 +54,40 @@ public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
.ConfigureAwait(false);
latestEtag = response.Headers.ETag?.Tag;

API.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
PublicApi.Instance.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
return plugins;
}
else if (response.StatusCode == HttpStatusCode.NotModified)
{
API.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
PublicApi.Instance.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
return plugins;
}
else
{
API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
PublicApi.Instance.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
return null;
}
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
API.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
PublicApi.Instance.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
return null;
}
catch (TaskCanceledException)
{
// Likely an HttpClient timeout or external cancellation not requested by our token
API.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
PublicApi.Instance.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
return null;
}
catch (Exception e)
{
if (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
{
API.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
PublicApi.Instance.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
}
else
{
API.LogException(ClassName, "Error Occurred", e);
PublicApi.Instance.LogException(ClassName, "Error Occurred", e);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
Expand All @@ -15,7 +14,7 @@ public abstract class AbstractPluginEnvironment
{
private static readonly string ClassName = nameof(AbstractPluginEnvironment);

protected readonly IPublicAPI API = Ioc.Default.GetRequiredService<IPublicAPI>();
protected readonly IPublicAPI API = PublicApi.Instance;

internal abstract string Language { get; }

Expand Down Expand Up @@ -58,15 +57,10 @@ internal IEnumerable<PluginPair> Setup()
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
}

var noRuntimeMessage = string.Format(
API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
Language,
EnvName,
Environment.NewLine
);
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
{
var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
var msg = Localize.runtimePluginChooseRuntimeExecutable(EnvName);

var selectedFile = GetFileFromDialog(msg, FileDialogFilter);

Expand All @@ -77,12 +71,7 @@ internal IEnumerable<PluginPair> Setup()
// Nothing selected because user pressed cancel from the file dialog window
else
{
var forceDownloadMessage = string.Format(
API.GetTranslation("runtimeExecutableInvalidChooseDownload"),
Language,
EnvName,
Environment.NewLine
);
var forceDownloadMessage = Localize.runtimeExecutableInvalidChooseDownload(Language, EnvName, Environment.NewLine);

// Let users select valid path or choose to download
while (string.IsNullOrEmpty(selectedFile))
Expand Down Expand Up @@ -120,7 +109,7 @@ internal IEnumerable<PluginPair> Setup()
}
else
{
API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
API.ShowMsgBox(Localize.runtimePluginUnableToSetExecutablePath(Language));
API.LogError(ClassName,
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
$"{Language}Environment");
Expand Down Expand Up @@ -248,7 +237,7 @@ private static bool IsUsingRoamingPath(string filePath)
private static string GetUpdatedEnvironmentPath(string filePath)
{
var index = filePath.IndexOf(DataLocation.PluginEnvironments);

// get the substring after "Environments" because we can not determine it dynamically
var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..];
return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

// Python 3.11.4 is no longer Windows 7 compatible. If user is on Win 7 and
// uses Python plugin they need to custom install and use v3.8.9
JTF.Run(async () =>

Check warning on line 44 in Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`JTF` is not a recognized word. (unrecognized-spelling)
{
try
{
Expand All @@ -51,7 +51,7 @@
}
catch (System.Exception e)
{
API.ShowMsgError(API.GetTranslation("failToInstallPythonEnv"));
API.ShowMsgError(Localize.failToInstallPythonEnv());
API.LogException(ClassName, "Failed to install Python environment", e);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@

internal TypeScriptEnvironment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }

private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());

Check warning on line 33 in Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`JTF` is not a recognized word. (unrecognized-spelling)

internal override void InstallEnvironment()
{
FilesFolders.RemoveFolderIfExists(InstallPath, (s) => API.ShowMsgBox(s));

JTF.Run(async () =>

Check warning on line 39 in Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`JTF` is not a recognized word. (unrecognized-spelling)
{
try
{
Expand All @@ -46,7 +46,7 @@
}
catch (System.Exception e)
{
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
API.LogException(ClassName, "Failed to install TypeScript environment", e);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

internal TypeScriptV2Environment(List<PluginMetadata> pluginMetadataList, PluginsSettings pluginSettings) : base(pluginMetadataList, pluginSettings) { }

private JoinableTaskFactory JTF { get; } = new JoinableTaskFactory(new JoinableTaskContext());

Check warning on line 33 in Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs

View workflow job for this annotation

GitHub Actions / Check Spelling

`JTF` is not a recognized word. (unrecognized-spelling)

internal override void InstallEnvironment()
{
Expand All @@ -46,7 +46,7 @@
}
catch (System.Exception e)
{
API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
API.LogException(ClassName, "Failed to install TypeScript environment", e);
}
});
Expand Down
11 changes: 3 additions & 8 deletions Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Plugin;
using Flow.Launcher.Infrastructure;

Expand All @@ -23,10 +22,6 @@ public static class PluginsManifest
private static DateTime lastFetchedAt = DateTime.MinValue;
private static readonly TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);

// We should not initialize API in static constructor because it will create another API instance
private static IPublicAPI api = null;
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();

public static List<UserPlugin> UserPlugins { get; private set; }

public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
Expand Down Expand Up @@ -61,7 +56,7 @@ public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = fals
}
catch (Exception e)
{
API.LogException(ClassName, "Http request failed", e);
PublicApi.Instance.LogException(ClassName, "Http request failed", e);
}
finally
{
Expand All @@ -83,12 +78,12 @@ private static bool IsMinimumAppVersionSatisfied(UserPlugin plugin, SemanticVers
}
catch (Exception e)
{
API.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
+ "Plugin excluded from manifest", e);
return false;
}

API.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
+ $"but current version is {Constant.Version}. Plugin excluded from manifest.");

return false;
Expand Down
15 changes: 14 additions & 1 deletion Flow.Launcher.Core/Flow.Launcher.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0-windows</TargetFramework>
Expand Down Expand Up @@ -34,6 +34,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<NoWarn>$(NoWarn);FLSG0007</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand All @@ -55,13 +56,25 @@

<ItemGroup>
<PackageReference Include="Droplex" Version="1.7.0" />
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
<PackageReference Include="FSharp.Core" Version="9.0.303" />
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.4.4" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
<PackageReference Include="StreamJsonRpc" Version="2.22.11" />
</ItemGroup>

<PropertyGroup>
<FLLUseDependencyInjection>true</FLLUseDependencyInjection>
</PropertyGroup>

<ItemGroup>
<AdditionalFiles Remove="Languages\en.xaml" />
<AdditionalFiles Include="..\Flow.Launcher\Languages\en.xaml">
<Link>Languages\en.xaml</Link>
</AdditionalFiles>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ public Control CreateSettingPanel()
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center,
Margin = SettingPanelItemLeftMargin,
Content = API.GetTranslation("select")
Content = Localize.select()
};

Btn.Click += (_, _) =>
Expand Down
Loading
Loading