Skip to content

Commit ea65e20

Browse files
authored
Merge branch 'dev' into quickswitch
2 parents d6e69b2 + d30fdbb commit ea65e20

File tree

26 files changed

+454
-161
lines changed

26 files changed

+454
-161
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;
@@ -58,12 +56,13 @@ public void Save()
5856
public bool AutoQuickSwitch { get; set; } = false;
5957
public bool ShowQuickSwitchWindow { get; set; } = true;
6058

59+
private string _language = Constant.SystemLanguageCode;
6160
public string Language
6261
{
63-
get => language;
62+
get => _language;
6463
set
6564
{
66-
language = value;
65+
_language = value;
6766
OnPropertyChanged();
6867
}
6968
}
@@ -86,18 +85,18 @@ public string Theme
8685
/* Appearance Settings. It should be separated from the setting later.*/
8786
public double WindowHeightSize { get; set; } = 42;
8887
public double ItemHeightSize { get; set; } = 58;
89-
public double QueryBoxFontSize { get; set; } = 20;
88+
public double QueryBoxFontSize { get; set; } = 16;
9089
public double ResultItemFontSize { get; set; } = 16;
9190
public double ResultSubItemFontSize { get; set; } = 13;
92-
public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name;
91+
public string QueryBoxFont { get; set; } = Win32Helper.GetSystemDefaultFont();
9392
public string QueryBoxFontStyle { get; set; }
9493
public string QueryBoxFontWeight { get; set; }
9594
public string QueryBoxFontStretch { get; set; }
96-
public string ResultFont { get; set; } = FontFamily.GenericSansSerif.Name;
95+
public string ResultFont { get; set; } = Win32Helper.GetSystemDefaultFont();
9796
public string ResultFontStyle { get; set; }
9897
public string ResultFontWeight { get; set; }
9998
public string ResultFontStretch { get; set; }
100-
public string ResultSubFont { get; set; } = FontFamily.GenericSansSerif.Name;
99+
public string ResultSubFont { get; set; } = Win32Helper.GetSystemDefaultFont();
101100
public string ResultSubFontStyle { get; set; }
102101
public string ResultSubFontWeight { get; set; }
103102
public string ResultSubFontStretch { get; set; }
@@ -120,7 +119,7 @@ public string Theme
120119
public double? SettingWindowLeft { get; set; } = null;
121120
public WindowState SettingWindowState { get; set; } = WindowState.Normal;
122121

123-
bool _showPlaceholder { get; set; } = false;
122+
private bool _showPlaceholder { get; set; } = true;
124123
public bool ShowPlaceholder
125124
{
126125
get => _showPlaceholder;
@@ -133,7 +132,7 @@ public bool ShowPlaceholder
133132
}
134133
}
135134
}
136-
string _placeholderText { get; set; } = string.Empty;
135+
private string _placeholderText { get; set; } = string.Empty;
137136
public string PlaceholderText
138137
{
139138
get => _placeholderText;
@@ -146,7 +145,6 @@ public string PlaceholderText
146145
}
147146
}
148147
}
149-
150148
public int CustomExplorerIndex { get; set; } = 0;
151149

152150
[JsonIgnore]
@@ -313,7 +311,7 @@ public bool KeepMaxResults
313311
public bool StartFlowLauncherOnSystemStartup { get; set; } = false;
314312
public bool UseLogonTaskForStartup { get; set; } = false;
315313
public bool HideOnStartup { get; set; } = true;
316-
bool _hideNotifyIcon { get; set; }
314+
private bool _hideNotifyIcon;
317315
public bool HideNotifyIcon
318316
{
319317
get => _hideNotifyIcon;

Flow.Launcher.Infrastructure/Win32Helper.cs

Lines changed: 71 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;
56
using System.IO;
7+
using System.Linq;
68
using System.Runtime.InteropServices;
79
using System.Threading;
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;
@@ -18,6 +21,7 @@
1821
using WindowsInput;
1922
using WindowsInput.Native;
2023
using Point = System.Windows.Point;
24+
using SystemFonts = System.Windows.SystemFonts;
2125

2226
namespace Flow.Launcher.Infrastructure
2327
{
@@ -746,6 +750,73 @@ public static unsafe bool GetWindowRect(nint handle, out Rect outRect)
746750
rect.bottom - rect.top
747751
);
748752
return true;
753+
754+
#endregion
755+
756+
#region System Font
757+
758+
private static readonly Dictionary<string, string> _languageToNotoSans = new()
759+
{
760+
{ "ko", "Noto Sans KR" },
761+
{ "ja", "Noto Sans JP" },
762+
{ "zh-CN", "Noto Sans SC" },
763+
{ "zh-SG", "Noto Sans SC" },
764+
{ "zh-Hans", "Noto Sans SC" },
765+
{ "zh-TW", "Noto Sans TC" },
766+
{ "zh-HK", "Noto Sans TC" },
767+
{ "zh-MO", "Noto Sans TC" },
768+
{ "zh-Hant", "Noto Sans TC" },
769+
{ "th", "Noto Sans Thai" },
770+
{ "ar", "Noto Sans Arabic" },
771+
{ "he", "Noto Sans Hebrew" },
772+
{ "hi", "Noto Sans Devanagari" },
773+
{ "bn", "Noto Sans Bengali" },
774+
{ "ta", "Noto Sans Tamil" },
775+
{ "el", "Noto Sans Greek" },
776+
{ "ru", "Noto Sans" },
777+
{ "en", "Noto Sans" },
778+
{ "fr", "Noto Sans" },
779+
{ "de", "Noto Sans" },
780+
{ "es", "Noto Sans" },
781+
{ "pt", "Noto Sans" }
782+
};
783+
784+
public static string GetSystemDefaultFont()
785+
{
786+
try
787+
{
788+
var culture = CultureInfo.CurrentCulture;
789+
var language = culture.Name; // e.g., "zh-TW"
790+
var langPrefix = language.Split('-')[0]; // e.g., "zh"
791+
792+
// First, try to find by full name, and if not found, fallback to prefix
793+
if (TryGetNotoFont(language, out var notoFont) || TryGetNotoFont(langPrefix, out notoFont))
794+
{
795+
// If the font is installed, return it
796+
if (Fonts.SystemFontFamilies.Any(f => f.Source.Equals(notoFont)))
797+
{
798+
return notoFont;
799+
}
800+
}
801+
802+
// If Noto font is not found, fallback to the system default font
803+
var font = SystemFonts.MessageFontFamily;
804+
if (font.FamilyNames.TryGetValue(XmlLanguage.GetLanguage("en-US"), out var englishName))
805+
{
806+
return englishName;
807+
}
808+
809+
return font.Source ?? "Segoe UI";
810+
}
811+
catch
812+
{
813+
return "Segoe UI";
814+
}
815+
}
816+
817+
private static bool TryGetNotoFont(string langKey, out string notoFont)
818+
{
819+
return _languageToNotoSans.TryGetValue(langKey, out notoFont);
749820
}
750821

751822
#endregion

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
@@ -205,18 +205,11 @@ private void AutoStartup()
205205
{
206206
// we try to enable auto-startup on first launch, or reenable if it was removed
207207
// but the user still has the setting set
208-
if (_settings.StartFlowLauncherOnSystemStartup && !Helper.AutoStartup.IsEnabled)
208+
if (_settings.StartFlowLauncherOnSystemStartup)
209209
{
210210
try
211211
{
212-
if (_settings.UseLogonTaskForStartup)
213-
{
214-
Helper.AutoStartup.EnableViaLogonTask();
215-
}
216-
else
217-
{
218-
Helper.AutoStartup.EnableViaRegistry();
219-
}
212+
Helper.AutoStartup.CheckIsEnabled(_settings.UseLogonTaskForStartup);
220213
}
221214
catch (Exception e)
222215
{

0 commit comments

Comments
 (0)