From f932e88f19dcc767ffd268e791cecdb06f9186a1 Mon Sep 17 00:00:00 2001 From: natsurainko Date: Sat, 2 Nov 2024 00:50:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=8E=E5=9B=BE=E7=89=87=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E4=B8=BB=E9=A2=98=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Utils/DominantColorHelper.cs | 42 +++++++++++++++++++ .../Settings/AppearanceViewModel.cs | 24 ++++++++++- .../Views/Settings/AppearancePage.xaml | 20 +++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 Natsurainko.FluentLauncher/Utils/DominantColorHelper.cs diff --git a/Natsurainko.FluentLauncher/Utils/DominantColorHelper.cs b/Natsurainko.FluentLauncher/Utils/DominantColorHelper.cs new file mode 100644 index 00000000..af074f97 --- /dev/null +++ b/Natsurainko.FluentLauncher/Utils/DominantColorHelper.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Threading.Tasks; + +namespace Natsurainko.FluentLauncher.Utils; + +internal static class DominantColorHelper +{ + public static async Task GetColorFromImageAsync(string imageFile) + { + var colorDictionary = new Dictionary(); + using var bitmap = new Bitmap(imageFile); + + for (int x = 0; x < bitmap.Width; x++) + { + for (int y = 0; y < bitmap.Height; y++) + { + Color pixelColor = bitmap.GetPixel(x, y); + if (!colorDictionary.ContainsKey(pixelColor)) + colorDictionary[pixelColor] = 1; + else colorDictionary[pixelColor] += 1; + } + } + + var resultColor = colorDictionary + .OrderByDescending(kvp => kvp.Value) + .First(kvp => + { + double brightness = 0.299 * kvp.Key.R + 0.587 * kvp.Key.G + 0.114 * kvp.Key.B; + return brightness > 128 && brightness < 240; + }).Key; + + return await Task.FromResult(new Windows.UI.Color + { + A = 255, + R = resultColor.R, + G = resultColor.G, + B = resultColor.B, + }); + } +} diff --git a/Natsurainko.FluentLauncher/ViewModels/Settings/AppearanceViewModel.cs b/Natsurainko.FluentLauncher/ViewModels/Settings/AppearanceViewModel.cs index dfe8c948..46073459 100644 --- a/Natsurainko.FluentLauncher/ViewModels/Settings/AppearanceViewModel.cs +++ b/Natsurainko.FluentLauncher/ViewModels/Settings/AppearanceViewModel.cs @@ -2,12 +2,16 @@ using CommunityToolkit.Mvvm.Input; using FluentLauncher.Infra.Settings.Mvvm; using Microsoft.UI.Composition.SystemBackdrops; +using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.Win32; using Natsurainko.FluentLauncher.Services.Settings; +using Natsurainko.FluentLauncher.Services.UI; using Natsurainko.FluentLauncher.Utils; using Natsurainko.FluentLauncher.ViewModels.Common; +using Natsurainko.FluentLauncher.XamlHelpers.Converters; using System.IO; +using System.Threading.Tasks; using Windows.UI; #nullable disable @@ -17,10 +21,13 @@ internal partial class AppearanceViewModel : SettingsViewModelBase, ISettingsVie { [SettingsProvider] private readonly SettingsService _settingsService; + private readonly NotificationService _notificationService; - public AppearanceViewModel(SettingsService settingsService) + public AppearanceViewModel(SettingsService settingsService, NotificationService notificationService) { _settingsService = settingsService; + _notificationService = notificationService; + (this as ISettingsViewModel).InitializeSettings(); } @@ -30,6 +37,7 @@ public AppearanceViewModel(SettingsService settingsService) [ObservableProperty] [BindToSetting(Path = nameof(SettingsService.BackgroundMode))] + [NotifyPropertyChangedFor(nameof(CanUseImageThemeColor))] private int backgroundMode; [ObservableProperty] @@ -44,6 +52,7 @@ public AppearanceViewModel(SettingsService settingsService) [ObservableProperty] [BindToSetting(Path = nameof(SettingsService.ImageFilePath))] [NotifyPropertyChangedFor(nameof(ImageFileExists))] + [NotifyPropertyChangedFor(nameof(CanUseImageThemeColor))] private string imageFilePath; [ObservableProperty] @@ -71,6 +80,8 @@ public AppearanceViewModel(SettingsService settingsService) public bool ImageFileExists => File.Exists(ImageFilePath); + public bool CanUseImageThemeColor => BackgroundMode == 3 && ImageFileExists; + private Flyout backgroundColorFlyout; private Flyout themeColorFlyout; @@ -96,6 +107,17 @@ private void SelectColorConfirm(Button button) private void RadioButtonChecked(int index) => BackgroundMode = index; + [RelayCommand] + private async Task UseImageThemeColor() + { + CustomThemeColor = await DominantColorHelper.GetColorFromImageAsync(ImageFilePath); + var converter = (ColorHexCodeConverter)Application.Current.Resources["ColorHexCodeConverter"]; + + _notificationService.NotifyWithoutContent( + $"Image theme color successfully set, {converter.Convert(CustomThemeColor, null, null, null)}", + icon: "\uE73E"); + } + /// /// 神金 Command 无法被触发 /// diff --git a/Natsurainko.FluentLauncher/Views/Settings/AppearancePage.xaml b/Natsurainko.FluentLauncher/Views/Settings/AppearancePage.xaml index 67e43bff..eaed69f7 100644 --- a/Natsurainko.FluentLauncher/Views/Settings/AppearancePage.xaml +++ b/Natsurainko.FluentLauncher/Views/Settings/AppearancePage.xaml @@ -343,6 +343,7 @@ + @@ -442,6 +443,25 @@ + + + + + + + +