Skip to content

Commit 6859232

Browse files
authored
Merge branch 'dev' into delete_clipboard_jsonrpc
2 parents adde491 + d30fdbb commit 6859232

File tree

27 files changed

+455
-162
lines changed

27 files changed

+455
-162
lines changed

Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ namespace Flow.Launcher.Core.ExternalPlugins
1616
{
1717
public record CommunityPluginSource(string ManifestFileUrl)
1818
{
19+
private static readonly string ClassName = nameof(CommunityPluginSource);
20+
1921
// We should not initialize API in static constructor because it will create another API instance
2022
private static IPublicAPI api = null;
2123
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
2224

23-
private static readonly string ClassName = nameof(CommunityPluginSource);
24-
2525
private string latestEtag = "";
2626

2727
private List<UserPlugin> plugins = new();
@@ -70,7 +70,7 @@ public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
7070
else
7171
{
7272
API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
73-
return plugins;
73+
return null;
7474
}
7575
}
7676
catch (Exception e)
@@ -83,7 +83,7 @@ public async Task<List<UserPlugin>> FetchAsync(CancellationToken token)
8383
{
8484
API.LogException(ClassName, "Error Occurred", e);
8585
}
86-
return plugins;
86+
return null;
8787
}
8888
}
8989
}

Flow.Launcher.Core/ExternalPlugins/CommunityPluginStore.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ public async Task<List<UserPlugin>> FetchAsync(CancellationToken token, bool onl
4040
var completedTask = await Task.WhenAny(tasks);
4141
if (completedTask.IsCompletedSuccessfully)
4242
{
43-
// one of the requests completed successfully; keep its results
44-
// and cancel the remaining http requests.
45-
pluginResults = await completedTask;
46-
cts.Cancel();
43+
var result = await completedTask;
44+
if (result != null)
45+
{
46+
// one of the requests completed successfully; keep its results
47+
// and cancel the remaining http requests.
48+
pluginResults = result;
49+
cts.Cancel();
50+
}
4751
}
4852
tasks.Remove(completedTask);
4953
}

Flow.Launcher.Core/Resource/Theme.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ private ResourceDictionary GetResourceDictionary(string theme)
325325
return dict;
326326
}
327327

328-
private ResourceDictionary GetCurrentResourceDictionary()
328+
public ResourceDictionary GetCurrentResourceDictionary()
329329
{
330330
return GetResourceDictionary(_settings.Theme);
331331
}
@@ -772,22 +772,18 @@ private void ApplyPreviewBackground(Color? bgColor = null)
772772
{
773773
if (bgColor == null) return;
774774

775-
// Copy the existing WindowBorderStyle
775+
// Create a new Style for the preview
776776
var previewStyle = new Style(typeof(Border));
777-
if (Application.Current.Resources.Contains("WindowBorderStyle"))
777+
778+
// Get the original WindowBorderStyle
779+
if (Application.Current.Resources.Contains("WindowBorderStyle") &&
780+
Application.Current.Resources["WindowBorderStyle"] is Style originalStyle)
778781
{
779-
if (Application.Current.Resources["WindowBorderStyle"] is Style originalStyle)
780-
{
781-
foreach (var setter in originalStyle.Setters.OfType<Setter>())
782-
{
783-
previewStyle.Setters.Add(new Setter(setter.Property, setter.Value));
784-
}
785-
}
782+
// Copy the original style, including the base style if it exists
783+
CopyStyle(originalStyle, previewStyle);
786784
}
787785

788786
// Apply background color (remove transparency in color)
789-
// WPF does not allow the use of an acrylic brush within the window's internal area,
790-
// so transparency effects are not applied to the preview.
791787
Color backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B);
792788
previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(backgroundColor)));
793789

@@ -798,9 +794,26 @@ private void ApplyPreviewBackground(Color? bgColor = null)
798794
previewStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5)));
799795
previewStyle.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(1)));
800796
}
797+
798+
// Set the new style to the resource
801799
Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle;
802800
}
803801

802+
private void CopyStyle(Style originalStyle, Style targetStyle)
803+
{
804+
// If the style is based on another style, copy the base style first
805+
if (originalStyle.BasedOn != null)
806+
{
807+
CopyStyle(originalStyle.BasedOn, targetStyle);
808+
}
809+
810+
// Copy the setters from the original style
811+
foreach (var setter in originalStyle.Setters.OfType<Setter>())
812+
{
813+
targetStyle.Setters.Add(new Setter(setter.Property, setter.Value));
814+
}
815+
}
816+
804817
private void ColorizeWindow(string theme, BackdropTypes backdropType)
805818
{
806819
var dict = GetThemeResourceDictionary(theme);

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
3-
using System.Drawing;
43
using System.Text.Json.Serialization;
54
using System.Windows;
65
using CommunityToolkit.Mvvm.DependencyInjection;
@@ -32,8 +31,7 @@ public void Save()
3231
{
3332
_storage.Save();
3433
}
35-
36-
private string language = Constant.SystemLanguageCode;
34+
3735
private string _theme = Constant.DefaultTheme;
3836
public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}";
3937
public string OpenResultModifiers { get; set; } = KeyConstant.Alt;
@@ -54,12 +52,13 @@ public void Save()
5452
public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up";
5553
public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down";
5654

55+
private string _language = Constant.SystemLanguageCode;
5756
public string Language
5857
{
59-
get => language;
58+
get => _language;
6059
set
6160
{
62-
language = value;
61+
_language = value;
6362
OnPropertyChanged();
6463
}
6564
}
@@ -82,18 +81,18 @@ public string Theme
8281
/* Appearance Settings. It should be separated from the setting later.*/
8382
public double WindowHeightSize { get; set; } = 42;
8483
public double ItemHeightSize { get; set; } = 58;
85-
public double QueryBoxFontSize { get; set; } = 20;
84+
public double QueryBoxFontSize { get; set; } = 16;
8685
public double ResultItemFontSize { get; set; } = 16;
8786
public double ResultSubItemFontSize { get; set; } = 13;
88-
public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name;
87+
public string QueryBoxFont { get; set; } = Win32Helper.GetSystemDefaultFont();
8988
public string QueryBoxFontStyle { get; set; }
9089
public string QueryBoxFontWeight { get; set; }
9190
public string QueryBoxFontStretch { get; set; }
92-
public string ResultFont { get; set; } = FontFamily.GenericSansSerif.Name;
91+
public string ResultFont { get; set; } = Win32Helper.GetSystemDefaultFont();
9392
public string ResultFontStyle { get; set; }
9493
public string ResultFontWeight { get; set; }
9594
public string ResultFontStretch { get; set; }
96-
public string ResultSubFont { get; set; } = FontFamily.GenericSansSerif.Name;
95+
public string ResultSubFont { get; set; } = Win32Helper.GetSystemDefaultFont();
9796
public string ResultSubFontStyle { get; set; }
9897
public string ResultSubFontWeight { get; set; }
9998
public string ResultSubFontStretch { get; set; }
@@ -116,7 +115,7 @@ public string Theme
116115
public double? SettingWindowLeft { get; set; } = null;
117116
public WindowState SettingWindowState { get; set; } = WindowState.Normal;
118117

119-
bool _showPlaceholder { get; set; } = false;
118+
private bool _showPlaceholder { get; set; } = true;
120119
public bool ShowPlaceholder
121120
{
122121
get => _showPlaceholder;
@@ -129,7 +128,7 @@ public bool ShowPlaceholder
129128
}
130129
}
131130
}
132-
string _placeholderText { get; set; } = string.Empty;
131+
private string _placeholderText { get; set; } = string.Empty;
133132
public string PlaceholderText
134133
{
135134
get => _placeholderText;
@@ -142,7 +141,6 @@ public string PlaceholderText
142141
}
143142
}
144143
}
145-
146144
public int CustomExplorerIndex { get; set; } = 0;
147145

148146
[JsonIgnore]
@@ -309,7 +307,7 @@ public bool KeepMaxResults
309307
public bool StartFlowLauncherOnSystemStartup { get; set; } = false;
310308
public bool UseLogonTaskForStartup { get; set; } = false;
311309
public bool HideOnStartup { get; set; } = true;
312-
bool _hideNotifyIcon { get; set; }
310+
private bool _hideNotifyIcon;
313311
public bool HideNotifyIcon
314312
{
315313
get => _hideNotifyIcon;

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel;
34
using System.Diagnostics;
45
using System.Globalization;
6+
using System.Linq;
57
using System.Runtime.InteropServices;
68
using System.Threading;
79
using System.Threading.Tasks;
810
using System.Windows;
911
using System.Windows.Interop;
12+
using System.Windows.Markup;
1013
using System.Windows.Media;
1114
using Flow.Launcher.Infrastructure.UserSettings;
1215
using Microsoft.Win32;
@@ -16,6 +19,7 @@
1619
using Windows.Win32.UI.Input.KeyboardAndMouse;
1720
using Windows.Win32.UI.WindowsAndMessaging;
1821
using Point = System.Windows.Point;
22+
using SystemFonts = System.Windows.SystemFonts;
1923

2024
namespace Flow.Launcher.Infrastructure
2125
{
@@ -669,5 +673,73 @@ public static void OpenImeSettings()
669673
}
670674

671675
#endregion
676+
677+
#region System Font
678+
679+
private static readonly Dictionary<string, string> _languageToNotoSans = new()
680+
{
681+
{ "ko", "Noto Sans KR" },
682+
{ "ja", "Noto Sans JP" },
683+
{ "zh-CN", "Noto Sans SC" },
684+
{ "zh-SG", "Noto Sans SC" },
685+
{ "zh-Hans", "Noto Sans SC" },
686+
{ "zh-TW", "Noto Sans TC" },
687+
{ "zh-HK", "Noto Sans TC" },
688+
{ "zh-MO", "Noto Sans TC" },
689+
{ "zh-Hant", "Noto Sans TC" },
690+
{ "th", "Noto Sans Thai" },
691+
{ "ar", "Noto Sans Arabic" },
692+
{ "he", "Noto Sans Hebrew" },
693+
{ "hi", "Noto Sans Devanagari" },
694+
{ "bn", "Noto Sans Bengali" },
695+
{ "ta", "Noto Sans Tamil" },
696+
{ "el", "Noto Sans Greek" },
697+
{ "ru", "Noto Sans" },
698+
{ "en", "Noto Sans" },
699+
{ "fr", "Noto Sans" },
700+
{ "de", "Noto Sans" },
701+
{ "es", "Noto Sans" },
702+
{ "pt", "Noto Sans" }
703+
};
704+
705+
public static string GetSystemDefaultFont()
706+
{
707+
try
708+
{
709+
var culture = CultureInfo.CurrentCulture;
710+
var language = culture.Name; // e.g., "zh-TW"
711+
var langPrefix = language.Split('-')[0]; // e.g., "zh"
712+
713+
// First, try to find by full name, and if not found, fallback to prefix
714+
if (TryGetNotoFont(language, out var notoFont) || TryGetNotoFont(langPrefix, out notoFont))
715+
{
716+
// If the font is installed, return it
717+
if (Fonts.SystemFontFamilies.Any(f => f.Source.Equals(notoFont)))
718+
{
719+
return notoFont;
720+
}
721+
}
722+
723+
// If Noto font is not found, fallback to the system default font
724+
var font = SystemFonts.MessageFontFamily;
725+
if (font.FamilyNames.TryGetValue(XmlLanguage.GetLanguage("en-US"), out var englishName))
726+
{
727+
return englishName;
728+
}
729+
730+
return font.Source ?? "Segoe UI";
731+
}
732+
catch
733+
{
734+
return "Segoe UI";
735+
}
736+
}
737+
738+
private static bool TryGetNotoFont(string langKey, out string notoFont)
739+
{
740+
return _languageToNotoSans.TryGetValue(langKey, out notoFont);
741+
}
742+
743+
#endregion
672744
}
673745
}

Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,15 @@ public interface IPublicAPI
223223
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
224224

225225
/// <summary>
226-
/// Add ActionKeyword and update action keyword metadata for specific plugin
226+
/// Add ActionKeyword and update action keyword metadata for specific plugin.
227227
/// Before adding, please check if action keyword is already assigned by <see cref="ActionKeywordAssigned"/>
228228
/// </summary>
229229
/// <param name="pluginId">ID for plugin that needs to add action keyword</param>
230230
/// <param name="newActionKeyword">The actionkeyword that is supposed to be added</param>
231+
/// <remarks>
232+
/// If new action keyword contains any whitespace, FL will still add it but it will not work for users.
233+
/// So plugin should check the whitespace before calling this function.
234+
/// </remarks>
231235
void AddActionKeyword(string pluginId, string newActionKeyword);
232236

233237
/// <summary>
@@ -280,9 +284,10 @@ public interface IPublicAPI
280284
T LoadSettingJsonStorage<T>() where T : new();
281285

282286
/// <summary>
283-
/// Save JsonStorage for current plugin's setting. This is the method used to save settings to json in Flow.Launcher
287+
/// Save JsonStorage for current plugin's setting. This is the method used to save settings to json in Flow.
284288
/// This method will save the original instance loaded with LoadJsonStorage.
285-
/// This API call is for manually Save. Flow will automatically save all setting type that has called LoadSettingJsonStorage or SaveSettingJsonStorage previously.
289+
/// This API call is for manually Save.
290+
/// Flow will automatically save all setting type that has called <see cref="LoadSettingJsonStorage"/> or <see cref="SaveSettingJsonStorage"/> previously.
286291
/// </summary>
287292
/// <typeparam name="T">Type for Serialization</typeparam>
288293
/// <returns></returns>
@@ -424,9 +429,10 @@ public interface IPublicAPI
424429
Task<T> LoadCacheBinaryStorageAsync<T>(string cacheName, string cacheDirectory, T defaultData) where T : new();
425430

426431
/// <summary>
427-
/// Save BinaryStorage for current plugin's cache. This is the method used to save cache to binary in Flow.Launcher
432+
/// Save BinaryStorage for current plugin's cache. This is the method used to save cache to binary in Flow.
428433
/// This method will save the original instance loaded with LoadCacheBinaryStorageAsync.
429-
/// This API call is for manually Save. Flow will automatically save all cache type that has called LoadCacheBinaryStorageAsync or SaveCacheBinaryStorageAsync previously.
434+
/// This API call is for manually Save.
435+
/// Flow will automatically save all cache type that has called <see cref="LoadCacheBinaryStorageAsync"/> or <see cref="SaveCacheBinaryStorageAsync"/> previously.
430436
/// </summary>
431437
/// <typeparam name="T">Type for Serialization</typeparam>
432438
/// <param name="cacheName">Cache file name</param>

Flow.Launcher/App.xaml.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,18 +202,11 @@ private void AutoStartup()
202202
{
203203
// we try to enable auto-startup on first launch, or reenable if it was removed
204204
// but the user still has the setting set
205-
if (_settings.StartFlowLauncherOnSystemStartup && !Helper.AutoStartup.IsEnabled)
205+
if (_settings.StartFlowLauncherOnSystemStartup)
206206
{
207207
try
208208
{
209-
if (_settings.UseLogonTaskForStartup)
210-
{
211-
Helper.AutoStartup.EnableViaLogonTask();
212-
}
213-
else
214-
{
215-
Helper.AutoStartup.EnableViaRegistry();
216-
}
209+
Helper.AutoStartup.CheckIsEnabled(_settings.UseLogonTaskForStartup);
217210
}
218211
catch (Exception e)
219212
{

0 commit comments

Comments
 (0)