Skip to content

Commit 8cc9f2d

Browse files
authored
Merge pull request #3420 from Jack251970/theme_change_api
New API Function from Theme & Improve Theme Model
2 parents c159b48 + a4c8343 commit 8cc9f2d

File tree

6 files changed

+151
-67
lines changed

6 files changed

+151
-67
lines changed

Diff for: Flow.Launcher.Core/Resource/Theme.cs

+20-19
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Flow.Launcher.Infrastructure.Logger;
1717
using Flow.Launcher.Infrastructure.UserSettings;
1818
using Flow.Launcher.Plugin;
19+
using Flow.Launcher.Plugin.SharedModels;
1920
using Microsoft.Win32;
2021

2122
namespace Flow.Launcher.Core.Resource
@@ -81,11 +82,6 @@ public Theme(IPublicAPI publicAPI, Settings settings)
8182

8283
#region Theme Resources
8384

84-
public string GetCurrentTheme()
85-
{
86-
return _settings.Theme;
87-
}
88-
8985
private void MakeSureThemeDirectoriesExist()
9086
{
9187
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
@@ -127,7 +123,7 @@ public void UpdateFonts()
127123
try
128124
{
129125
// Load a ResourceDictionary for the specified theme.
130-
var themeName = GetCurrentTheme();
126+
var themeName = _settings.Theme;
131127
var dict = GetThemeResourceDictionary(themeName);
132128

133129
// Apply font settings to the theme resource.
@@ -330,7 +326,7 @@ private ResourceDictionary GetResourceDictionary(string theme)
330326

331327
private ResourceDictionary GetCurrentResourceDictionary()
332328
{
333-
return GetResourceDictionary(GetCurrentTheme());
329+
return GetResourceDictionary(_settings.Theme);
334330
}
335331

336332
private ThemeData GetThemeDataFromPath(string path)
@@ -383,9 +379,20 @@ private string GetThemePath(string themeName)
383379

384380
#endregion
385381

386-
#region Load & Change
382+
#region Get & Change Theme
383+
384+
public ThemeData GetCurrentTheme()
385+
{
386+
var themes = GetAvailableThemes();
387+
var matchingTheme = themes.FirstOrDefault(t => t.FileNameWithoutExtension == _settings.Theme);
388+
if (matchingTheme == null)
389+
{
390+
Log.Warn($"No matching theme found for '{_settings.Theme}'. Falling back to the first available theme.");
391+
}
392+
return matchingTheme ?? themes.FirstOrDefault();
393+
}
387394

388-
public List<ThemeData> LoadAvailableThemes()
395+
public List<ThemeData> GetAvailableThemes()
389396
{
390397
List<ThemeData> themes = new List<ThemeData>();
391398
foreach (var themeDirectory in _themeDirectories)
@@ -403,7 +410,7 @@ public List<ThemeData> LoadAvailableThemes()
403410
public bool ChangeTheme(string theme = null)
404411
{
405412
if (string.IsNullOrEmpty(theme))
406-
theme = GetCurrentTheme();
413+
theme = _settings.Theme;
407414

408415
string path = GetThemePath(theme);
409416
try
@@ -426,7 +433,7 @@ public bool ChangeTheme(string theme = null)
426433

427434
BlurEnabled = IsBlurTheme();
428435

429-
// Can only apply blur but here also apply drop shadow effect to avoid possible drop shadow effect issues
436+
// Apply blur and drop shadow effect so that we do not need to call it again
430437
_ = RefreshFrameAsync();
431438

432439
return true;
@@ -591,7 +598,7 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
591598
{
592599
AutoDropShadow(useDropShadowEffect);
593600
}
594-
SetBlurForWindow(GetCurrentTheme(), backdropType);
601+
SetBlurForWindow(_settings.Theme, backdropType);
595602

596603
if (!BlurEnabled)
597604
{
@@ -610,7 +617,7 @@ await Application.Current.Dispatcher.InvokeAsync(() =>
610617
// Get the actual backdrop type and drop shadow effect settings
611618
var (backdropType, _) = GetActualValue();
612619

613-
SetBlurForWindow(GetCurrentTheme(), backdropType);
620+
SetBlurForWindow(_settings.Theme, backdropType);
614621
}, DispatcherPriority.Render);
615622
}
616623

@@ -898,11 +905,5 @@ private static bool IsBlurTheme()
898905
}
899906

900907
#endregion
901-
902-
#region Classes
903-
904-
public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null);
905-
906-
#endregion
907908
}
908909
}

Diff for: Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using Flow.Launcher.Plugin.SharedModels;
2-
using JetBrains.Annotations;
3-
using System;
1+
using System;
42
using System.Collections.Generic;
53
using System.ComponentModel;
64
using System.IO;
@@ -9,6 +7,8 @@
97
using System.Threading.Tasks;
108
using System.Windows;
119
using System.Windows.Media;
10+
using Flow.Launcher.Plugin.SharedModels;
11+
using JetBrains.Annotations;
1212

1313
namespace Flow.Launcher.Plugin
1414
{
@@ -352,6 +352,26 @@ public interface IPublicAPI
352352
public void StopLoadingBar();
353353

354354
/// <summary>
355+
/// Get all available themes
356+
/// </summary>
357+
/// <returns></returns>
358+
public List<ThemeData> GetAvailableThemes();
359+
360+
/// <summary>
361+
/// Get the current theme
362+
/// </summary>
363+
/// <returns></returns>
364+
public ThemeData GetCurrentTheme();
365+
366+
/// <summary>
367+
/// Set the current theme
368+
/// </summary>
369+
/// <param name="theme"></param>
370+
/// <returns>
371+
/// True if the theme is set successfully, false otherwise.
372+
/// </returns>
373+
public bool SetCurrentTheme(ThemeData theme);
374+
355375
/// Save all Flow's plugins caches
356376
/// </summary>
357377
void SavePluginCaches();

Diff for: Flow.Launcher.Plugin/SharedModels/ThemeData.cs

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using System;
2+
3+
namespace Flow.Launcher.Plugin.SharedModels;
4+
5+
/// <summary>
6+
/// Theme data model
7+
/// </summary>
8+
public class ThemeData
9+
{
10+
/// <summary>
11+
/// Theme file name without extension
12+
/// </summary>
13+
public string FileNameWithoutExtension { get; private init; }
14+
15+
/// <summary>
16+
/// Theme name
17+
/// </summary>
18+
public string Name { get; private init; }
19+
20+
/// <summary>
21+
/// Indicates whether the theme supports dark mode
22+
/// </summary>
23+
public bool? IsDark { get; private init; }
24+
25+
/// <summary>
26+
/// Indicates whether the theme supports blur effects
27+
/// </summary>
28+
public bool? HasBlur { get; private init; }
29+
30+
/// <summary>
31+
/// Theme data constructor
32+
/// </summary>
33+
public ThemeData(string fileNameWithoutExtension, string name, bool? isDark = null, bool? hasBlur = null)
34+
{
35+
FileNameWithoutExtension = fileNameWithoutExtension;
36+
Name = name;
37+
IsDark = isDark;
38+
HasBlur = hasBlur;
39+
}
40+
41+
/// <inheritdoc />
42+
public static bool operator ==(ThemeData left, ThemeData right)
43+
{
44+
if (left is null && right is null)
45+
return true;
46+
if (left is null || right is null)
47+
return false;
48+
return left.Equals(right);
49+
}
50+
51+
/// <inheritdoc />
52+
public static bool operator !=(ThemeData left, ThemeData right)
53+
{
54+
return !(left == right);
55+
}
56+
57+
/// <inheritdoc />
58+
public override bool Equals(object obj)
59+
{
60+
if (obj is not ThemeData other)
61+
return false;
62+
return FileNameWithoutExtension == other.FileNameWithoutExtension &&
63+
Name == other.Name;
64+
}
65+
66+
/// <inheritdoc />
67+
public override int GetHashCode()
68+
{
69+
return HashCode.Combine(FileNameWithoutExtension, Name);
70+
}
71+
72+
/// <inheritdoc />
73+
public override string ToString()
74+
{
75+
return Name;
76+
}
77+
}

Diff for: Flow.Launcher/PublicAPIInstance.cs

+10
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public class PublicAPIInstance : IPublicAPI, IRemovable
4040
private readonly Internationalization _translater;
4141
private readonly MainViewModel _mainVM;
4242

43+
private Theme _theme;
44+
private Theme Theme => _theme ??= Ioc.Default.GetRequiredService<Theme>();
45+
4346
private readonly object _saveSettingsLock = new();
4447

4548
#region Constructor
@@ -360,6 +363,13 @@ public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "",
360363
public Task ShowProgressBoxAsync(string caption, Func<Action<double>, Task> reportProgressAsync,
361364
Action cancelProgress = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, cancelProgress);
362365

366+
public List<ThemeData> GetAvailableThemes() => Theme.GetAvailableThemes();
367+
368+
public ThemeData GetCurrentTheme() => Theme.GetCurrentTheme();
369+
370+
public bool SetCurrentTheme(ThemeData theme) =>
371+
Theme.ChangeTheme(theme.FileNameWithoutExtension);
372+
363373
private readonly ConcurrentDictionary<(string, string, Type), object> _pluginBinaryStorages = new();
364374

365375
public void RemovePluginCaches(string cacheDirectory)

Diff for: Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs

+7-8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Flow.Launcher.Infrastructure;
1313
using Flow.Launcher.Infrastructure.UserSettings;
1414
using Flow.Launcher.Plugin;
15+
using Flow.Launcher.Plugin.SharedModels;
1516
using Flow.Launcher.ViewModel;
1617
using ModernWpf;
1718
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
@@ -28,25 +29,23 @@ public partial class SettingsPaneThemeViewModel : BaseModel
2829
public static string LinkHowToCreateTheme => @"https://www.flowlauncher.com/theme-builder/";
2930
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
3031

31-
private List<Theme.ThemeData> _themes;
32-
public List<Theme.ThemeData> Themes => _themes ??= _theme.LoadAvailableThemes();
32+
private List<ThemeData> _themes;
33+
public List<ThemeData> Themes => _themes ??= App.API.GetAvailableThemes();
3334

34-
private Theme.ThemeData _selectedTheme;
35-
public Theme.ThemeData SelectedTheme
35+
private ThemeData _selectedTheme;
36+
public ThemeData SelectedTheme
3637
{
37-
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
38+
get => _selectedTheme ??= Themes.Find(v => v == App.API.GetCurrentTheme());
3839
set
3940
{
4041
_selectedTheme = value;
41-
_theme.ChangeTheme(value.FileNameWithoutExtension);
42+
App.API.SetCurrentTheme(value);
4243

4344
// Update UI state
4445
OnPropertyChanged(nameof(BackdropType));
4546
OnPropertyChanged(nameof(IsBackdropEnabled));
4647
OnPropertyChanged(nameof(IsDropShadowEnabled));
4748
OnPropertyChanged(nameof(DropShadowEffect));
48-
49-
_ = _theme.RefreshFrameAsync();
5049
}
5150
}
5251

Diff for: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs

+14-37
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Collections.Generic;
22
using System.Linq;
3-
using CommunityToolkit.Mvvm.DependencyInjection;
4-
using Flow.Launcher.Core.Resource;
3+
using Flow.Launcher.Plugin.SharedModels;
54

65
namespace Flow.Launcher.Plugin.Sys
76
{
@@ -11,61 +10,37 @@ public class ThemeSelector
1110

1211
private readonly PluginInitContext _context;
1312

14-
// Do not initialize it in the constructor, because it will cause null reference in
15-
// var dicts = Application.Current.Resources.MergedDictionaries; line of Theme
16-
private Theme theme = null;
17-
private Theme Theme => theme ??= Ioc.Default.GetRequiredService<Theme>();
18-
19-
#region Theme Selection
20-
21-
// Theme select codes simplified from SettingsPaneThemeViewModel.cs
22-
23-
private Theme.ThemeData _selectedTheme;
24-
public Theme.ThemeData SelectedTheme
25-
{
26-
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == Theme.GetCurrentTheme());
27-
set
28-
{
29-
_selectedTheme = value;
30-
Theme.ChangeTheme(value.FileNameWithoutExtension);
31-
32-
_ = Theme.RefreshFrameAsync();
33-
}
34-
}
35-
36-
private List<Theme.ThemeData> Themes => Theme.LoadAvailableThemes();
37-
38-
#endregion
39-
4013
public ThemeSelector(PluginInitContext context)
4114
{
4215
_context = context;
4316
}
4417

4518
public List<Result> Query(Query query)
4619
{
20+
var themes = _context.API.GetAvailableThemes();
21+
var selectedTheme = _context.API.GetCurrentTheme();
22+
4723
var search = query.SecondToEndSearch;
4824
if (string.IsNullOrWhiteSpace(search))
4925
{
50-
return Themes.Select(CreateThemeResult)
26+
return themes.Select(x => CreateThemeResult(x, selectedTheme))
5127
.OrderBy(x => x.Title)
5228
.ToList();
5329
}
5430

55-
return Themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme.Name)))
31+
return themes.Select(theme => (theme, matchResult: _context.API.FuzzySearch(search, theme.Name)))
5632
.Where(x => x.matchResult.IsSearchPrecisionScoreMet())
57-
.Select(x => CreateThemeResult(x.theme, x.matchResult.Score, x.matchResult.MatchData))
33+
.Select(x => CreateThemeResult(x.theme, selectedTheme, x.matchResult.Score, x.matchResult.MatchData))
5834
.OrderBy(x => x.Title)
5935
.ToList();
6036
}
6137

62-
private Result CreateThemeResult(Theme.ThemeData theme) => CreateThemeResult(theme, 0, null);
38+
private Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme) => CreateThemeResult(theme, selectedTheme, 0, null);
6339

64-
private Result CreateThemeResult(Theme.ThemeData theme, int score, IList<int> highlightData)
40+
private Result CreateThemeResult(ThemeData theme, ThemeData selectedTheme, int score, IList<int> highlightData)
6541
{
66-
string themeName = theme.Name;
6742
string title;
68-
if (theme == SelectedTheme)
43+
if (theme == selectedTheme)
6944
{
7045
title = $"{theme.Name} ★";
7146
// Set current theme to the top
@@ -101,8 +76,10 @@ private Result CreateThemeResult(Theme.ThemeData theme, int score, IList<int> hi
10176
Score = score,
10277
Action = c =>
10378
{
104-
SelectedTheme = theme;
105-
_context.API.ReQuery();
79+
if (_context.API.SetCurrentTheme(theme))
80+
{
81+
_context.API.ReQuery();
82+
}
10683
return false;
10784
}
10885
};

0 commit comments

Comments
 (0)