From a3b250dd467d4d785501c94d2db8c7c36c562500 Mon Sep 17 00:00:00 2001 From: Zhe Fang Date: Wed, 4 Jun 2025 20:12:45 -0400 Subject: [PATCH] update docs, fix a lot bugs --- .../BetterLyrics.WinUI3 (Package).wapproj | 6 +- .../Package.appxmanifest | 2 +- .../BetterLyrics.WinUI3/App.xaml | 8 +- .../BetterLyrics.WinUI3/App.xaml.cs | 53 ++- .../BetterLyrics.WinUI3/Assets/TestMusic.mp3 | Bin 0 -> 1445162 bytes .../BetterLyrics.WinUI3.csproj | 106 +++-- .../Helper/AnimationHelper.cs | 39 +- .../BetterLyrics.WinUI3/Helper/AppInfo.cs | 55 +++ .../BetterLyrics.WinUI3/Helper/ColorThief.cs | 380 ++++++------------ .../Helper/DatabaseHelper.cs | 21 - .../Helper/VisualHelper.cs | 8 +- .../BetterLyrics.WinUI3/MainWindow.xaml.cs | 25 +- .../Messages/SystemBackdropChangedMessage.cs | 4 +- .../Messages/ThemeChangedMessage.cs | 4 +- .../Models/MetadataIndex.cs | 11 +- .../BetterLyrics.WinUI3/Models/MusicFolder.cs | 20 - .../BetterLyrics.WinUI3/Program.cs | 89 ++++ .../Services/Database/DatabaseService.cs | 18 +- .../Services/Settings/SettingsService.cs | 46 +-- .../Strings/en-US/Resources.resw | 17 +- .../Strings/zh-CN/Resources.resw | 15 + .../Strings/zh-TW/Resources.resw | 15 + .../ViewModels/MainViewModel.cs | 20 +- .../ViewModels/SettingsViewModel.cs | 77 ++-- .../BetterLyrics.WinUI3/Views/MainPage.xaml | 278 ++++++------- .../Views/MainPage.xaml.cs | 104 +++-- .../Views/SettingsPage.xaml | 63 +-- .../Views/SettingsPage.xaml.cs | 29 +- How2Install/How2Install.md | 35 ++ How2Install/image-1.png | Bin 0 -> 121201 bytes How2Install/image-2.png | Bin 0 -> 101526 bytes How2Install/image-3.png | Bin 0 -> 52548 bytes How2Install/image-4.png | Bin 0 -> 52548 bytes How2Install/image-5.png | Bin 0 -> 46139 bytes How2Install/image-6.png | Bin 0 -> 112012 bytes How2Install/image.png | Bin 0 -> 85998 bytes README.md | 6 + 37 files changed, 781 insertions(+), 773 deletions(-) create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/TestMusic.mp3 create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AppInfo.cs delete mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DatabaseHelper.cs delete mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MusicFolder.cs create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Program.cs create mode 100644 How2Install/How2Install.md create mode 100644 How2Install/image-1.png create mode 100644 How2Install/image-2.png create mode 100644 How2Install/image-3.png create mode 100644 How2Install/image-4.png create mode 100644 How2Install/image-5.png create mode 100644 How2Install/image-6.png create mode 100644 How2Install/image.png diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package).wapproj b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package).wapproj index fcbc5b7..bb19ab6 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package).wapproj +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/BetterLyrics.WinUI3 (Package).wapproj @@ -40,15 +40,16 @@ 10.0.17763.0 net8.0-windows$(TargetPlatformVersion);$(AssetTargetFallback) zh-CN - false + True ..\BetterLyrics.WinUI3\BetterLyrics.WinUI3.csproj False SHA256 - True + False True x86|x64|arm64 True 0 + BetterLyrics.WinUI3 %28Package%29_TemporaryKey.pfx Always @@ -80,6 +81,7 @@ + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest index 3add04e..ee9c2f6 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest @@ -10,7 +10,7 @@ + Version="1.0.0.0" /> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml index 651e4b9..0258d61 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml @@ -16,12 +16,8 @@ - - #80000000 - - - #80FFFFFF - + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs index b00ee70..853f48b 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs @@ -7,7 +7,17 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.Windows.ApplicationModel.Resources; +using System.IO; using System.Text; +using System; +using Microsoft.Extensions.Logging; +using Serilog; +using Windows.ApplicationModel.Core; +using Serilog.Core; +using BetterLyrics.WinUI3.Models; +using Newtonsoft.Json; +using System.Collections.Generic; +using Microsoft.Windows.AppLifecycle; // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. @@ -17,11 +27,14 @@ namespace BetterLyrics.WinUI3 { /// Provides application-specific behavior to supplement the default Application class. /// public partial class App : Application { - public static App Current => (App)Application.Current; + + private readonly ILogger _logger; + + public static new App Current => (App)Application.Current; public MainWindow? MainWindow { get; private set; } public MainWindow? SettingsWindow { get; set; } - public static ResourceLoader ResourceLoader = new(); + public static ResourceLoader? ResourceLoader { get; private set; } public static DispatcherQueue DispatcherQueue => DispatcherQueue.GetForCurrentThread(); @@ -31,18 +44,32 @@ namespace BetterLyrics.WinUI3 { /// public App() { this.InitializeComponent(); + + App.ResourceLoader = new ResourceLoader(); + + Helper.AppInfo.EnsureDirectories(); + ConfigureServices(); + + _logger = Ioc.Default.GetService>()!; + + UnhandledException += App_UnhandledException; } - /// - /// Invoked when the application is launched. - /// - /// Details about the launch request and process. - protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { + private static void ConfigureServices() { + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .WriteTo.File(Helper.AppInfo.LogFilePattern, rollingInterval: RollingInterval.Day) + .CreateLogger(); // Register services Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(DispatcherQueue.GetForCurrentThread()) + .AddLogging(loggingBuilder => { + loggingBuilder.ClearProviders(); + loggingBuilder.AddSerilog(); + }) // Services .AddSingleton() .AddSingleton() @@ -50,6 +77,18 @@ namespace BetterLyrics.WinUI3 { .AddSingleton() .AddSingleton() .BuildServiceProvider()); + } + + private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) { + _logger.LogError(e.Exception, "App_UnhandledException"); + e.Handled = true; + } + + /// + /// Invoked when the application is launched. + /// + /// Details about the launch request and process. + protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/TestMusic.mp3 b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Assets/TestMusic.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..29bf4b498413ce975079018a137e0ca962c38a5f GIT binary patch literal 1445162 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 UE7tqZo - - WinExe - net8.0-windows10.0.26100.0 - 10.0.17763.0 - BetterLyrics.WinUI3 - app.manifest - x86;x64;ARM64 - win-x86;win-x64;win-arm64 - true - enable - + + WinExe + net8.0-windows10.0.26100.0 + 10.0.19041.0 + BetterLyrics.WinUI3 + app.manifest + x86;x64;ARM64 + win-x86;win-x64;win-arm64 + true + enable + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + Never + + + Never + + + + + + False + True + False + True + 10.0.19041.0 + + + + $(DefineConstants);DISABLE_XAML_GENERATED_MAIN + - - - False - True - False - True - 10.0.19041.0 - \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AnimationHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AnimationHelper.cs index e407c98..6b7d0a4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AnimationHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AnimationHelper.cs @@ -4,41 +4,10 @@ using System; namespace BetterLyrics.WinUI3.Helper { - /// - /// Edited based on: https://stackoverflow.com/a/25236507/11048731 - /// - public class AnimationHelper : DependencyObject { - public static int GetAnimationDuration(DependencyObject obj) { - return (int)obj.GetValue(AnimationDurationProperty); - } - - public static void SetAnimationDuration(DependencyObject obj, int value) { - obj.SetValue(AnimationDurationProperty, value); - } - - // Using a DependencyProperty as the backing store for AnimationDuration. - // This enables animation, styling, binding, etc... - public static readonly DependencyProperty AnimationDurationProperty = - DependencyProperty.RegisterAttached("AnimationDuration", typeof(int), - typeof(AnimationHelper), new PropertyMetadata(0, - OnAnimationDurationChanged)); - - private static void OnAnimationDurationChanged(DependencyObject d, - DependencyPropertyChangedEventArgs e) { - FrameworkElement element = d as FrameworkElement; - - var ms = (int)e.NewValue; - - if (ms < 0) return; - - var key = "LyricsLineCharGradientInTextBlock"; - foreach (var timeline in (element.Resources[key] as Storyboard).Children) { - foreach (var keyFrame in (timeline as DoubleAnimationUsingKeyFrames).KeyFrames) { - (keyFrame as LinearDoubleKeyFrame).KeyTime = - KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(ms)); - } - } - } + public static class AnimationHelper { + public const int StackedNotificationsShowingDuration = 3900; + public const int StoryboardDefaultDuration = 200; + public const int DebounceDefaultDuration = 200; } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AppInfo.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AppInfo.cs new file mode 100644 index 0000000..f2632d6 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/AppInfo.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BetterLyrics.WinUI3.Helper { + using System; + using System.IO; + using Windows.ApplicationModel; + using Windows.Storage; + + public static class AppInfo { + // App Metadata + public const string AppName = "BetterLyrics"; + public const string AppDisplayName = "Better Lyrics"; + public const string AppAuthor = "Zhe Fang"; + public const string GithubUrl = "https://github.com/jayfunc/BetterLyrics"; + public static string AppVersion { + get { + var version = Package.Current.Id.Version; + return $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"; + } + } + + // Environment Info + public static bool IsDebug => +#if DEBUG + true; +#else + false; +#endif + + // Base Folders + private static string LocalFolder => ApplicationData.Current.LocalFolder.Path; + private static string CacheFolder => ApplicationData.Current.LocalCacheFolder.Path; + public static string AssetsFolder => Path.Combine(AppContext.BaseDirectory, "Assets"); + + // Data Files + private static string DatabaseFileName => "database.db"; + public static string DatabasePath => Path.Combine(LocalFolder, DatabaseFileName); + + public static string LogDirectory => Path.Combine(CacheFolder, "logs"); + public static string LogFilePattern => Path.Combine(LogDirectory, "log-.txt"); + + private static string TestMusicFileName => "TestMusic.mp3"; + public static string TestMusicPath => Path.Combine(AssetsFolder, TestMusicFileName); + + public static void EnsureDirectories() { + Directory.CreateDirectory(LogDirectory); + Directory.CreateDirectory(LocalFolder); + } + } + +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ColorThief.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ColorThief.cs index 61139a8..17f7457 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ColorThief.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ColorThief.cs @@ -4,26 +4,21 @@ using System.Linq; using System.Threading.Tasks; using Windows.Graphics.Imaging; -namespace BetterLyrics.WinUI3.Helper -{ +namespace BetterLyrics.WinUI3.Helper { /// /// Color map /// - internal class CMap - { + internal class CMap { private readonly List vboxes = new List(); - private List palette; + private List? palette; - public void Push(VBox box) - { + public void Push(VBox box) { palette = null; vboxes.Add(box); } - public List GeneratePalette() - { - if (palette == null) - { + public List GeneratePalette() { + if (palette == null) { palette = (from vBox in vboxes let rgb = vBox.Avg(false) let color = FromRgb(rgb[0], rgb[1], rgb[2]) @@ -33,33 +28,27 @@ namespace BetterLyrics.WinUI3.Helper return palette; } - public int Size() - { + public int Size() { return vboxes.Count; } - public int[] Map(int[] color) - { - foreach (var vbox in vboxes.Where(vbox => vbox.Contains(color))) - { + public int[]? Map(int[] color) { + foreach (var vbox in vboxes.Where(vbox => vbox.Contains(color))) { return vbox.Avg(false); } return Nearest(color); } - public int[] Nearest(int[] color) - { + public int[]? Nearest(int[] color) { var d1 = double.MaxValue; - int[] pColor = null; + int[]? pColor = null; - foreach (var t in vboxes) - { + foreach (var t in vboxes) { var vbColor = t.Avg(false); var d2 = Math.Sqrt(Math.Pow(color[0] - vbColor[0], 2) + Math.Pow(color[1] - vbColor[1], 2) + Math.Pow(color[2] - vbColor[2], 2)); - if (d2 < d1) - { + if (d2 < d1) { d1 = d2; pColor = vbColor; } @@ -67,27 +56,23 @@ namespace BetterLyrics.WinUI3.Helper return pColor; } - public VBox FindColor(double targetLuma, double minLuma, double maxLuma, double targetSaturation, double minSaturation, double maxSaturation) - { - VBox max = null; + public VBox FindColor(double targetLuma, double minLuma, double maxLuma, double targetSaturation, double minSaturation, double maxSaturation) { + VBox? max = null; double maxValue = 0; var highestPopulation = vboxes.Select(p => p.Count(false)).Max(); - foreach (var swatch in vboxes) - { + foreach (var swatch in vboxes) { var avg = swatch.Avg(false); var hsl = FromRgb(avg[0], avg[1], avg[2]).ToHsl(); var sat = hsl.S; var luma = hsl.L; if (sat >= minSaturation && sat <= maxSaturation && - luma >= minLuma && luma <= maxLuma) - { + luma >= minLuma && luma <= maxLuma) { var thisValue = Mmcq.CreateComparisonValue(sat, targetSaturation, luma, targetLuma, swatch.Count(false), highestPopulation); - if (max == null || thisValue > maxValue) - { + if (max == null || thisValue > maxValue) { max = swatch; maxValue = thisValue; } @@ -97,10 +82,8 @@ namespace BetterLyrics.WinUI3.Helper return max; } - public Color FromRgb(int red, int green, int blue) - { - var color = new Color - { + public Color FromRgb(int red, int green, int blue) { + var color = new Color { A = 255, R = (byte)red, G = (byte)green, @@ -114,8 +97,7 @@ namespace BetterLyrics.WinUI3.Helper /// /// Defines a color in RGB space. /// - public struct Color - { + public struct Color { /// /// Get or Set the Alpha component value for sRGB. /// @@ -140,8 +122,7 @@ namespace BetterLyrics.WinUI3.Helper /// Get HSL color. /// /// - public HslColor ToHsl() - { + public HslColor ToHsl() { const double toDouble = 1.0 / 255; var r = toDouble * R; var g = toDouble * G; @@ -152,20 +133,14 @@ namespace BetterLyrics.WinUI3.Helper double h1; // ReSharper disable CompareOfFloatsByEqualityOperator - if (chroma == 0) - { + if (chroma == 0) { h1 = 0; - } - else if (max == r) - { + } else if (max == r) { h1 = (g - b) / chroma % 6; - } - else if (max == g) - { + } else if (max == g) { h1 = 2 + (b - r) / chroma; - } - else //if (max == b) - { + } else //if (max == b) + { h1 = 4 + (r - g) / chroma; } @@ -180,20 +155,16 @@ namespace BetterLyrics.WinUI3.Helper // ReSharper restore CompareOfFloatsByEqualityOperator } - public string ToHexString() - { + public string ToHexString() { return "#" + R.ToString("X2") + G.ToString("X2") + B.ToString("X2"); } - public string ToHexAlphaString() - { + public string ToHexAlphaString() { return "#" + A.ToString("X2") + R.ToString("X2") + G.ToString("X2") + B.ToString("X2"); } - public override string ToString() - { - if (A == 255) - { + public override string ToString() { + if (A == 255) { return ToHexString(); } @@ -204,8 +175,7 @@ namespace BetterLyrics.WinUI3.Helper /// /// Defines a color in Hue/Saturation/Lightness (HSL) space. /// - public struct HslColor - { + public struct HslColor { /// /// The Alpha/opacity in 0..1 range. /// @@ -227,8 +197,7 @@ namespace BetterLyrics.WinUI3.Helper public double S; } - internal static class Mmcq - { + internal static class Mmcq { public const int Sigbits = 5; public const int Rshift = 8 - Sigbits; public const int Mult = 1 << Rshift; @@ -242,8 +211,7 @@ namespace BetterLyrics.WinUI3.Helper private static readonly VBoxComparer ComparatorProduct = new VBoxComparer(); private static readonly VBoxCountComparer ComparatorCount = new VBoxCountComparer(); - public static int GetColorIndex(int r, int g, int b) - { + public static int GetColorIndex(int r, int g, int b) { return (r << (2 * Sigbits)) + (g << Sigbits) + b; } @@ -252,12 +220,10 @@ namespace BetterLyrics.WinUI3.Helper /// /// The pixels. /// Histo (1-d array, giving the number of pixels in each quantized region of color space), or null on error. - private static int[] GetHisto(IEnumerable pixels) - { + private static int[] GetHisto(IEnumerable pixels) { var histo = new int[Histosize]; - foreach (var pixel in pixels) - { + foreach (var pixel in pixels) { var rval = pixel[0] >> Rshift; var gval = pixel[1] >> Rshift; var bval = pixel[2] >> Rshift; @@ -267,45 +233,34 @@ namespace BetterLyrics.WinUI3.Helper return histo; } - private static VBox VboxFromPixels(IList pixels, int[] histo) - { + private static VBox VboxFromPixels(IList pixels, int[] histo) { int rmin = 1000000, rmax = 0; int gmin = 1000000, gmax = 0; int bmin = 1000000, bmax = 0; // find min/max var numPixels = pixels.Count; - for (var i = 0; i < numPixels; i++) - { + for (var i = 0; i < numPixels; i++) { var pixel = pixels[i]; var rval = pixel[0] >> Rshift; var gval = pixel[1] >> Rshift; var bval = pixel[2] >> Rshift; - if (rval < rmin) - { + if (rval < rmin) { rmin = rval; - } - else if (rval > rmax) - { + } else if (rval > rmax) { rmax = rval; } - if (gval < gmin) - { + if (gval < gmin) { gmin = gval; - } - else if (gval > gmax) - { + } else if (gval > gmax) { gmax = gval; } - if (bval < bmin) - { + if (bval < bmin) { bmin = bval; - } - else if (bval > bmax) - { + } else if (bval > bmax) { bmax = bval; } } @@ -313,13 +268,11 @@ namespace BetterLyrics.WinUI3.Helper return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, histo); } - private static VBox[] DoCut(char color, VBox vbox, IList partialsum, IList lookaheadsum, int total) - { + private static VBox[] DoCut(char color, VBox vbox, IList partialsum, IList lookaheadsum, int total) { int vboxDim1; int vboxDim2; - switch (color) - { + switch (color) { case 'r': vboxDim1 = vbox.R1; vboxDim2 = vbox.R2; @@ -334,10 +287,8 @@ namespace BetterLyrics.WinUI3.Helper break; } - for (var i = vboxDim1; i <= vboxDim2; i++) - { - if (partialsum[i] > total / 2) - { + for (var i = vboxDim1; i <= vboxDim2; i++) { + if (partialsum[i] > total / 2) { var vbox1 = vbox.Clone(); var vbox2 = vbox.Clone(); @@ -349,19 +300,16 @@ namespace BetterLyrics.WinUI3.Helper : Math.Max(vboxDim1, Math.Abs(Convert.ToInt32(i - 1 - left / 2.0))); // avoid 0-count boxes - while (d2 < 0 || partialsum[d2] <= 0) - { + while (d2 < 0 || partialsum[d2] <= 0) { d2++; } var count2 = lookaheadsum[d2]; - while (count2 == 0 && d2 > 0 && partialsum[d2 - 1] > 0) - { + while (count2 == 0 && d2 > 0 && partialsum[d2 - 1] > 0) { count2 = lookaheadsum[--d2]; } // set dimensions - switch (color) - { + switch (color) { case 'r': vbox1.R2 = d2; vbox2.R1 = d2 + 1; @@ -383,15 +331,12 @@ namespace BetterLyrics.WinUI3.Helper throw new Exception("VBox can't be cut"); } - private static VBox[] MedianCutApply(IList histo, VBox vbox) - { - if (vbox.Count(false) == 0) - { + private static VBox?[]? MedianCutApply(IList histo, VBox vbox) { + if (vbox.Count(false) == 0) { return null; } - if (vbox.Count(false) == 1) - { - return new[] { vbox.Clone(), null }; + if (vbox.Count(false) == 1) { + return [vbox.Clone(), null]; } // only one pixel, no split @@ -405,29 +350,23 @@ namespace BetterLyrics.WinUI3.Helper var total = 0; var partialsum = new int[VboxLength]; // -1 = not set / 0 = 0 - for (var l = 0; l < partialsum.Length; l++) - { + for (var l = 0; l < partialsum.Length; l++) { partialsum[l] = -1; } // -1 = not set / 0 = 0 var lookaheadsum = new int[VboxLength]; - for (var l = 0; l < lookaheadsum.Length; l++) - { + for (var l = 0; l < lookaheadsum.Length; l++) { lookaheadsum[l] = -1; } int i, j, k, sum, index; - if (maxw == rw) - { - for (i = vbox.R1; i <= vbox.R2; i++) - { + if (maxw == rw) { + for (i = vbox.R1; i <= vbox.R2; i++) { sum = 0; - for (j = vbox.G1; j <= vbox.G2; j++) - { - for (k = vbox.B1; k <= vbox.B2; k++) - { + for (j = vbox.G1; j <= vbox.G2; j++) { + for (k = vbox.B1; k <= vbox.B2; k++) { index = GetColorIndex(i, j, k); sum += histo[index]; } @@ -435,16 +374,11 @@ namespace BetterLyrics.WinUI3.Helper total += sum; partialsum[i] = total; } - } - else if (maxw == gw) - { - for (i = vbox.G1; i <= vbox.G2; i++) - { + } else if (maxw == gw) { + for (i = vbox.G1; i <= vbox.G2; i++) { sum = 0; - for (j = vbox.R1; j <= vbox.R2; j++) - { - for (k = vbox.B1; k <= vbox.B2; k++) - { + for (j = vbox.R1; j <= vbox.R2; j++) { + for (k = vbox.B1; k <= vbox.B2; k++) { index = GetColorIndex(j, i, k); sum += histo[index]; } @@ -452,16 +386,12 @@ namespace BetterLyrics.WinUI3.Helper total += sum; partialsum[i] = total; } - } - else /* maxw == bw */ - { - for (i = vbox.B1; i <= vbox.B2; i++) - { + } else /* maxw == bw */ + { + for (i = vbox.B1; i <= vbox.B2; i++) { sum = 0; - for (j = vbox.R1; j <= vbox.R2; j++) - { - for (k = vbox.G1; k <= vbox.G2; k++) - { + for (j = vbox.R1; j <= vbox.R2; j++) { + for (k = vbox.G1; k <= vbox.G2; k++) { index = GetColorIndex(j, k, i); sum += histo[index]; } @@ -471,10 +401,8 @@ namespace BetterLyrics.WinUI3.Helper } } - for (i = 0; i < VboxLength; i++) - { - if (partialsum[i] != -1) - { + for (i = 0; i < VboxLength; i++) { + if (partialsum[i] != -1) { lookaheadsum[i] = total - partialsum[i]; } } @@ -492,16 +420,13 @@ namespace BetterLyrics.WinUI3.Helper /// The target. /// The histo. /// vbox1 not defined; shouldn't happen! - private static void Iter(List lh, IComparer comparator, int target, IList histo) - { + private static void Iter(List lh, IComparer comparator, int target, IList histo) { var ncolors = 1; var niters = 0; - while (niters < MaxIterations) - { + while (niters < MaxIterations) { var vbox = lh[lh.Count - 1]; - if (vbox.Count(false) == 0) - { + if (vbox.Count(false) == 0) { lh.Sort(comparator); niters++; continue; @@ -511,39 +436,33 @@ namespace BetterLyrics.WinUI3.Helper // do the cut var vboxes = MedianCutApply(histo, vbox); - var vbox1 = vboxes[0]; - var vbox2 = vboxes[1]; + var vbox1 = vboxes?[0]; + var vbox2 = vboxes?[1]; - if (vbox1 == null) - { + if (vbox1 == null) { throw new Exception( "vbox1 not defined; shouldn't happen!"); } lh.Add(vbox1); - if (vbox2 != null) - { + if (vbox2 != null) { lh.Add(vbox2); ncolors++; } lh.Sort(comparator); - if (ncolors >= target) - { + if (ncolors >= target) { return; } - if (niters++ > MaxIterations) - { + if (niters++ > MaxIterations) { return; } } } - public static CMap Quantize(byte[][] pixels, int maxcolors) - { + public static CMap Quantize(byte[][] pixels, int maxcolors) { // short-circuit - if (pixels.Length == 0 || maxcolors < 2 || maxcolors > 256) - { + if (pixels.Length == 0 || maxcolors < 2 || maxcolors > 256) { return null; } @@ -571,28 +490,24 @@ namespace BetterLyrics.WinUI3.Helper // calculate the actual colors var cmap = new CMap(); - foreach (var vb in pq) - { + foreach (var vb in pq) { cmap.Push(vb); } return cmap; } - public static double CreateComparisonValue(double saturation, double targetSaturation, double luma, double targetLuma, int population, int highestPopulation) - { + public static double CreateComparisonValue(double saturation, double targetSaturation, double luma, double targetLuma, int population, int highestPopulation) { return WeightedMean(InvertDiff(saturation, targetSaturation), WeightSaturation, InvertDiff(luma, targetLuma), WeightLuma, population / (double)highestPopulation, WeightPopulation); } - private static double WeightedMean(params double[] values) - { + private static double WeightedMean(params double[] values) { double sum = 0; double sumWeight = 0; - for (var i = 0; i < values.Length; i += 2) - { + for (var i = 0; i < values.Length; i += 2) { var value = values[i]; var weight = values[i + 1]; @@ -603,16 +518,13 @@ namespace BetterLyrics.WinUI3.Helper return sum / sumWeight; } - private static double InvertDiff(double value, double targetValue) - { + private static double InvertDiff(double value, double targetValue) { return 1 - Math.Abs(value - targetValue); } } - public class QuantizedColor - { - public QuantizedColor(Color color, int population) - { + public class QuantizedColor { + public QuantizedColor(Color color, int population) { Color = color; Population = population; IsDark = CalculateYiqLuma(color) < 128; @@ -622,8 +534,7 @@ namespace BetterLyrics.WinUI3.Helper public int Population { get; private set; } public bool IsDark { get; private set; } - public int CalculateYiqLuma(Color color) - { + public int CalculateYiqLuma(Color color) { return Convert.ToInt32(Math.Round((299 * color.R + 587 * color.G + 114 * color.B) / 1000f)); } } @@ -631,8 +542,7 @@ namespace BetterLyrics.WinUI3.Helper /// /// 3D color space box. /// - internal class VBox - { + internal class VBox { private readonly int[] histo; private int[] avg; public int B1; @@ -644,8 +554,7 @@ namespace BetterLyrics.WinUI3.Helper public int R2; private int? volume; - public VBox(int r1, int r2, int g1, int g2, int b1, int b2, int[] histo) - { + public VBox(int r1, int r2, int g1, int g2, int b1, int b2, int[] histo) { R1 = r1; R2 = r2; G1 = g1; @@ -656,31 +565,24 @@ namespace BetterLyrics.WinUI3.Helper this.histo = histo; } - public int Volume(bool force) - { - if (volume == null || force) - { + public int Volume(bool force) { + if (volume == null || force) { volume = (R2 - R1 + 1) * (G2 - G1 + 1) * (B2 - B1 + 1); } return volume.Value; } - public int Count(bool force) - { - if (count == null || force) - { + public int Count(bool force) { + if (count == null || force) { var npix = 0; int i; - for (i = R1; i <= R2; i++) - { + for (i = R1; i <= R2; i++) { int j; - for (j = G1; j <= G2; j++) - { + for (j = G1; j <= G2; j++) { int k; - for (k = B1; k <= B2; k++) - { + for (k = B1; k <= B2; k++) { var index = Mmcq.GetColorIndex(i, j, k); npix += histo[index]; } @@ -693,15 +595,12 @@ namespace BetterLyrics.WinUI3.Helper return count.Value; } - public VBox Clone() - { + public VBox Clone() { return new VBox(R1, R2, G1, G2, B1, B2, histo); } - public int[] Avg(bool force) - { - if (avg == null || force) - { + public int[] Avg(bool force) { + if (avg == null || force) { var ntot = 0; var rsum = 0; @@ -710,14 +609,11 @@ namespace BetterLyrics.WinUI3.Helper int i; - for (i = R1; i <= R2; i++) - { + for (i = R1; i <= R2; i++) { int j; - for (j = G1; j <= G2; j++) - { + for (j = G1; j <= G2; j++) { int k; - for (k = B1; k <= B2; k++) - { + for (k = B1; k <= B2; k++) { var histoindex = Mmcq.GetColorIndex(i, j, k); var hval = histo[histoindex]; ntot += hval; @@ -728,16 +624,13 @@ namespace BetterLyrics.WinUI3.Helper } } - if (ntot > 0) - { + if (ntot > 0) { avg = new[] { Math.Abs(rsum / ntot), Math.Abs(gsum / ntot), Math.Abs(bsum / ntot) }; - } - else - { + } else { avg = new[] { Math.Abs(Mmcq.Mult * (R1 + R2 + 1) / 2), @@ -750,8 +643,7 @@ namespace BetterLyrics.WinUI3.Helper return avg; } - public bool Contains(int[] pixel) - { + public bool Contains(int[] pixel) { var rval = pixel[0] >> Mmcq.Rshift; var gval = pixel[1] >> Mmcq.Rshift; var bval = pixel[2] >> Mmcq.Rshift; @@ -760,20 +652,16 @@ namespace BetterLyrics.WinUI3.Helper } } - internal class VBoxCountComparer : IComparer - { - public int Compare(VBox x, VBox y) - { + internal class VBoxCountComparer : IComparer { + public int Compare(VBox x, VBox y) { var a = x.Count(false); var b = y.Count(false); return a < b ? -1 : (a > b ? 1 : 0); } } - internal class VBoxComparer : IComparer - { - public int Compare(VBox x, VBox y) - { + internal class VBoxComparer : IComparer { + public int Compare(VBox x, VBox y) { var aCount = x.Count(false); var bCount = y.Count(false); var aVolume = x.Volume(false); @@ -786,20 +674,17 @@ namespace BetterLyrics.WinUI3.Helper } } - public class ColorThief - { + public class ColorThief { public const int DefaultColorCount = 5; public const int DefaultQuality = 10; public const bool DefaultIgnoreWhite = true; public const int ColorDepth = 4; - private CMap GetColorMap(byte[][] pixelArray, int colorCount) - { + private CMap GetColorMap(byte[][] pixelArray, int colorCount) { // Send array to quantize function which clusters values using median // cut algorithm - if (colorCount > 0) - { + if (colorCount > 0) { --colorCount; } @@ -807,13 +692,11 @@ namespace BetterLyrics.WinUI3.Helper return cmap; } - private byte[][] ConvertPixels(byte[] pixels, int pixelCount, int quality, bool ignoreWhite) - { + private byte[][] ConvertPixels(byte[] pixels, int pixelCount, int quality, bool ignoreWhite) { var expectedDataLength = pixelCount * ColorDepth; - if (expectedDataLength != pixels.Length) - { + if (expectedDataLength != pixels.Length) { throw new ArgumentException("(expectedDataLength = " + expectedDataLength + ") != (pixels.length = " + pixels.Length + ")"); @@ -830,8 +713,7 @@ namespace BetterLyrics.WinUI3.Helper var numUsedPixels = 0; var pixelArray = new byte[numRegardedPixels][]; - for (var i = 0; i < pixelCount; i += quality) - { + for (var i = 0; i < pixelCount; i += quality) { var offset = i * ColorDepth; var b = pixels[offset]; var g = pixels[offset + 1]; @@ -839,8 +721,7 @@ namespace BetterLyrics.WinUI3.Helper var a = pixels[offset + 3]; // If pixel is mostly opaque and not white - if (a >= 125 && !(ignoreWhite && r > 250 && g > 250 && b > 250)) - { + if (a >= 125 && !(ignoreWhite && r > 250 && g > 250 && b > 250)) { pixelArray[numUsedPixels] = new[] { r, g, b }; numUsedPixels++; } @@ -864,12 +745,10 @@ namespace BetterLyrics.WinUI3.Helper /// /// if set to true [ignore white]. /// - public async Task GetColor(BitmapDecoder sourceImage, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite) - { + public async Task GetColor(BitmapDecoder sourceImage, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite) { var palette = await GetPalette(sourceImage, 3, quality, ignoreWhite); - var dominantColor = new QuantizedColor(new Color - { + var dominantColor = new QuantizedColor(new Color { A = Convert.ToByte(palette.Average(a => a.Color.A)), R = Convert.ToByte(palette.Average(a => a.Color.R)), G = Convert.ToByte(palette.Average(a => a.Color.G)), @@ -893,29 +772,24 @@ namespace BetterLyrics.WinUI3.Helper /// if set to true [ignore white]. /// /// true - public async Task> GetPalette(BitmapDecoder sourceImage, int colorCount = DefaultColorCount, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite) - { + public async Task> GetPalette(BitmapDecoder sourceImage, int colorCount = DefaultColorCount, int quality = DefaultQuality, bool ignoreWhite = DefaultIgnoreWhite) { var pixelArray = await GetPixelsFast(sourceImage, quality, ignoreWhite); var cmap = GetColorMap(pixelArray, colorCount); - if (cmap != null) - { + if (cmap != null) { var colors = cmap.GeneratePalette(); return colors; } return new List(); } - private async Task GetIntFromPixel(BitmapDecoder decoder) - { + private async Task GetIntFromPixel(BitmapDecoder decoder) { var pixelsData = await decoder.GetPixelDataAsync(); var pixels = pixelsData.DetachPixelData(); return pixels; } - private async Task GetPixelsFast(BitmapDecoder sourceImage, int quality, bool ignoreWhite) - { - if (quality < 1) - { + private async Task GetPixelsFast(BitmapDecoder sourceImage, int quality, bool ignoreWhite) { + if (quality < 1) { quality = DefaultQuality; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DatabaseHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DatabaseHelper.cs deleted file mode 100644 index 7bad089..0000000 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DatabaseHelper.cs +++ /dev/null @@ -1,21 +0,0 @@ -using BetterLyrics.WinUI3.Models; -using SQLite; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BetterLyrics.WinUI3.Helper { - public class DatabaseHelper { - private static SQLiteConnection _database; - - public static SQLiteConnection InitializeDatabase() { - string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MusicMetadataIndex.db"); - _database = new SQLiteConnection(dbPath); - _database.CreateTable(); // Create table if it doesn't exist - return _database; - } - } -} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/VisualHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/VisualHelper.cs index e87aabf..d82e4d8 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/VisualHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/VisualHelper.cs @@ -16,16 +16,16 @@ namespace BetterLyrics.WinUI3.Helper { /// /// public static List FindVisualChildren(DependencyObject depObj) where T : DependencyObject { - List list = new List(); + List list = []; if (depObj != null) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); - if (child != null && child is T) { - list.Add((T)child); + if (child != null && child is T t) { + list.Add(t); } List childItems = FindVisualChildren(child); - if (childItems != null && childItems.Count() > 0) { + if (childItems != null && childItems.Count > 0) { foreach (var item in childItems) { list.Add(item); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs index db5dd00..ca8442e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/MainWindow.xaml.cs @@ -1,26 +1,18 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Messages; using BetterLyrics.WinUI3.Services.Settings; -using BetterLyrics.WinUI3.ViewModels; using BetterLyrics.WinUI3.Views; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.WinUI.Behaviors; using DevWinUI; -using Microsoft.UI; -using Microsoft.UI.Composition; -using Microsoft.UI.Composition.SystemBackdrops; +using Microsoft.Graphics.Canvas.UI.Xaml; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Animation; using Microsoft.UI.Xaml.Navigation; -using WinRT; -using WinRT.Interop; +using System; // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. @@ -33,14 +25,14 @@ namespace BetterLyrics.WinUI3 { private readonly OverlappedPresenter _presenter; - private SettingsService _settingsService; + private readonly SettingsService _settingsService; public static StackedNotificationsBehavior? StackedNotificationsBehavior { get; private set; } public MainWindow() { this.InitializeComponent(); - _settingsService = Ioc.Default.GetService(); + _settingsService = Ioc.Default.GetService()!; RootGrid.RequestedTheme = (ElementTheme)_settingsService.Theme; SystemBackdrop = SystemBackdropHelper.CreateSystemBackdrop((BackdropType)_settingsService.BackdropType); @@ -72,14 +64,9 @@ namespace BetterLyrics.WinUI3 { throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } - private void BackButton_Click(object sender, RoutedEventArgs e) { - if (RootFrame.CanGoBack) { - RootFrame.GoBack(); - } - } - private void CloseButton_Click(object sender, RoutedEventArgs e) { if (RootFrame.CurrentSourcePageType == typeof(MainPage)) { + ((RootFrame.Content as MainPage)!.FindChild("LyricsCanvas") as CanvasAnimatedControl)!.Paused = true; App.Current.Exit(); } else if (RootFrame.CurrentSourcePageType == typeof(SettingsPage)) { App.Current.SettingsWindow!.AppWindow.Hide(); @@ -133,7 +120,7 @@ namespace BetterLyrics.WinUI3 { } private void RootFrame_Navigated(object sender, NavigationEventArgs e) { - AppWindow.Title = Title = App.ResourceLoader.GetString($"{e.SourcePageType.Name}Title"); + AppWindow.Title = Title = App.ResourceLoader!.GetString($"{e.SourcePageType.Name}Title"); } private void AOTButton_Click(object sender, RoutedEventArgs e) { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/SystemBackdropChangedMessage.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/SystemBackdropChangedMessage.cs index 86e3da9..8eba17a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/SystemBackdropChangedMessage.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/SystemBackdropChangedMessage.cs @@ -7,8 +7,6 @@ using System.Text; using System.Threading.Tasks; namespace BetterLyrics.WinUI3.Messages { - public class SystemBackdropChangedMessage : ValueChangedMessage { - public SystemBackdropChangedMessage(BackdropType value) : base(value) { - } + public class SystemBackdropChangedMessage(BackdropType value) : ValueChangedMessage(value) { } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/ThemeChangedMessage.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/ThemeChangedMessage.cs index d573786..dede073 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/ThemeChangedMessage.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Messages/ThemeChangedMessage.cs @@ -7,8 +7,6 @@ using System.Text; using System.Threading.Tasks; namespace BetterLyrics.WinUI3.Messages { - public class ThemeChangedMessage : ValueChangedMessage { - public ThemeChangedMessage(ElementTheme value) : base(value) { - } + public class ThemeChangedMessage(ElementTheme value) : ValueChangedMessage(value) { } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MetadataIndex.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MetadataIndex.cs index 8e31171..6bf7529 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MetadataIndex.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MetadataIndex.cs @@ -1,15 +1,10 @@ using SQLite; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BetterLyrics.WinUI3.Models { public class MetadataIndex { [PrimaryKey] - public string Path { get; set; } - public string Title { get; set; } - public string Artist { get; set; } + public string? Path { get; set; } + public string? Title { get; set; } + public string? Artist { get; set; } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MusicFolder.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MusicFolder.cs deleted file mode 100644 index 53af245..0000000 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/MusicFolder.cs +++ /dev/null @@ -1,20 +0,0 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace BetterLyrics.WinUI3.Models { - public partial class MusicFolder : ObservableObject { - [ObservableProperty] - private string _path; - - public bool IsValid => Directory.Exists(Path); - - public MusicFolder(string path) { - Path = path; - } - } -} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Program.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Program.cs new file mode 100644 index 0000000..8d94a64 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Program.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.UI.Dispatching; +using Microsoft.UI.Xaml; +using Microsoft.Windows.AppLifecycle; + +namespace BetterLyrics.WinUI3 { + public class Program { + [STAThread] + static int Main(string[] args) { + WinRT.ComWrappersSupport.InitializeComWrappers(); + bool isRedirect = DecideRedirection(); + + if (!isRedirect) { + Application.Start((p) => { + var context = new DispatcherQueueSynchronizationContext( + DispatcherQueue.GetForCurrentThread()); + SynchronizationContext.SetSynchronizationContext(context); + _ = new App(); + }); + } + + return 0; + } + + private static bool DecideRedirection() { + bool isRedirect = false; + AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs(); + ExtendedActivationKind kind = args.Kind; + AppInstance keyInstance = AppInstance.FindOrRegisterForKey(Helper.AppInfo.AppName); + + if (keyInstance.IsCurrent) { + keyInstance.Activated += OnActivated; + } else { + isRedirect = true; + RedirectActivationTo(args, keyInstance); + } + + return isRedirect; + } + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern IntPtr CreateEvent( + IntPtr lpEventAttributes, bool bManualReset, + bool bInitialState, string lpName); + + [DllImport("kernel32.dll")] + private static extern bool SetEvent(IntPtr hEvent); + + [DllImport("ole32.dll")] + private static extern uint CoWaitForMultipleObjects( + uint dwFlags, uint dwMilliseconds, ulong nHandles, + IntPtr[] pHandles, out uint dwIndex); + + [DllImport("user32.dll")] + static extern bool SetForegroundWindow(IntPtr hWnd); + + private static IntPtr redirectEventHandle = IntPtr.Zero; + + // Do the redirection on another thread, and use a non-blocking + // wait method to wait for the redirection to complete. + public static void RedirectActivationTo(AppActivationArguments args, + AppInstance keyInstance) { + redirectEventHandle = CreateEvent(IntPtr.Zero, true, false, null); + Task.Run(() => { + keyInstance.RedirectActivationToAsync(args).AsTask().Wait(); + SetEvent(redirectEventHandle); + }); + + uint CWMO_DEFAULT = 0; + uint INFINITE = 0xFFFFFFFF; + _ = CoWaitForMultipleObjects( + CWMO_DEFAULT, INFINITE, 1, + [redirectEventHandle], out uint handleIndex); + + // Bring the window to the foreground + Process process = Process.GetProcessById((int)keyInstance.ProcessId); + SetForegroundWindow(process.MainWindowHandle); + } + + private static void OnActivated(object sender, AppActivationArguments args) { + ExtendedActivationKind kind = args.Kind; + } + + } +} \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Database/DatabaseService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Database/DatabaseService.cs index 93cb845..22eecf0 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Database/DatabaseService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Database/DatabaseService.cs @@ -19,20 +19,18 @@ namespace BetterLyrics.WinUI3.Services.Database { private readonly CharsetDetector _charsetDetector = new(); public DatabaseService() { - string dbPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "MusicMetadataIndex.db" - ); - _connection = new SQLiteConnection(dbPath); - _connection.CreateTable(); + _connection = new SQLiteConnection(Helper.AppInfo.DatabasePath); + if (_connection.GetTableInfo("MetadataIndex").Count == 0) { + _connection.CreateTable(); + } } - public async Task RebuildMusicMetadataIndexDatabaseAsync(IList musicFolders) { + public async Task RebuildMusicMetadataIndexDatabaseAsync(IList paths) { await Task.Run(() => { _connection.DeleteAll(); - foreach (var localMusicFolder in musicFolders) { - if (localMusicFolder.IsValid) { - foreach (var file in Directory.GetFiles(localMusicFolder.Path)) { + foreach (var path in paths) { + if (Directory.Exists(path)) { + foreach (var file in Directory.GetFiles(path)) { var fileExtension = Path.GetExtension(file); var track = new Track(file); _connection.Insert(new MetadataIndex { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs index 34dd146..ce7b7bb 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/Settings/SettingsService.cs @@ -1,29 +1,16 @@ -using ATL; -using BetterLyrics.WinUI3.Helper; -using BetterLyrics.WinUI3.Messages; -using BetterLyrics.WinUI3.Models; -using BetterLyrics.WinUI3.Services.Database; +using BetterLyrics.WinUI3.Messages; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using DevWinUI; -using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls.Primitives; -using Microsoft.UI.Xaml.Media; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Data.Common; -using System.Diagnostics; -using System.IO; using System.Linq; using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; using Windows.Globalization; using Windows.Storage; -using Windows.System; namespace BetterLyrics.WinUI3.Services.Settings { public partial class SettingsService : ObservableObject { @@ -34,7 +21,7 @@ namespace BetterLyrics.WinUI3.Services.Settings { } [ObservableProperty] - private bool _isRebuildingLyricsIndexDatabase; + private bool _isRebuildingLyricsIndexDatabase = false; // Theme public int Theme { @@ -46,19 +33,10 @@ namespace BetterLyrics.WinUI3.Services.Settings { } // Music - private ObservableCollection _musicLibraries; + private ObservableCollection _musicLibraries; - public ObservableCollection MusicLibraries { + public ObservableCollection MusicLibraries { get { - if (_musicLibraries == null) { - var list = JsonConvert.DeserializeObject>( - Get(SettingsKeys.MusicLibraries, SettingsDefaultValues.MusicLibraries) - ); - - _musicLibraries = new ObservableCollection(list); - _musicLibraries.CollectionChanged += (_, _) => SaveMusicLibraries(); - } - return _musicLibraries; } set { @@ -157,24 +135,26 @@ namespace BetterLyrics.WinUI3.Services.Settings { set => Set(SettingsKeys.IsLyricsDynamicGlowEffectEnabled, value); } - private readonly ApplicationDataContainer _localSettings; - private readonly DatabaseService _databaseService; - public SettingsService(DatabaseService databaseService) { + public SettingsService() { _localSettings = ApplicationData.Current.LocalSettings; - _databaseService = databaseService; + + _musicLibraries = [.. JsonConvert.DeserializeObject>( + Get(SettingsKeys.MusicLibraries, SettingsDefaultValues.MusicLibraries)!)!]; + + _musicLibraries.CollectionChanged += (_, _) => SaveMusicLibraries(); } - private T Get(string key, T defaultValue = default) { - if (_localSettings.Values.TryGetValue(key, out object value)) { + private T? Get(string key, T? defaultValue = default) { + if (_localSettings.Values.TryGetValue(key, out object? value)) { return (T)Convert.ChangeType(value, typeof(T)); } return defaultValue; } - private void Set(string key, T value, [CallerMemberName] string propertyName = null) { + private void Set(string key, T value, [CallerMemberName] string? propertyName = null) { _localSettings.Values[key] = value; OnPropertyChanged(propertyName); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw index 51d29da..ee989b9 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw @@ -126,6 +126,9 @@ Open in file explorer + + Open in file explorer + Remove from app @@ -322,7 +325,7 @@ Setup lyrics database now - Hover on the bottom left corner and then click to open settings page + Hover on the bottom left corner and then click to open settings page Hover on the bottom area to show it @@ -339,4 +342,16 @@ No music playing now + + Developer options + + + Play test music + + + Play using system player + + + Log + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw index 3872a6b..72c633c 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw @@ -126,6 +126,9 @@ 在文件资源管理器中打开 + + 在文件资源管理器中打开 + 从应用中移除 @@ -339,4 +342,16 @@ 当前没有正在播放的音乐 + + 开发者选项 + + + 播放测试音乐 + + + 使用系统播放器播放 + + + 日志 + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw index a4cd688..84dea11 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw @@ -126,6 +126,9 @@ 在檔案總管中開啟 + + 在檔案總管中開啟 + 從應用程式中移除 @@ -339,4 +342,16 @@ 目前沒有正在播放的音樂 + + 開發者選項 + + + 播放測試音樂 + + + 使用系統播放器播放 + + + 紀錄 + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/MainViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/MainViewModel.cs index 13ec1f7..1461dd4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/MainViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/MainViewModel.cs @@ -1,6 +1,7 @@ using ATL; using BetterLyrics.WinUI3.Models; using BetterLyrics.WinUI3.Services.Database; +using BetterLyrics.WinUI3.Services.Settings; using CommunityToolkit.Mvvm.ComponentModel; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.UI.Xaml; @@ -17,7 +18,7 @@ using Windows.UI; using static ATL.LyricsInfo; namespace BetterLyrics.WinUI3.ViewModels { - public partial class MainViewModel : ObservableObject { + public partial class MainViewModel(DatabaseService databaseService) : ObservableObject { [ObservableProperty] private bool _isAnyMusicSessionExisted = false; @@ -46,17 +47,18 @@ namespace BetterLyrics.WinUI3.ViewModels { [ObservableProperty] private bool _lyricsExisted = false; - private Helper.ColorThief _colorThief = new(); + private readonly Helper.ColorThief _colorThief = new(); - private readonly DatabaseService _databaseService; - - public MainViewModel(DatabaseService databaseService) { - _databaseService = databaseService; - } + private readonly DatabaseService _databaseService = databaseService; public List GetLyrics(Track? track) { List result = []; - var lyricsPhrases = track?.Lyrics.SynchronizedLyrics; + + if (track == null) { + return result; + } + + var lyricsPhrases = track.Lyrics.SynchronizedLyrics; if (lyricsPhrases?.Count > 0) { if (lyricsPhrases[0].TimestampMs > 0) { @@ -100,7 +102,7 @@ namespace BetterLyrics.WinUI3.ViewModels { } - public async Task<(List, SoftwareBitmap?, uint, uint)> SetSongInfoAsync(GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProps, ICanvasAnimatedControl control) { + public async Task<(List, SoftwareBitmap?, uint, uint)> SetSongInfoAsync(GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProps) { SoftwareBitmap? coverSoftwareBitmap = null; uint coverImagePixelWidth = 0; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs index c0f69e2..acbfb79 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsViewModel.cs @@ -2,37 +2,26 @@ using BetterLyrics.WinUI3.Services.Database; using BetterLyrics.WinUI3.Services.Settings; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; -using Microsoft.UI.Xaml; using System; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; -using Windows.ApplicationModel; using Windows.ApplicationModel.Core; using Windows.Storage.Pickers; using Windows.System; using WinRT.Interop; namespace BetterLyrics.WinUI3.ViewModels { - public partial class SettingsViewModel : ObservableObject { + public partial class SettingsViewModel(DatabaseService databaseService, SettingsService settingsService) : ObservableObject { - private readonly DatabaseService _databaseService; + private readonly DatabaseService _databaseService = databaseService; [ObservableProperty] - private SettingsService _settingsService; + private SettingsService _settingsService = settingsService; [ObservableProperty] - private string _version; - - public SettingsViewModel(DatabaseService databaseService, SettingsService settingsService) { - _databaseService = databaseService; - _settingsService = settingsService; - - var version = Package.Current.Id.Version; - Version = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}"; - } + private string _version = Helper.AppInfo.AppVersion; [RelayCommand] private async Task RebuildLyricsIndexDatabaseAsync() { @@ -41,14 +30,13 @@ namespace BetterLyrics.WinUI3.ViewModels { SettingsService.IsRebuildingLyricsIndexDatabase = false; } - [RelayCommand] - private async Task RemoveFolderAsync(MusicFolder musicFolder) { - SettingsService.MusicLibraries.Remove(musicFolder); + public async Task RemoveFolderAsync(string path) { + SettingsService.MusicLibraries.Remove(path); await RebuildLyricsIndexDatabaseAsync(); } [RelayCommand] - private async Task AddFolderAsync() { + private async Task SelectAndAddFolderAsync() { var picker = new FolderPicker(); picker.FileTypeFilter.Add("*"); @@ -58,35 +46,44 @@ namespace BetterLyrics.WinUI3.ViewModels { var folder = await picker.PickSingleFolderAsync(); + App.Current.SettingsWindow!.AppWindow.MoveInZOrderAtTop(); + if (folder != null) { - string path = folder.Path; - bool existed = SettingsService.MusicLibraries.Count((x) => x.Path == path) > 0; - if (existed) { - MainWindow.StackedNotificationsBehavior?.Show(App.ResourceLoader.GetString("SettingsPagePathExistedInfo"), 3900); - } else { - SettingsService.MusicLibraries.Add(new MusicFolder(path)); - await RebuildLyricsIndexDatabaseAsync(); - } + await AddFolderAsync(folder.Path); } } - [RelayCommand] - private async Task LaunchProjectGitHubPageAsync() { - await Launcher.LaunchUriAsync(new Uri("https://github.com/jayfunc/BetterLyrics")); + private async Task AddFolderAsync(string path) { + bool existed = SettingsService.MusicLibraries.Any((x) => x == path); + if (existed) { + MainWindow.StackedNotificationsBehavior?.Show(App.ResourceLoader!.GetString("SettingsPagePathExistedInfo"), + Helper.AnimationHelper.StackedNotificationsShowingDuration); + } else { + SettingsService.MusicLibraries.Add(path); + await RebuildLyricsIndexDatabaseAsync(); + } } [RelayCommand] - private void OpenFolderInFileExplorer(MusicFolder musicFolder) { + private static async Task LaunchProjectGitHubPageAsync() { + await Launcher.LaunchUriAsync(new Uri(Helper.AppInfo.GithubUrl)); + } + + private static void OpenFolderInFileExplorer(string path) { Process.Start(new ProcessStartInfo { FileName = "explorer.exe", - Arguments = musicFolder.Path, + Arguments = path, UseShellExecute = true }); } + public static void OpenMusicFolder(string path) { + OpenFolderInFileExplorer(path); + } + [RelayCommand] - private void RestartApp() { + private static void RestartApp() { // The restart will be executed immediately. AppRestartFailureReason failureReason = Microsoft.Windows.AppLifecycle.AppInstance.Restart(""); @@ -104,5 +101,19 @@ namespace BetterLyrics.WinUI3.ViewModels { } } + [RelayCommand] + private async Task PlayTestingMusicTask() { + await AddFolderAsync(Helper.AppInfo.AssetsFolder); + Process.Start(new ProcessStartInfo { + FileName = Helper.AppInfo.TestMusicPath, + UseShellExecute = true + }); + } + + [RelayCommand] + private static void OpenLogFolder() { + OpenFolderInFileExplorer(Helper.AppInfo.LogDirectory); + } + } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml index 17510da..6bcedc7 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/MainPage.xaml @@ -32,6 +32,7 @@ @@ -111,32 +112,40 @@ - + Grid.ColumnSpan="3"> + + + + + + + + + + - + - + @@ -157,179 +166,142 @@ - + x:Name="CoverArea" + Grid.Row="1" + SizeChanged="CoverArea_SizeChanged"> - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - + + + + + + + + + + + - - + + - + + - + - + - - + + - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + - - - - - - - - + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + (MainViewModel)DataContext; - private SettingsService _settingsService; + private readonly SettingsService _settingsService; private List _lyricsLines = []; @@ -48,29 +50,27 @@ namespace BetterLyrics.WinUI3.Views { private float _coverBitmapRotateAngle = 0f; private float _coverScaleFactor = 1; - private float _coverRotateSpeed = 0.003f; + private readonly float _coverRotateSpeed = 0.003f; private float _lyricsGlowEffectAngle = 0f; - private float _lyricsGlowEffectSpeed = 0.01f; + private readonly float _lyricsGlowEffectSpeed = 0.01f; - private float _lyricsGlowEffectMinBlurAmount = 0f; - private float _lyricsGlowEffectMaxBlurAmount = 6f; + private readonly float _lyricsGlowEffectMinBlurAmount = 0f; + private readonly float _lyricsGlowEffectMaxBlurAmount = 6f; - private int _animationDurationMs = 200; - - private DispatcherQueueTimer _queueTimer; + private readonly DispatcherQueueTimer _queueTimer; private TimeSpan _currentTime = TimeSpan.Zero; - private float _defaultOpacity = 0.3f; - private float _highlightedOpacity = 1.0f; + private readonly float _defaultOpacity = 0.3f; + private readonly float _highlightedOpacity = 1.0f; - private float _defaultScale = 0.95f; - private float _highlightedScale = 1.0f; + private readonly float _defaultScale = 0.95f; + private readonly float _highlightedScale = 1.0f; - private int _lineEnteringDurationMs = 800; - private int _lineExitingDurationMs = 800; - private int _lineScrollDurationMs = 800; + private readonly int _lineEnteringDurationMs = 800; + private readonly int _lineExitingDurationMs = 800; + private readonly int _lineScrollDurationMs = 800; private float _lastTotalYScroll = 0.0f; private float _totalYScroll = 0.0f; @@ -78,7 +78,7 @@ namespace BetterLyrics.WinUI3.Views { private double _lyricsAreaWidth = 0.0f; private double _lyricsAreaHeight = 0.0f; - private double _lyricsCanvasRightMargin = 36; + private readonly double _lyricsCanvasRightMargin = 36; private double _lyricsCanvasLeftMargin = 0; private double _lyricsCanvasMaxTextWidth = 0; @@ -86,7 +86,6 @@ namespace BetterLyrics.WinUI3.Views { private int _endVisibleLineIndex = -1; private bool _forceToScroll = false; - private bool _isRelayoutLyricsNeeded = false; private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); @@ -95,9 +94,13 @@ namespace BetterLyrics.WinUI3.Views { private Color _lyricsColor; + private readonly ILogger _logger; + public MainPage() { this.InitializeComponent(); + _logger = Ioc.Default.GetService>()!; + SetLyricsColor(); _settingsService = Ioc.Default.GetService()!; @@ -134,6 +137,7 @@ namespace BetterLyrics.WinUI3.Views { } break; case nameof(_settingsService.Theme): + await Task.Delay(1); SetLyricsColor(); break; default: @@ -152,7 +156,7 @@ namespace BetterLyrics.WinUI3.Views { } private void SetLyricsColor() { - _lyricsColor = ((SolidColorBrush)TitleTextBlock.Foreground).Color; + _lyricsColor = ((SolidColorBrush)LyricsCanvas.Foreground).Color; } private async void InitMediaManager() { @@ -163,14 +167,14 @@ namespace BetterLyrics.WinUI3.Views { SessionManager_CurrentSessionChanged(_sessionManager, null); } - private void CurrentSession_TimelinePropertiesChanged(GlobalSystemMediaTransportControlsSession sender, TimelinePropertiesChangedEventArgs args) { + private void CurrentSession_TimelinePropertiesChanged(GlobalSystemMediaTransportControlsSession? sender, TimelinePropertiesChangedEventArgs? args) { if (sender == null) { _currentTime = TimeSpan.Zero; return; } _currentTime = sender.GetTimelineProperties().Position; - // Debug.WriteLine(_currentTime); + // _logger.LogDebug(_currentTime); } /// @@ -178,7 +182,7 @@ namespace BetterLyrics.WinUI3.Views { /// /// /// - private void CurrentSession_PlaybackInfoChanged(GlobalSystemMediaTransportControlsSession sender, PlaybackInfoChangedEventArgs args) { + private void CurrentSession_PlaybackInfoChanged(GlobalSystemMediaTransportControlsSession? sender, PlaybackInfoChangedEventArgs? args) { _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () => { if (sender == null) { LyricsCanvas.Paused = true; @@ -186,7 +190,7 @@ namespace BetterLyrics.WinUI3.Views { } var playbackState = sender.GetPlaybackInfo().PlaybackStatus; - Debug.WriteLine(playbackState); + _logger.LogDebug(playbackState.ToString()); switch (playbackState) { case GlobalSystemMediaTransportControlsSessionPlaybackStatus.Closed: @@ -214,12 +218,12 @@ namespace BetterLyrics.WinUI3.Views { } - private void SessionManager_SessionsChanged(GlobalSystemMediaTransportControlsSessionManager sender, SessionsChangedEventArgs args) { - Debug.WriteLine("SessionManager_SessionsChanged"); + private void SessionManager_SessionsChanged(GlobalSystemMediaTransportControlsSessionManager sender, SessionsChangedEventArgs? args) { + _logger.LogDebug("SessionManager_SessionsChanged"); } - private void SessionManager_CurrentSessionChanged(GlobalSystemMediaTransportControlsSessionManager sender, CurrentSessionChangedEventArgs args) { - Debug.WriteLine("SessionManager_CurrentSessionChanged"); + private void SessionManager_CurrentSessionChanged(GlobalSystemMediaTransportControlsSessionManager sender, CurrentSessionChangedEventArgs? args) { + _logger.LogDebug("SessionManager_CurrentSessionChanged"); // Unregister events associated with the previous session if (_currentSession != null) { _currentSession.MediaPropertiesChanged -= CurrentSession_MediaPropertiesChanged; @@ -244,9 +248,9 @@ namespace BetterLyrics.WinUI3.Views { /// /// /// - private void CurrentSession_MediaPropertiesChanged(GlobalSystemMediaTransportControlsSession sender, MediaPropertiesChangedEventArgs args) { + private void CurrentSession_MediaPropertiesChanged(GlobalSystemMediaTransportControlsSession? sender, MediaPropertiesChangedEventArgs? args) { _queueTimer.Debounce(() => { - Debug.WriteLine("CurrentSession_MediaPropertiesChanged"); + _logger.LogDebug("CurrentSession_MediaPropertiesChanged"); _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.High, async () => { GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProps = null; @@ -261,13 +265,14 @@ namespace BetterLyrics.WinUI3.Views { ViewModel.IsAnyMusicSessionExisted = _currentSession != null; ViewModel.AboutToUpdateUI = true; - await Task.Delay(_animationDurationMs); + await Task.Delay(AnimationHelper.StoryboardDefaultDuration); - (_lyricsLines, _coverSoftwareBitmap, _coverImagePixelWidth, _coverImagePixelHeight) = await ViewModel.SetSongInfoAsync(mediaProps, LyricsCanvas); + (_lyricsLines, _coverSoftwareBitmap, _coverImagePixelWidth, _coverImagePixelHeight) = await ViewModel.SetSongInfoAsync(mediaProps); // Force to show lyrics and scroll to current line even if the music is not playing LyricsCanvas.Paused = false; await ForceToScrollToCurrentPlayingLineAsync(); + await Task.Delay(1); // Detect and recover the music state CurrentSession_PlaybackInfoChanged(_currentSession, null); CurrentSession_TimelinePropertiesChanged(_currentSession, null); @@ -275,17 +280,17 @@ namespace BetterLyrics.WinUI3.Views { ViewModel.AboutToUpdateUI = false; if (_lyricsLines.Count == 0) { - Grid.SetColumnSpan(SongInfoStackPanel, 3); + Grid.SetColumnSpan(SongInfoInnerGrid, 3); } else { - Grid.SetColumnSpan(SongInfoStackPanel, 1); + Grid.SetColumnSpan(SongInfoInnerGrid, 1); } }); - }, TimeSpan.FromMilliseconds(200)); + }, TimeSpan.FromMilliseconds(AnimationHelper.DebounceDefaultDuration)); } - private async void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) { + private async void RootGrid_SizeChanged(object? sender, SizeChangedEventArgs? e) { //_queueTimer.Debounce(async () => { _lyricsAreaHeight = LyricsGrid.ActualHeight; @@ -315,7 +320,7 @@ namespace BetterLyrics.WinUI3.Views { // Draw (dynamic) cover image as the very first layer if (_settingsService.IsCoverOverlayEnabled && _coverSoftwareBitmap != null) { - DrawCoverImage(sender, ds, _settingsService.IsDynamicCoverOverlay); + DrawCoverImage(sender, ds); } // Lyrics only layer @@ -450,7 +455,7 @@ namespace BetterLyrics.WinUI3.Views { // Scale ds.Transform = Matrix3x2.CreateScale(line.Scale, new Vector2(centerX, centerY)) * Matrix3x2.CreateTranslation(0, _totalYScroll); - //Debug.WriteLine(_totalYScroll); + // _logger.LogDebug(_totalYScroll); ds.DrawTextLayout(line.TextLayout, position, Colors.Transparent); @@ -460,7 +465,7 @@ namespace BetterLyrics.WinUI3.Views { } - private void DrawCoverImage(ICanvasAnimatedControl control, CanvasDrawingSession ds, bool dynamic) { + private void DrawCoverImage(ICanvasAnimatedControl control, CanvasDrawingSession ds) { ds.Transform = Matrix3x2.CreateRotation(_coverBitmapRotateAngle, control.Size.ToVector2() * 0.5f); @@ -518,7 +523,7 @@ namespace BetterLyrics.WinUI3.Views { } - if (_lyricsLines.LastOrDefault()?.TextLayout == null || _isRelayoutLyricsNeeded) { + if (_lyricsLines.LastOrDefault()?.TextLayout == null) { LayoutLyrics(); } @@ -542,7 +547,7 @@ namespace BetterLyrics.WinUI3.Views { } private Tuple GetVisibleLyricsLineIndexBoundaries() { - //Debug.WriteLine($"{_startVisibleLineIndex} {_endVisibleLineIndex}"); + // _logger.LogDebug($"{_startVisibleLineIndex} {_endVisibleLineIndex}"); return new Tuple(_startVisibleLineIndex, _endVisibleLineIndex); } @@ -725,11 +730,20 @@ namespace BetterLyrics.WinUI3.Views { } private void SettingsButton_Click(object sender, RoutedEventArgs e) { - if (App.Current.SettingsWindow == null) { - App.Current.SettingsWindow = new MainWindow(); - App.Current.SettingsWindow!.Navigate(typeof(SettingsPage)); + if (App.Current.SettingsWindow is null) { + var settingsWindow = new MainWindow(); + settingsWindow.Navigate(typeof(SettingsPage)); + App.Current.SettingsWindow = settingsWindow; } - App.Current.SettingsWindow.AppWindow.Show(); + + var appWindow = App.Current.SettingsWindow.AppWindow; + + if (appWindow.Presenter is OverlappedPresenter presenter) { + presenter.Restore(); + } + + appWindow.Show(); + appWindow.MoveInZOrderAtTop(); } private void WelcomeTeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args) { @@ -751,5 +765,9 @@ namespace BetterLyrics.WinUI3.Views { private void InitDatabaseTeachingTip_Closed(TeachingTip sender, TeachingTipClosedEventArgs args) { _settingsService.IsFirstRun = false; } + + private void CoverArea_SizeChanged(object sender, SizeChangedEventArgs e) { + CoverImageGrid.Width = CoverImageGrid.Height = Math.Min(CoverArea.ActualWidth, CoverArea.ActualHeight); + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml index d072322..20453d3 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml @@ -10,7 +10,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ui="using:CommunityToolkit.WinUI" xmlns:vm="using:BetterLyrics.WinUI3.ViewModels" - x:Name="RootPage" NavigationCacheMode="Required" mc:Ignorable="d"> @@ -29,54 +28,21 @@ - - - - - - - - - - - - - - - - - - - - - + + Click="SettingsPageOpenPathButton_Click" + Tag="{Binding}" /> + Click="SettingsPageRemovePathButton_Click" + Tag="{Binding}" /> @@ -110,11 +76,8 @@ - -