mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into 250410-PluginBadge2
This commit is contained in:
commit
02b53732c2
22 changed files with 655 additions and 62 deletions
|
|
@ -37,7 +37,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
private static PluginsSettings Settings;
|
||||
private static List<PluginMetadata> _metadatas;
|
||||
private static List<string> _modifiedPlugins = new();
|
||||
private static readonly List<string> _modifiedPlugins = new();
|
||||
|
||||
/// <summary>
|
||||
/// Directories that will hold Flow Launcher plugin directory
|
||||
|
|
@ -61,10 +61,17 @@ namespace Flow.Launcher.Core.Plugin
|
|||
/// </summary>
|
||||
public static void Save()
|
||||
{
|
||||
foreach (var plugin in AllPlugins)
|
||||
foreach (var pluginPair in AllPlugins)
|
||||
{
|
||||
var savable = plugin.Plugin as ISavable;
|
||||
savable?.Save();
|
||||
var savable = pluginPair.Plugin as ISavable;
|
||||
try
|
||||
{
|
||||
savable?.Save();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to save plugin {pluginPair.Metadata.Name}", e);
|
||||
}
|
||||
}
|
||||
|
||||
API.SavePluginSettings();
|
||||
|
|
@ -81,14 +88,21 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
private static async Task DisposePluginAsync(PluginPair pluginPair)
|
||||
{
|
||||
switch (pluginPair.Plugin)
|
||||
try
|
||||
{
|
||||
case IDisposable disposable:
|
||||
disposable.Dispose();
|
||||
break;
|
||||
case IAsyncDisposable asyncDisposable:
|
||||
await asyncDisposable.DisposeAsync();
|
||||
break;
|
||||
switch (pluginPair.Plugin)
|
||||
{
|
||||
case IDisposable disposable:
|
||||
disposable.Dispose();
|
||||
break;
|
||||
case IAsyncDisposable asyncDisposable:
|
||||
await asyncDisposable.DisposeAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
API.LogException(ClassName, $"Failed to dispose plugin {pluginPair.Metadata.Name}", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -292,7 +306,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
Title = $"{metadata.Name}: Failed to respond!",
|
||||
SubTitle = "Select this result for more info",
|
||||
IcoPath = Flow.Launcher.Infrastructure.Constant.ErrorIcon,
|
||||
IcoPath = Constant.ErrorIcon,
|
||||
PluginDirectory = metadata.PluginDirectory,
|
||||
ActionKeywordAssigned = query.ActionKeyword,
|
||||
PluginID = metadata.ID,
|
||||
|
|
@ -369,8 +383,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
// this method is only checking for action keywords (defined as not '*') registration
|
||||
// hence the actionKeyword != Query.GlobalPluginWildcardSign logic
|
||||
return actionKeyword != Query.GlobalPluginWildcardSign
|
||||
&& NonGlobalPlugins.ContainsKey(actionKeyword);
|
||||
return actionKeyword != Query.GlobalPluginWildcardSign
|
||||
&& NonGlobalPlugins.ContainsKey(actionKeyword);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ namespace Flow.Launcher.Core.Resource
|
|||
private const string DefaultFile = "en.xaml";
|
||||
private const string Extension = ".xaml";
|
||||
private readonly Settings _settings;
|
||||
private readonly List<string> _languageDirectories = new List<string>();
|
||||
private readonly List<ResourceDictionary> _oldResources = new List<ResourceDictionary>();
|
||||
private readonly List<string> _languageDirectories = new();
|
||||
private readonly List<ResourceDictionary> _oldResources = new();
|
||||
private readonly string SystemLanguageCode;
|
||||
|
||||
public Internationalization(Settings settings)
|
||||
|
|
@ -144,7 +144,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
_settings.Language = isSystem ? Constant.SystemLanguageCode : language.LanguageCode;
|
||||
}
|
||||
|
||||
private Language GetLanguageByLanguageCode(string languageCode)
|
||||
private static Language GetLanguageByLanguageCode(string languageCode)
|
||||
{
|
||||
var lowercase = languageCode.ToLower();
|
||||
var language = AvailableLanguages.GetAvailableLanguages().FirstOrDefault(o => o.LanguageCode.ToLower() == lowercase);
|
||||
|
|
@ -239,7 +239,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
return list;
|
||||
}
|
||||
|
||||
public string GetTranslation(string key)
|
||||
public static string GetTranslation(string key)
|
||||
{
|
||||
var translation = Application.Current.TryFindResource(key);
|
||||
if (translation is string)
|
||||
|
|
@ -257,8 +257,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
{
|
||||
foreach (var p in PluginManager.GetPluginsForInterface<IPluginI18n>())
|
||||
{
|
||||
var pluginI18N = p.Plugin as IPluginI18n;
|
||||
if (pluginI18N == null) return;
|
||||
if (p.Plugin is not IPluginI18n pluginI18N) return;
|
||||
try
|
||||
{
|
||||
p.Metadata.Name = pluginI18N.GetTranslatedPluginTitle();
|
||||
|
|
@ -272,11 +271,11 @@ namespace Flow.Launcher.Core.Resource
|
|||
}
|
||||
}
|
||||
|
||||
public string LanguageFile(string folder, string language)
|
||||
private static string LanguageFile(string folder, string language)
|
||||
{
|
||||
if (Directory.Exists(folder))
|
||||
{
|
||||
string path = Path.Combine(folder, language);
|
||||
var path = Path.Combine(folder, language);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
|
|
@ -284,7 +283,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
else
|
||||
{
|
||||
Log.Error($"|Internationalization.LanguageFile|Language path can't be found <{path}>");
|
||||
string english = Path.Combine(folder, DefaultFile);
|
||||
var english = Path.Combine(folder, DefaultFile);
|
||||
if (File.Exists(english))
|
||||
{
|
||||
return english;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
|
|
@ -40,6 +41,16 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
FilePath = Path.Combine(DirectoryPath, $"{filename}{FileSuffix}");
|
||||
}
|
||||
|
||||
// Let the old Program plugin get this constructor
|
||||
[Obsolete("This constructor is obsolete. Use BinaryStorage(string filename) instead.")]
|
||||
public BinaryStorage(string filename, string directoryPath = null!)
|
||||
{
|
||||
DirectoryPath = directoryPath ?? DataLocation.CacheDirectory;
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
FilePath = Path.Combine(DirectoryPath, $"{filename}{FileSuffix}");
|
||||
}
|
||||
|
||||
public async ValueTask<T> TryLoadAsync(T defaultData)
|
||||
{
|
||||
if (Data != null) return Data;
|
||||
|
|
@ -82,8 +93,10 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
|
||||
public void Save()
|
||||
{
|
||||
var serialized = MemoryPackSerializer.Serialize(Data);
|
||||
// User may delete the directory, so we need to check it
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
var serialized = MemoryPackSerializer.Serialize(Data);
|
||||
File.WriteAllBytes(FilePath, serialized);
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +116,9 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
// so we need to pass it to SaveAsync
|
||||
public async ValueTask SaveAsync(T data)
|
||||
{
|
||||
// User may delete the directory, so we need to check it
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
await using var stream = new FileStream(FilePath, FileMode.Create);
|
||||
await MemoryPackSerializer.SerializeAsync(stream, data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
|
||||
public FlowLauncherJsonStorage()
|
||||
{
|
||||
var directoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName);
|
||||
FilesFolders.ValidateDirectory(directoryPath);
|
||||
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName);
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
var filename = typeof(T).Name;
|
||||
FilePath = Path.Combine(directoryPath, $"{filename}{FileSuffix}");
|
||||
FilePath = Path.Combine(DirectoryPath, $"{filename}{FileSuffix}");
|
||||
}
|
||||
|
||||
public new void Save()
|
||||
|
|
|
|||
|
|
@ -183,7 +183,10 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
|
||||
public void Save()
|
||||
{
|
||||
string serialized = JsonSerializer.Serialize(Data,
|
||||
// User may delete the directory, so we need to check it
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
var serialized = JsonSerializer.Serialize(Data,
|
||||
new JsonSerializerOptions { WriteIndented = true });
|
||||
|
||||
File.WriteAllText(TempFilePath, serialized);
|
||||
|
|
@ -193,6 +196,9 @@ namespace Flow.Launcher.Infrastructure.Storage
|
|||
|
||||
public async Task SaveAsync()
|
||||
{
|
||||
// User may delete the directory, so we need to check it
|
||||
FilesFolders.ValidateDirectory(DirectoryPath);
|
||||
|
||||
await using var tempOutput = File.OpenWrite(TempFilePath);
|
||||
await JsonSerializer.SerializeAsync(tempOutput, Data,
|
||||
new JsonSerializerOptions { WriteIndented = true });
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
|
@ -517,5 +518,92 @@ namespace Flow.Launcher.Infrastructure
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Korean IME
|
||||
|
||||
public static bool IsWindows11()
|
||||
{
|
||||
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
|
||||
Environment.OSVersion.Version.Build >= 22000;
|
||||
}
|
||||
|
||||
public static bool IsKoreanIMEExist()
|
||||
{
|
||||
return GetLegacyKoreanIMERegistryValue() != null;
|
||||
}
|
||||
|
||||
public static bool IsLegacyKoreanIMEEnabled()
|
||||
{
|
||||
object value = GetLegacyKoreanIMERegistryValue();
|
||||
|
||||
if (value is int intValue)
|
||||
{
|
||||
return intValue == 1;
|
||||
}
|
||||
else if (value != null && int.TryParse(value.ToString(), out int parsedValue))
|
||||
{
|
||||
return parsedValue == 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetLegacyKoreanIMEEnabled(bool enable)
|
||||
{
|
||||
const string subKeyPath = @"Software\Microsoft\input\tsf\tsf3override\{A028AE76-01B1-46C2-99C4-ACD9858AE02F}";
|
||||
const string valueName = "NoTsf3Override5";
|
||||
|
||||
try
|
||||
{
|
||||
using RegistryKey key = Registry.CurrentUser.CreateSubKey(subKeyPath);
|
||||
if (key != null)
|
||||
{
|
||||
int value = enable ? 1 : 0;
|
||||
key.SetValue(valueName, value, RegistryValueKind.DWord);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static object GetLegacyKoreanIMERegistryValue()
|
||||
{
|
||||
const string subKeyPath = @"Software\Microsoft\input\tsf\tsf3override\{A028AE76-01B1-46C2-99C4-ACD9858AE02F}";
|
||||
const string valueName = "NoTsf3Override5";
|
||||
|
||||
try
|
||||
{
|
||||
using RegistryKey key = Registry.CurrentUser.OpenSubKey(subKeyPath);
|
||||
if (key != null)
|
||||
{
|
||||
return key.GetValue(valueName);
|
||||
}
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void OpenImeSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo("ms-settings:regionlanguage") { UseShellExecute = true });
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,12 +264,12 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
var index = path.LastIndexOf('\\');
|
||||
if (index > 0 && index < (path.Length - 1))
|
||||
{
|
||||
string previousDirectoryPath = path.Substring(0, index + 1);
|
||||
return locationExists(previousDirectoryPath) ? previousDirectoryPath : "";
|
||||
string previousDirectoryPath = path[..(index + 1)];
|
||||
return locationExists(previousDirectoryPath) ? previousDirectoryPath : string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
// not full path, get previous level directory string
|
||||
var indexOfSeparator = path.LastIndexOf('\\');
|
||||
|
||||
return path.Substring(0, indexOfSeparator + 1);
|
||||
return path[..(indexOfSeparator + 1)];
|
||||
}
|
||||
|
||||
return path;
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ namespace Flow.Launcher
|
|||
|
||||
RegisterAppDomainExceptions();
|
||||
RegisterDispatcherUnhandledException();
|
||||
RegisterTaskSchedulerUnhandledException();
|
||||
|
||||
var imageLoadertask = ImageLoader.InitializeAsync();
|
||||
|
||||
|
|
@ -284,6 +285,15 @@ namespace Flow.Launcher
|
|||
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// let exception throw as normal is better for Debug
|
||||
/// </summary>
|
||||
[Conditional("RELEASE")]
|
||||
private static void RegisterTaskSchedulerUnhandledException()
|
||||
{
|
||||
TaskScheduler.UnobservedTaskException += ErrorReporting.TaskSchedulerUnobservedTaskException;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
|
@ -43,8 +44,16 @@ public class QuerySuggestionBoxConverter : IMultiValueConverter
|
|||
|
||||
// Check if Text will be larger than our QueryTextBox
|
||||
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
|
||||
// TODO: Obsolete warning?
|
||||
var ft = new FormattedText(queryTextBox.Text, CultureInfo.CurrentCulture, System.Windows.FlowDirection.LeftToRight, typeface, queryTextBox.FontSize, Brushes.Black);
|
||||
var dpi = VisualTreeHelper.GetDpi(queryTextBox);
|
||||
var ft = new FormattedText(
|
||||
queryTextBox.Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
typeface,
|
||||
queryTextBox.FontSize,
|
||||
Brushes.Black,
|
||||
dpi.PixelsPerDip
|
||||
);
|
||||
|
||||
var offset = queryTextBox.Padding.Right;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using NLog;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Exception;
|
||||
using NLog;
|
||||
|
||||
namespace Flow.Launcher.Helper;
|
||||
|
||||
|
|
@ -30,6 +32,13 @@ public static class ErrorReporting
|
|||
e.Handled = true;
|
||||
}
|
||||
|
||||
public static void TaskSchedulerUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
|
||||
{
|
||||
//handle unobserved task exceptions
|
||||
Application.Current.Dispatcher.Invoke(() => Report(e.Exception));
|
||||
//prevent application exit, so the user can copy the prompted error info
|
||||
}
|
||||
|
||||
public static string RuntimeInfo()
|
||||
{
|
||||
var info =
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<system:String x:Key="GameMode">Game Mode</system:String>
|
||||
<system:String x:Key="GameModeToolTip">Suspend the use of Hotkeys.</system:String>
|
||||
<system:String x:Key="PositionReset">Position Reset</system:String>
|
||||
<system:String x:Key="PositionResetToolTip">Reset search window position</system:String>
|
||||
<system:String x:Key="queryTextBoxPlaceholder">Type here to search</system:String>
|
||||
|
||||
<!-- Setting General -->
|
||||
|
|
@ -109,8 +110,22 @@
|
|||
<system:String x:Key="shadowEffectNotAllowed">Shadow effect is not allowed while current theme has blur effect enabled</system:String>
|
||||
<system:String x:Key="searchDelay">Search Delay</system:String>
|
||||
<system:String x:Key="searchDelayToolTip">Adds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average.</system:String>
|
||||
<system:String x:Key="searchDelayNumberBoxToolTip">Enter the wait time (in ms) until input is considered complete. This can only be edited if Search Delay is enabled.</system:String>
|
||||
<system:String x:Key="searchDelayTime">Default Search Delay Time</system:String>
|
||||
<system:String x:Key="searchDelayTimeToolTip">Wait time before showing results after typing stops. Higher values wait longer. (ms)</system:String>
|
||||
<system:String x:Key="KoreanImeTitle">Information for Korean IME user</system:String>
|
||||
<system:String x:Key="KoreanImeGuide">
|
||||
The Korean input method used in Windows 11 may cause some issues in Flow Launcher.

|
||||
If you experience any problems, you may need to enable "Use previous version of Korean IME".


|
||||
Open Setting in Windows 11 and go to:

|
||||
Time & Language > Language & Region > Korean > Language Options > Keyboard - Microsoft IME > Compatibility,

|
||||
and enable "Use previous version of Microsoft IME".


|
||||
</system:String>
|
||||
<system:String x:Key="KoreanImeOpenLink">Open Language and Region System Settings</system:String>
|
||||
<system:String x:Key="KoreanImeOpenLinkToolTip">Opens the Korean IME setting location. Go to Korean > Language Options > Keyboard - Microsoft IME > Compatibility</system:String>
|
||||
<system:String x:Key="KoreanImeOpenLinkButton">Open</system:String>
|
||||
<system:String x:Key="KoreanImeRegistry">Use Previous Korean IME</system:String>
|
||||
<system:String x:Key="KoreanImeRegistryTooltip">You can change the Previous Korean IME settings directly from here</system:String>
|
||||
|
||||
<!-- Setting Plugin -->
|
||||
<system:String x:Key="searchplugin">Search Plugin</system:String>
|
||||
|
|
|
|||
|
|
@ -291,15 +291,15 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (!CanClose)
|
||||
{
|
||||
CanClose = true;
|
||||
_notifyIcon.Visible = false;
|
||||
App.API.SaveAppAllSettings();
|
||||
e.Cancel = true;
|
||||
await ImageLoader.WaitSaveAsync();
|
||||
await PluginManager.DisposePluginsAsync();
|
||||
Notification.Uninstall();
|
||||
// After plugins are all disposed, we can close the main window
|
||||
CanClose = true;
|
||||
// Use this instead of Close() to avoid InvalidOperationException when calling Close() in OnClosing event
|
||||
// After plugins are all disposed, we shutdown application to close app
|
||||
// We use this instead of Close() to avoid InvalidOperationException when calling Close() in OnClosing event
|
||||
Application.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,20 +38,23 @@ namespace Flow.Launcher
|
|||
public class PublicAPIInstance : IPublicAPI, IRemovable
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private readonly Internationalization _translater;
|
||||
private readonly MainViewModel _mainVM;
|
||||
|
||||
// Must use getter to access Application.Current.Resources.MergedDictionaries so earlier
|
||||
private Theme _theme;
|
||||
private Theme Theme => _theme ??= Ioc.Default.GetRequiredService<Theme>();
|
||||
|
||||
// Must use getter to avoid circular dependency
|
||||
private Updater _updater;
|
||||
private Updater Updater => _updater ??= Ioc.Default.GetRequiredService<Updater>();
|
||||
|
||||
private readonly object _saveSettingsLock = new();
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PublicAPIInstance(Settings settings, Internationalization translater, MainViewModel mainVM)
|
||||
public PublicAPIInstance(Settings settings, MainViewModel mainVM)
|
||||
{
|
||||
_settings = settings;
|
||||
_translater = translater;
|
||||
_mainVM = mainVM;
|
||||
GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
|
||||
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
|
||||
|
|
@ -100,8 +103,7 @@ namespace Flow.Launcher
|
|||
remove => _mainVM.VisibilityChanged -= value;
|
||||
}
|
||||
|
||||
// Must use Ioc.Default.GetRequiredService<Updater>() to avoid circular dependency
|
||||
public void CheckForNewUpdate() => _ = Ioc.Default.GetRequiredService<Updater>().UpdateAppAsync(false);
|
||||
public void CheckForNewUpdate() => _ = Updater.UpdateAppAsync(false);
|
||||
|
||||
public void SaveAppAllSettings()
|
||||
{
|
||||
|
|
@ -178,7 +180,7 @@ namespace Flow.Launcher
|
|||
|
||||
public void StopLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Collapsed;
|
||||
|
||||
public string GetTranslation(string key) => _translater.GetTranslation(key);
|
||||
public string GetTranslation(string key) => Internationalization.GetTranslation(key);
|
||||
|
||||
public List<PluginPair> GetAllPlugins() => PluginManager.AllPlugins.ToList();
|
||||
|
||||
|
|
|
|||
81
Flow.Launcher/Resources/Controls/InfoBar.xaml
Normal file
81
Flow.Launcher/Resources/Controls/InfoBar.xaml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<UserControl
|
||||
x:Class="Flow.Launcher.Resources.Controls.InfoBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
d:DesignHeight="45"
|
||||
d:DesignWidth="400"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources />
|
||||
<Grid>
|
||||
<Border
|
||||
x:Name="PART_Border"
|
||||
MinHeight="48"
|
||||
Padding="18 18 18 18"
|
||||
Background="{DynamicResource InfoBarInfoBG}"
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" MinWidth="24" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||
<Border
|
||||
x:Name="PART_IconBorder"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0 0 12 0"
|
||||
VerticalAlignment="Top"
|
||||
CornerRadius="10">
|
||||
<ui:FontIcon
|
||||
x:Name="PART_Icon"
|
||||
Margin="1 0 0 1"
|
||||
VerticalAlignment="Center"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="13"
|
||||
Foreground="{DynamicResource Color01B}"
|
||||
Visibility="Visible" />
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
x:Name="PART_StackPanel"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
x:Name="PART_Title"
|
||||
Margin="0 0 12 0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding RelativeSource={RelativeSource AncestorType=cc:InfoBar}, Path=Title}" />
|
||||
<TextBlock
|
||||
x:Name="PART_Message"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding RelativeSource={RelativeSource AncestorType=cc:InfoBar}, Path=Message}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<Button
|
||||
x:Name="PART_CloseButton"
|
||||
Grid.Column="2"
|
||||
Width="32"
|
||||
Height="32"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="Close InfoBar"
|
||||
Click="PART_CloseButton_Click"
|
||||
Content=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
ToolTip="Close"
|
||||
Visibility="Visible" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
222
Flow.Launcher/Resources/Controls/InfoBar.xaml.cs
Normal file
222
Flow.Launcher/Resources/Controls/InfoBar.xaml.cs
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Flow.Launcher.Resources.Controls
|
||||
{
|
||||
public partial class InfoBar : UserControl
|
||||
{
|
||||
public InfoBar()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += InfoBar_Loaded;
|
||||
}
|
||||
|
||||
private void InfoBar_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateStyle();
|
||||
UpdateTitleVisibility();
|
||||
UpdateMessageVisibility();
|
||||
UpdateOrientation();
|
||||
UpdateIconAlignmentAndMargin();
|
||||
UpdateIconVisibility();
|
||||
UpdateCloseButtonVisibility();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TypeProperty =
|
||||
DependencyProperty.Register(nameof(Type), typeof(InfoBarType), typeof(InfoBar), new PropertyMetadata(InfoBarType.Info, OnTypeChanged));
|
||||
|
||||
public InfoBarType Type
|
||||
{
|
||||
get => (InfoBarType)GetValue(TypeProperty);
|
||||
set => SetValue(TypeProperty, value);
|
||||
}
|
||||
|
||||
private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is InfoBar infoBar)
|
||||
{
|
||||
infoBar.UpdateStyle();
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MessageProperty =
|
||||
DependencyProperty.Register(nameof(Message), typeof(string), typeof(InfoBar), new PropertyMetadata(string.Empty, OnMessageChanged));
|
||||
|
||||
public string Message
|
||||
{
|
||||
get => (string)GetValue(MessageProperty);
|
||||
set
|
||||
{
|
||||
SetValue(MessageProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is InfoBar infoBar)
|
||||
{
|
||||
infoBar.UpdateMessageVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMessageVisibility()
|
||||
{
|
||||
PART_Message.Visibility = string.IsNullOrEmpty(Message) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register(nameof(Title), typeof(string), typeof(InfoBar), new PropertyMetadata(string.Empty, OnTitleChanged));
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => (string)GetValue(TitleProperty);
|
||||
set
|
||||
{
|
||||
SetValue(TitleProperty, value);
|
||||
UpdateTitleVisibility(); // Visibility update when change Title
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is InfoBar infoBar)
|
||||
{
|
||||
infoBar.UpdateTitleVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTitleVisibility()
|
||||
{
|
||||
PART_Title.Visibility = string.IsNullOrEmpty(Title) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsIconVisibleProperty =
|
||||
DependencyProperty.Register(nameof(IsIconVisible), typeof(bool), typeof(InfoBar), new PropertyMetadata(true, OnIsIconVisibleChanged));
|
||||
|
||||
public bool IsIconVisible
|
||||
{
|
||||
get => (bool)GetValue(IsIconVisibleProperty);
|
||||
set => SetValue(IsIconVisibleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LengthProperty =
|
||||
DependencyProperty.Register(nameof(Length), typeof(InfoBarLength), typeof(InfoBar), new PropertyMetadata(InfoBarLength.Short, OnLengthChanged));
|
||||
|
||||
public InfoBarLength Length
|
||||
{
|
||||
get { return (InfoBarLength)GetValue(LengthProperty); }
|
||||
set { SetValue(LengthProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is InfoBar infoBar)
|
||||
{
|
||||
infoBar.UpdateOrientation();
|
||||
infoBar.UpdateIconAlignmentAndMargin();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOrientation()
|
||||
{
|
||||
PART_StackPanel.Orientation = Length == InfoBarLength.Long ? Orientation.Vertical : Orientation.Horizontal;
|
||||
}
|
||||
|
||||
private void UpdateIconAlignmentAndMargin()
|
||||
{
|
||||
if (Length == InfoBarLength.Short)
|
||||
{
|
||||
PART_IconBorder.VerticalAlignment = VerticalAlignment.Center;
|
||||
PART_IconBorder.Margin = new Thickness(0, 0, 12, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PART_IconBorder.VerticalAlignment = VerticalAlignment.Top;
|
||||
PART_IconBorder.Margin = new Thickness(0, 2, 12, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ClosableProperty =
|
||||
DependencyProperty.Register(nameof(Closable), typeof(bool), typeof(InfoBar), new PropertyMetadata(true, OnClosableChanged));
|
||||
|
||||
public bool Closable
|
||||
{
|
||||
get => (bool)GetValue(ClosableProperty);
|
||||
set => SetValue(ClosableProperty, value);
|
||||
}
|
||||
|
||||
private void PART_CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void UpdateStyle()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case InfoBarType.Info:
|
||||
PART_Border.Background = (Brush)FindResource("InfoBarInfoBG");
|
||||
PART_IconBorder.Background = (Brush)FindResource("InfoBarInfoIcon");
|
||||
PART_Icon.Glyph = "\xF13F";
|
||||
break;
|
||||
case InfoBarType.Success:
|
||||
PART_Border.Background = (Brush)FindResource("InfoBarSuccessBG");
|
||||
PART_IconBorder.Background = (Brush)FindResource("InfoBarSuccessIcon");
|
||||
PART_Icon.Glyph = "\xF13E";
|
||||
break;
|
||||
case InfoBarType.Warning:
|
||||
PART_Border.Background = (Brush)FindResource("InfoBarWarningBG");
|
||||
PART_IconBorder.Background = (Brush)FindResource("InfoBarWarningIcon");
|
||||
PART_Icon.Glyph = "\xF13C";
|
||||
break;
|
||||
case InfoBarType.Error:
|
||||
PART_Border.Background = (Brush)FindResource("InfoBarErrorBG");
|
||||
PART_IconBorder.Background = (Brush)FindResource("InfoBarErrorIcon");
|
||||
PART_Icon.Glyph = "\xF13D";
|
||||
break;
|
||||
default:
|
||||
PART_Border.Background = (Brush)FindResource("InfoBarInfoBG");
|
||||
PART_IconBorder.Background = (Brush)FindResource("InfoBarInfoIcon");
|
||||
PART_Icon.Glyph = "\xF13F";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnIsIconVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var infoBar = (InfoBar)d;
|
||||
infoBar.UpdateIconVisibility();
|
||||
}
|
||||
|
||||
private static void OnClosableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var infoBar = (InfoBar)d;
|
||||
infoBar.UpdateCloseButtonVisibility();
|
||||
}
|
||||
|
||||
private void UpdateIconVisibility()
|
||||
{
|
||||
PART_IconBorder.Visibility = IsIconVisible ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void UpdateCloseButtonVisibility()
|
||||
{
|
||||
PART_CloseButton.Visibility = Closable ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public enum InfoBarType
|
||||
{
|
||||
Info,
|
||||
Success,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
public enum InfoBarLength
|
||||
{
|
||||
Short,
|
||||
Long
|
||||
}
|
||||
}
|
||||
|
|
@ -96,8 +96,11 @@
|
|||
PlaceholderText="{Binding DefaultSearchDelay}"
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
ToolTip="{DynamicResource searchDelayToolTip}"
|
||||
ToolTip="{DynamicResource searchDelayNumberBoxToolTip}"
|
||||
ToolTipService.InitialShowDelay="0"
|
||||
ToolTipService.ShowOnDisabled="True"
|
||||
Value="{Binding PluginSearchDelayTime, Mode=TwoWay}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- Put OnOffControl after PriorityControl & SearchDelayControl so that it can display correctly -->
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,6 @@
|
|||
BasedOn="{StaticResource DefaultComboBoxStyle}"
|
||||
TargetType="ComboBox">
|
||||
<Setter Property="Padding" Value="12 0 0 0" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="ui:ControlHelper.CornerRadius" Value="0" />
|
||||
|
|
@ -2784,9 +2783,12 @@
|
|||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter TargetName="HeaderContentPresenter" Property="Foreground" Value="{DynamicResource TextControlHeaderForegroundDisabled}" />
|
||||
<Setter Property="Background" Value="{DynamicResource TextControlBackgroundDisabled}" />
|
||||
<Setter Property="Background" Value="{DynamicResource CustomNumberBoxBGDisabled}" />
|
||||
<Setter TargetName="BorderElementInline" Property="Background" Value="{DynamicResource TextControlBackgroundDisabled}" />
|
||||
<Setter TargetName="BorderElement" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushDisabled}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}" />
|
||||
<Setter TargetName="BorderElement" Property="BorderThickness" Value="0 0 0 0" />
|
||||
<Setter TargetName="BorderElementInline" Property="BorderThickness" Value="0 0 0 0" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlPlaceholderForegroundDisabled}" />
|
||||
<Setter TargetName="PlaceholderTextContentPresenter" Property="Foreground" Value="{DynamicResource TextControlPlaceholderForegroundDisabled}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
|
|
@ -2801,7 +2803,7 @@
|
|||
<Setter TargetName="BorderElementInline" Property="BorderBrush" Value="{DynamicResource TextControlBorderBrushFocused}" />
|
||||
<Setter TargetName="BorderElementInline" Property="BorderThickness" Value="0 0 0 2" />
|
||||
<Setter TargetName="BorderElement" Property="BorderBrush" Value="{DynamicResource CustomTextBoxOutline}" />
|
||||
<Setter TargetName="BorderElement" Property="BorderThickness" Value="{DynamicResource 2 2 2 0}" />
|
||||
<Setter TargetName="BorderElement" Property="BorderThickness" Value="2 2 2 0" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundFocused}" />
|
||||
</Trigger>
|
||||
<MultiTrigger>
|
||||
|
|
@ -2872,7 +2874,6 @@
|
|||
FontFamily="{TemplateBinding FontFamily}"
|
||||
FontSize="{TemplateBinding FontSize}"
|
||||
FontWeight="{TemplateBinding FontWeight}"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
InputScope="{TemplateBinding InputScope}"
|
||||
SelectionBrush="{TemplateBinding SelectionBrush}"
|
||||
TextAlignment="{TemplateBinding TextAlignment}" />
|
||||
|
|
|
|||
|
|
@ -106,7 +106,6 @@
|
|||
<Color x:Key="NumberBoxColor24">#f5f5f5</Color>
|
||||
<Color x:Key="NumberBoxColor25">#464646</Color>
|
||||
<Color x:Key="NumberBoxColor26">#ffffff</Color>
|
||||
<SolidColorBrush x:Key="NumberBoxPlaceHolder" Color="#565656" />
|
||||
<Color x:Key="HoverStoreGrid">#272727</Color>
|
||||
|
||||
<!-- Resources for HotkeyControl -->
|
||||
|
|
@ -115,10 +114,19 @@
|
|||
<SolidColorBrush x:Key="CustomExpanderHover" Color="#323232" />
|
||||
<!-- Resource for ContentDialog -->
|
||||
<SolidColorBrush x:Key="ContentDialogOverlayBG" Color="#58000000" />
|
||||
<!-- Infobar Warning -->
|
||||
<SolidColorBrush x:Key="InfoBarWarningIcon" Color="#FCE100" />
|
||||
<SolidColorBrush x:Key="InfoBarWarningBG" Color="#433519" />
|
||||
<!-- DIY Infobar -->
|
||||
<SolidColorBrush x:Key="InfoBarBD" Color="#19000000" />
|
||||
<SolidColorBrush
|
||||
x:Key="InfoBarInfoIcon"
|
||||
Opacity="0.9"
|
||||
Color="{m:DynamicColor SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="InfoBarInfoBG" Color="#272727" />
|
||||
<SolidColorBrush x:Key="InfoBarWarningIcon" Color="#fce100" />
|
||||
<SolidColorBrush x:Key="InfoBarWarningBG" Color="#433519" />
|
||||
<SolidColorBrush x:Key="InfoBarSuccessIcon" Color="#6ccb5f" />
|
||||
<SolidColorBrush x:Key="InfoBarSuccessBG" Color="#393d1b" />
|
||||
<SolidColorBrush x:Key="InfoBarErrorIcon" Color="#ff99a4" />
|
||||
<SolidColorBrush x:Key="InfoBarErrorBG" Color="#442726" />
|
||||
|
||||
<SolidColorBrush x:Key="MouseOverWindowCloseButtonForegroundBrush" Color="#ffffff" />
|
||||
|
||||
|
|
|
|||
|
|
@ -108,10 +108,20 @@
|
|||
<SolidColorBrush x:Key="CustomExpanderHover" Color="#f6f6f6" />
|
||||
<!-- Resource for ContentDialog -->
|
||||
<SolidColorBrush x:Key="ContentDialogOverlayBG" Color="#4D000000" />
|
||||
<!-- Infobar Warning -->
|
||||
|
||||
<!-- DIY Infobar -->
|
||||
<SolidColorBrush x:Key="InfoBarBD" Color="#0F000000" />
|
||||
<SolidColorBrush
|
||||
x:Key="InfoBarInfoIcon"
|
||||
Opacity="0.8"
|
||||
Color="{m:DynamicColor SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="InfoBarInfoBG" Color="{m:DynamicColor Color01}" />
|
||||
<SolidColorBrush x:Key="InfoBarWarningIcon" Color="#9D5D00" />
|
||||
<SolidColorBrush x:Key="InfoBarWarningBG" Color="#FFF4CE" />
|
||||
<SolidColorBrush x:Key="InfoBarBD" Color="#0F000000" />
|
||||
<SolidColorBrush x:Key="InfoBarSuccessIcon" Color="#3f973e" />
|
||||
<SolidColorBrush x:Key="InfoBarSuccessBG" Color="#dff6dd" />
|
||||
<SolidColorBrush x:Key="InfoBarErrorIcon" Color="#c42b1c" />
|
||||
<SolidColorBrush x:Key="InfoBarErrorBG" Color="#fde7e9" />
|
||||
|
||||
<SolidColorBrush x:Key="MouseOverWindowCloseButtonForegroundBrush" Color="#ffffff" />
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
|
|
@ -179,6 +181,70 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
|||
}
|
||||
}
|
||||
|
||||
#region Korean IME
|
||||
|
||||
// The new Korean IME used in Windows 11 has compatibility issues with WPF. This issue is difficult to resolve within
|
||||
// WPF itself, but it can be avoided by having the user switch to the legacy IME at the system level. Therefore,
|
||||
// we provide guidance and a direct button for users to make this change themselves. If the relevant registry key does
|
||||
// not exist (i.e., the Korean IME is not installed), this setting will not be shown at all.
|
||||
|
||||
public bool LegacyKoreanIMEEnabled
|
||||
{
|
||||
get => Win32Helper.IsLegacyKoreanIMEEnabled();
|
||||
set
|
||||
{
|
||||
if (Win32Helper.SetLegacyKoreanIMEEnabled(value))
|
||||
{
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(KoreanIMERegistryValueIsZero));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Since this is rarely seen text, language support is not provided.
|
||||
App.API.ShowMsg("Failed to change Korean IME setting", "Please check your system registry access or contact support.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool KoreanIMERegistryKeyExists
|
||||
{
|
||||
get
|
||||
{
|
||||
var registryKeyExists = Win32Helper.IsKoreanIMEExist();
|
||||
var koreanLanguageInstalled = InputLanguage.InstalledInputLanguages.Cast<InputLanguage>().Any(lang => lang.Culture.Name.StartsWith("ko"));
|
||||
var isWindows11 = Win32Helper.IsWindows11();
|
||||
|
||||
// Return true if Windows 11 with Korean IME installed, or if the registry key exists
|
||||
return (isWindows11 && koreanLanguageInstalled) || registryKeyExists;
|
||||
}
|
||||
}
|
||||
|
||||
public bool KoreanIMERegistryValueIsZero
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = Win32Helper.GetLegacyKoreanIMERegistryValue();
|
||||
if (value is int intValue)
|
||||
{
|
||||
return intValue == 0;
|
||||
}
|
||||
else if (value != null && int.TryParse(value.ToString(), out var parsedValue))
|
||||
{
|
||||
return parsedValue == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenImeSettings()
|
||||
{
|
||||
Win32Helper.OpenImeSettings();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool ShouldUsePinyin
|
||||
{
|
||||
get => Settings.ShouldUsePinyin;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ext="clr-namespace:Flow.Launcher.Resources.MarkupExtensions"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
|
@ -14,6 +15,9 @@
|
|||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ui:Page.Resources>
|
||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
</ui:Page.Resources>
|
||||
<ScrollViewer
|
||||
Margin="0"
|
||||
CanContentScroll="False"
|
||||
|
|
@ -28,6 +32,7 @@
|
|||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource general}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource startFlowLauncherOnSystemStartup}"
|
||||
Margin="0 8 0 0"
|
||||
|
|
@ -215,12 +220,12 @@
|
|||
<ui:NumberBox
|
||||
Width="120"
|
||||
Margin="0 0 0 0"
|
||||
Minimum="0"
|
||||
Maximum="1000"
|
||||
Minimum="0"
|
||||
SmallChange="10"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
Value="{Binding SearchDelayTimeValue}"
|
||||
ValidationMode="InvalidInputOverwritten" />
|
||||
ValidationMode="InvalidInputOverwritten"
|
||||
Value="{Binding SearchDelayTimeValue}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:ExCard>
|
||||
|
|
@ -312,6 +317,35 @@
|
|||
SelectedValue="{Binding Language}"
|
||||
SelectedValuePath="LanguageCode" />
|
||||
</cc:Card>
|
||||
<Border Visibility="{Binding KoreanIMERegistryKeyExists, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<cc:InfoBar
|
||||
Title="{DynamicResource KoreanImeTitle}"
|
||||
Margin="0 14 0 0"
|
||||
Closable="False"
|
||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType=Border}, Path=DataContext}"
|
||||
IsIconVisible="True"
|
||||
Length="Long"
|
||||
Message="{DynamicResource KoreanImeGuide}"
|
||||
Type="Warning"
|
||||
Visibility="{Binding LegacyKoreanIMEEnabled, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Inverted, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Border>
|
||||
<cc:CardGroup Margin="0 14 0 0" Visibility="{Binding KoreanIMERegistryKeyExists, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<cc:Card
|
||||
Title="{DynamicResource KoreanImeRegistry}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource KoreanImeRegistryTooltip}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding LegacyKoreanIMEEnabled}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource KoreanImeOpenLink}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource KoreanImeOpenLinkToolTip}">
|
||||
<Button Command="{Binding OpenImeSettingsCommand}" Content="{DynamicResource KoreanImeOpenLinkButton}" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
</VirtualizingStackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
|
|
|
|||
|
|
@ -598,7 +598,7 @@
|
|||
<ComboBox
|
||||
Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding Settings.SortOptions, Mode=OneWay}"
|
||||
SelectedItem="{Binding Settings.SortOption}"
|
||||
|
|
@ -623,7 +623,7 @@
|
|||
Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Width="{StaticResource SettingPanelPathTextBoxWidth}"
|
||||
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding EverythingInstalledPath}" />
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue