From 3b1e0389aa2d3edb22cfcc59e3a2254fa2528a9c Mon Sep 17 00:00:00 2001 From: Zhe Fang Date: Sun, 13 Jul 2025 20:32:10 -0400 Subject: [PATCH] fix #13 , fix #20 , fix #21 , fix #24 --- .../Package.appxmanifest | 2 +- .../BetterLyrics.WinUI3/App.xaml | 4 + .../BetterLyrics.WinUI3/App.xaml.cs | 2 + .../BetterLyrics.WinUI3.csproj | 233 +++++++++--------- .../Helper/DesktopModeHelper.cs | 59 +++++ .../Helper/GlobalHotKeyHelper.cs | 46 ++++ .../Helper/LanguageHelper.cs | 8 + .../Helper/LyricsParser.cs | 28 +-- .../Helper/SystemVolumeHelper.cs | 74 ++++++ .../Models/{CharTiming.cs => LyricsChar.cs} | 4 +- .../BetterLyrics.WinUI3/Models/LyricsData.cs | 24 +- .../BetterLyrics.WinUI3/Models/LyricsLine.cs | 2 +- .../Services/ILyricsSearchService.cs | 2 +- .../Services/IPlaybackService.cs | 7 + .../Services/ISettingsService.cs | 5 + .../Services/LyricsSearchService.cs | 19 +- .../Services/PlaybackService.cs | 36 +++ .../Services/SettingsService.cs | 40 ++- .../Services/TranslateService.cs | 10 +- .../Strings/en-US/Resources.resw | 18 +- .../Strings/ja-JP/Resources.resw | 18 +- .../Strings/ko-KR/Resources.resw | 18 +- .../Strings/zh-CN/Resources.resw | 18 +- .../Strings/zh-TW/Resources.resw | 18 +- .../ViewModels/LyricsPageViewModel.cs | 85 ++++++- .../LyricsRendererViewModel.Ctor.cs | 2 + .../LyricsRendererViewModel.Draw.cs | 116 +++++---- .../LyricsRendererViewModel.Messages.cs | 4 + .../LyricsRendererViewModel.Update.cs | 5 +- .../ViewModels/LyricsRendererViewModel.cs | 69 +++++- .../ViewModels/LyricsWindowViewModel.cs | 52 +++- .../ViewModels/SettingsPageViewModel.cs | 25 +- .../BetterLyrics.WinUI3/Views/LyricsPage.xaml | 183 +++++++++++++- .../Views/LyricsPage.xaml.cs | 2 +- .../Views/LyricsWindow.xaml | 22 +- .../Views/LyricsWindow.xaml.cs | 39 ++- .../Views/SettingsPage.xaml | 43 +++- .../Views/SettingsPage.xaml.cs | 3 +- 38 files changed, 1076 insertions(+), 269 deletions(-) create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/GlobalHotKeyHelper.cs create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/SystemVolumeHelper.cs rename BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/{CharTiming.cs => LyricsChar.cs} (80%) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest index 9925b8f..15b0eb3 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="1.0.12.0" /> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml index 737ec28..1f411d7 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml @@ -93,6 +93,10 @@ + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs index 3e90ed8..4b96992 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/App.xaml.cs @@ -59,6 +59,7 @@ namespace BetterLyrics.WinUI3 var lyricsWindow = WindowHelper.GetWindowByWindowType(); if (lyricsWindow == null) return; + lyricsWindow.ViewModel.InitLockHotKey(); lyricsWindow.AutoSelectLyricsMode(); } @@ -84,6 +85,7 @@ namespace BetterLyrics.WinUI3 .AddSingleton() .AddSingleton() .AddSingleton() + // Manager // ViewModels .AddSingleton() .AddSingleton() diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj index 5b23554..af27b0e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj @@ -1,118 +1,119 @@  - - WinExe - net8.0-windows10.0.26100.0 - 10.0.19041.0 - BetterLyrics.WinUI3 - x86;x64;ARM64 - win-x86;win-x64;win-arm64 - true - enable - preview - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - False - True - False - True - 10.0.19041.0 - - - $(DefineConstants) - app.manifest - Logo.ico - true - True - True - False - False - False - True - SettingsVersion - AssemblyVersion - AssemblyVersion.None.None - 2025.6.0 - 2025.6.18.0110 - 2025.6.18.0110 - + + WinExe + net8.0-windows10.0.26100.0 + 10.0.19041.0 + BetterLyrics.WinUI3 + x86;x64;ARM64 + win-x86;win-x64;win-arm64 + true + enable + preview + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + False + True + False + True + 10.0.19041.0 + + + $(DefineConstants) + app.manifest + Logo.ico + true + True + True + False + False + False + True + SettingsVersion + AssemblyVersion + AssemblyVersion.None.None + 2025.6.0 + 2025.6.18.0110 + 2025.6.18.0110 + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs index 6d6855b..ff918fd 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/DesktopModeHelper.cs @@ -5,6 +5,8 @@ using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using System; using System.Collections.Generic; +using System.Drawing; +using System.Linq; using System.Runtime.InteropServices; using Vanara.PInvoke; using WinRT.Interop; @@ -17,8 +19,10 @@ namespace BetterLyrics.WinUI3.Helper private static readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService(); private static readonly Dictionary _originalTopmostStates = []; + private static readonly Dictionary _oldWndProcs = new(); private static readonly Dictionary _originalWindowBounds = []; private static readonly Dictionary _originalWindowStyles = []; + private static List _interactiveRects = new(); private delegate nint WndProcDelegate(nint hWnd, uint msg, nint wParam, nint lParam); @@ -90,6 +94,7 @@ namespace BetterLyrics.WinUI3.Helper { IntPtr hwnd = WindowNative.GetWindowHandle(window); int exStyle = User32.GetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE); + if (enable) { // ¼ÇÒäÔ­Ñùʽ @@ -98,6 +103,16 @@ namespace BetterLyrics.WinUI3.Helper window.ToggleWindowStyle(true, WindowStyle.Popup | WindowStyle.Visible); User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWL_EXSTYLE, exStyle | (int)User32.WindowStylesEx.WS_EX_TRANSPARENT | (int)User32.WindowStylesEx.WS_EX_LAYERED); + + //// °²×°×Ô¶¨ÒåWndProc + //if (!_oldWndProcs.ContainsKey(hwnd)) + //{ + // nint newWndProc = Marshal.GetFunctionPointerForDelegate((WndProcDelegate)((hWnd, msg, wParam, lParam) => + // CustomWndProc(hWnd, msg, wParam, lParam, hwnd) + // )); + // nint oldWndProc = User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWLP_WNDPROC, newWndProc); + // _oldWndProcs[hwnd] = oldWndProc; + //} } else { @@ -108,7 +123,51 @@ namespace BetterLyrics.WinUI3.Helper window.SetWindowStyle(style); _originalWindowStyles.Remove(hwnd); } + + //// »Ö¸´Ô­WndProc + //if (_oldWndProcs.TryGetValue(hwnd, out var oldWndProc)) + //{ + // User32.SetWindowLong(hwnd, User32.WindowLongFlags.GWLP_WNDPROC, oldWndProc); + // _oldWndProcs.Remove(hwnd); + //} } } + + private static nint CustomWndProc(nint hWnd, uint msg, nint wParam, nint lParam, IntPtr hwnd) + { + const int WM_NCHITTEST = 0x84; + const int HTCLIENT = 1; + const int HTTRANSPARENT = -1; + + if (msg == WM_NCHITTEST) + { + int x = (short)(lParam.ToInt32() & 0xFFFF); + int y = (short)((lParam.ToInt32() >> 16) & 0xFFFF); + + // תΪ´°¿Ú×ø±ê + POINT pt = new() { x = x, y = y }; + User32.ScreenToClient(hWnd, ref pt); + + foreach (var rect in _interactiveRects) + { + if (rect.Contains(pt.x, pt.y)) + return HTCLIENT; + } + return HTTRANSPARENT; + } + + // µ÷ÓÃÔ­WndProc + if (_oldWndProcs.TryGetValue(hwnd, out var oldWndProc)) + { + return User32.CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam); + } + return User32.DefWindowProc(hWnd, msg, wParam, lParam); + } + + public static void SetInteractiveRects(IEnumerable rects) + { + _interactiveRects = rects.ToList(); + } + } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/GlobalHotKeyHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/GlobalHotKeyHelper.cs new file mode 100644 index 0000000..fc828c7 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/GlobalHotKeyHelper.cs @@ -0,0 +1,46 @@ +using Microsoft.UI.Xaml; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Vanara.PInvoke; +using Windows.System; +using WinRT.Interop; + +namespace BetterLyrics.WinUI3.Helper +{ + public class GlobalHotKeyHelper + { + private static Dictionary _hotKeyActions = []; + private static int _nextId = 0; + + public static void RegisterHotKey(Window window, User32.HotKeyModifiers modifiers, uint key, Action action) + { + HWND hwnd = WindowNative.GetWindowHandle(window); + int id = _nextId++; + User32.RegisterHotKey(hwnd, id, modifiers, key); + _hotKeyActions[id] = action; + } + + public static void UnregisterAllHotKeys(Window window) + { + HWND hwnd = WindowNative.GetWindowHandle(window); + foreach (var id in _hotKeyActions.Keys.ToList()) + { + User32.UnregisterHotKey(hwnd, id); + _hotKeyActions.Remove(id); + } + } + + public static bool TryInvokeAction(int id) + { + if (_hotKeyActions.TryGetValue(id, out var action)) + { + action?.Invoke(); + return true; + } + return false; + } + } +} diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs index 591546a..11c0a7c 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LanguageHelper.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using Windows.Globalization; namespace BetterLyrics.WinUI3.Services { @@ -113,5 +114,12 @@ namespace BetterLyrics.WinUI3.Services { return SupportedTargetLanguages[_settingsService.SelectedTargetLanguageIndex].Code; } + + public static int GetDefaultTargetLanguageIndex() + { + int found = SupportedTargetLanguages.FindIndex(x => ApplicationLanguages.Languages.FirstOrDefault()?.Contains(x.Code) == true); + if (found == -1) found = 7; // 默认使用英语 + return found; + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs index 772d6c3..ba0f3cd 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/LyricsParser.cs @@ -130,7 +130,7 @@ namespace BetterLyrics.WinUI3.Helper StartMs = start, EndMs = 0, // ç¨åŽç»Ÿä¸€ä¿®æ­£ OriginalText = text, - CharTimings = [], + LyricsChars = [], }; if (syllables != null && syllables.Count > 0) { @@ -139,8 +139,8 @@ namespace BetterLyrics.WinUI3.Helper { var (charStart, charText) = syllables[j]; int startIndex = currentIndex; - line.CharTimings.Add( - new CharTiming + line.LyricsChars.Add( + new LyricsChar { StartMs = charStart, EndMs = 0, // Fixed later @@ -197,13 +197,13 @@ namespace BetterLyrics.WinUI3.Helper originalText = string.Concat(originalTextSpans.Select(s => s.Value)); } - var originalCharTimings = new List(); + var originalCharTimings = new List(); int originalStartIndex = 0; foreach (var span in originalTextSpans) { string? sBegin = span.Attribute("begin")?.Value; int sStartMs = ParseTtmlTime(sBegin); - originalCharTimings.Add(new CharTiming + originalCharTimings.Add(new LyricsChar { StartMs = sStartMs, EndMs = 0, @@ -220,18 +220,18 @@ namespace BetterLyrics.WinUI3.Helper StartMs = pStartMs, EndMs = 0, OriginalText = originalText, - CharTimings = originalCharTimings, + LyricsChars = originalCharTimings, }); // 翻译 string translationText = string.Concat(translationTextSpans.Select(s => s.Value)); - var translationCharTimings = new List(); + var translationCharTimings = new List(); int translationStartIndex = 0; foreach (var span in translationTextSpans) { string? sBegin = span.Attribute("begin")?.Value; int sStartMs = ParseTtmlTime(sBegin); - translationCharTimings.Add(new CharTiming + translationCharTimings.Add(new LyricsChar { StartMs = sStartMs, EndMs = 0, @@ -247,7 +247,7 @@ namespace BetterLyrics.WinUI3.Helper StartMs = pStartMs, EndMs = 0, OriginalText = translationText, - CharTimings = translationCharTimings, + LyricsChars = translationCharTimings, }); } } @@ -338,7 +338,7 @@ namespace BetterLyrics.WinUI3.Helper StartMs = lineRead.StartTime ?? 0, EndMs = 0, OriginalText = lineRead.Text, - CharTimings = [], + LyricsChars = [], }; var syllables = (lineRead as SyllableLineInfo)?.Syllables; @@ -352,7 +352,7 @@ namespace BetterLyrics.WinUI3.Helper ) { var syllable = syllables[syllableIndex]; - var charTiming = new CharTiming + var charTiming = new LyricsChar { StartMs = syllable.StartTime, EndMs = 0, @@ -367,7 +367,7 @@ namespace BetterLyrics.WinUI3.Helper { charTiming.EndMs = lineWrite.EndMs; } - lineWrite.CharTimings.Add(charTiming); + lineWrite.LyricsChars.Add(charTiming); startIndex += syllable.Text.Length; } } @@ -396,7 +396,7 @@ namespace BetterLyrics.WinUI3.Helper } // 修正 CharTimings çš„ EndMs - var timings = lines[i].CharTimings; + var timings = lines[i].LyricsChars; if (timings.Count > 0) { for (int j = 0; j < timings.Count; j++) @@ -423,7 +423,7 @@ namespace BetterLyrics.WinUI3.Helper StartMs = 0, EndMs = lines[0].StartMs, OriginalText = "â— â— â—", - CharTimings = [], + LyricsChars = [], } ); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/SystemVolumeHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/SystemVolumeHelper.cs new file mode 100644 index 0000000..8e36042 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/SystemVolumeHelper.cs @@ -0,0 +1,74 @@ +using Microsoft.UI.Dispatching; +using System; +using Vanara.Extensions; +using Vanara.PInvoke; +using static Vanara.PInvoke.CoreAudio; + +namespace BetterLyrics.WinUI3.Helper +{ + public static class SystemVolumeHelper + { + private readonly static IMMDeviceEnumerator _deviceEnumerator = new(); + private static IAudioEndpointVolume? _endpointVolume = null; + private static VolumeCallbackImpl? _callbackImpl; + private static int _masterVolume = 0; + private static DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); + + public static event Action? VolumeChanged; + + static SystemVolumeHelper() + { + var device = _deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia); + if (device != null) + { + device.Activate(typeof(IAudioEndpointVolume).GUID, 0, null, out var obj); + if (obj is IAudioEndpointVolume endpointVolume) + { + _endpointVolume = endpointVolume; + _callbackImpl = new VolumeCallbackImpl(); + _endpointVolume.RegisterControlChangeNotify(_callbackImpl); + } + } + } + + /// + /// 获å–当å‰ç³»ç»Ÿä¸»éŸ³é‡ï¼ˆ0~100)。 + /// + public static int GetMasterVolume() + { + if (_endpointVolume != null) + { + float level = _endpointVolume.GetMasterVolumeLevelScalar(); + _masterVolume = (int)(level * 100); + } + + return _masterVolume; + } + + /// + /// 设置当å‰ç³»ç»Ÿä¸»éŸ³é‡ï¼ˆ0~100)。 + /// + public static void SetMasterVolume(int volume) + { + if (_masterVolume == volume) return; + + _masterVolume = volume; + _endpointVolume?.SetMasterVolumeLevelScalar(_masterVolume / 100f, Guid.Empty); + } + + // 内部回调实现 + private class VolumeCallbackImpl : IAudioEndpointVolumeCallback + { + HRESULT IAudioEndpointVolumeCallback.OnNotify(nint pNotify) + { + var data = pNotify.ToStructure(); + _masterVolume = (int)(data.fMasterVolume * 100); + _dispatcherQueue.TryEnqueue(() => + { + VolumeChanged?.Invoke(_masterVolume); + }); + return HRESULT.S_OK; + } + } + } +} \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/CharTiming.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsChar.cs similarity index 80% rename from BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/CharTiming.cs rename to BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsChar.cs index 11f81e8..7d15654 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/CharTiming.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsChar.cs @@ -1,8 +1,10 @@ // 2025/6/23 by Zhe Fang +using BetterLyrics.WinUI3.Helper; + namespace BetterLyrics.WinUI3.Models { - public class CharTiming + public class LyricsChar { public int EndMs { get; set; } public int StartIndex { get; set; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs index da6de05..002dc22 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsData.cs @@ -1,10 +1,12 @@ using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Services; +using Lyricify.Lyrics.Helpers.General; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using StringHelper = BetterLyrics.WinUI3.Helper.StringHelper; namespace BetterLyrics.WinUI3.Models { @@ -35,7 +37,23 @@ namespace BetterLyrics.WinUI3.Models } else { - line.DisplayedText = $"{line.OriginalText}{StringHelper.NewLine}({translationData.LyricsLines[i].OriginalText})"; + if (translationData.LanguageCode?.Substring(0, 2) == "zh") + { + string tmp = ""; + if (LanguageHelper.GetUserTargetLanguageCode() == "zh-Hant") + { + tmp = ChineseConverter.ConvertToTraditionalChinese(translationData.LyricsLines[i].OriginalText); + } + else if (LanguageHelper.GetUserTargetLanguageCode() == "zh-Hans") + { + tmp = ChineseConverter.ConvertToSimplifiedChinese(translationData.LyricsLines[i].OriginalText); + } + line.DisplayedText = $"{line.OriginalText}\n{tmp}"; + } + else + { + line.DisplayedText = $"{line.OriginalText}\n{translationData.LyricsLines[i].OriginalText}"; + } } i++; } @@ -74,7 +92,7 @@ namespace BetterLyrics.WinUI3.Models StartMs = 0, EndMs = durationMs, OriginalText = App.ResourceLoader!.GetString("LyricsNotFound"), - CharTimings = [], + LyricsChars = [], }]); } @@ -87,7 +105,7 @@ namespace BetterLyrics.WinUI3.Models EndMs = (int)TimeSpan.FromMinutes(99).TotalMilliseconds, OriginalText = "â— â— â—", DisplayedText = "â— â— â—", - CharTimings = [], + LyricsChars = [], }, ]); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs index 015a356..974fa41 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs @@ -21,7 +21,7 @@ namespace BetterLyrics.WinUI3.Models public Vector2 CenterPosition { get; set; } public Vector2 Position { get; set; } - public List CharTimings { get; set; } = []; + public List LyricsChars { get; set; } = []; public int DurationMs => EndMs - StartMs; public int EndMs { get; set; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ILyricsSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ILyricsSearchService.cs index 192d4eb..197c512 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ILyricsSearchService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ILyricsSearchService.cs @@ -9,6 +9,6 @@ namespace BetterLyrics.WinUI3.Services { public interface ILyricsSearchService { - Task SearchAsync(string title, string artist, string album, double durationMs, CancellationToken token); + Task<(string?, LyricsSearchProvider?)> SearchAsync(string title, string artist, string album, double durationMs, CancellationToken token); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/IPlaybackService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/IPlaybackService.cs index 18e5dec..ab84b7b 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/IPlaybackService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/IPlaybackService.cs @@ -1,6 +1,7 @@ // 2025/6/23 by Zhe Fang using System; +using System.Threading.Tasks; using BetterLyrics.WinUI3.Events; using BetterLyrics.WinUI3.Models; @@ -13,5 +14,11 @@ namespace BetterLyrics.WinUI3.Services event EventHandler? SongInfoChanged; event EventHandler? AlbumArtChangedChanged; event EventHandler? MediaSourceProvidersInfoChanged; + + Task PlayAsync(); + Task PauseAsync(); + Task PreviousAsync(); + Task NextAsync(); + } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs index b94f924..c61230d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/ISettingsService.cs @@ -39,6 +39,8 @@ namespace BetterLyrics.WinUI3.Services string LibreTranslateServer { get; set; } int SelectedTargetLanguageIndex { get; set; } + bool ResetPositionOffsetOnSongChanged { get; set; } + int PositionOffset { get; set; } // Lyrics lib List LocalLyricsFolders { get; set; } @@ -69,6 +71,8 @@ namespace BetterLyrics.WinUI3.Services LineRenderingType LyricsGlowEffectScope { get; set; } LineRenderingType LyricsHighlightScope { get; set; } + bool IsLyricsFloatAnimationEnabled { get; set; } + float LyricsLineSpacingFactor { get; set; } List LyricsSearchProvidersInfo { get; set; } @@ -87,5 +91,6 @@ namespace BetterLyrics.WinUI3.Services LyricsDisplayType PreferredDisplayType { get; set; } int TimelineSyncThreshold { get; set; } + int LockHotKeyIndex { get; set; } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs index d686d2c..4f879c4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService.cs @@ -85,7 +85,7 @@ namespace BetterLyrics.WinUI3.Services } } - public async Task SearchAsync(string title, string artist, string album, double durationMs, CancellationToken token) + public async Task<(string?, LyricsSearchProvider?)> SearchAsync(string title, string artist, string album, double durationMs, CancellationToken token) { _logger.LogInformation("Searching img for: {Title} - {Artist} (Album: {Album}, Duration: {DurationMs}ms)", title, artist, album, durationMs); @@ -105,7 +105,7 @@ namespace BetterLyrics.WinUI3.Services cachedLyrics = FileHelper.ReadLyricsCache(title, artist, lyricsFormat, provider.Provider.GetCacheDirectory()); if (!string.IsNullOrWhiteSpace(cachedLyrics)) { - return cachedLyrics; + return (cachedLyrics, provider.Provider); } } @@ -155,11 +155,11 @@ namespace BetterLyrics.WinUI3.Services FileHelper.WriteLyricsCache(title, artist, searchedLyrics, lyricsFormat, provider.Provider.GetCacheDirectory()); } - return searchedLyrics; + return (searchedLyrics, provider.Provider); } } - return null; + return (null, null); } private async Task SearchFile(string title, string artist, LyricsFormat format) @@ -327,6 +327,17 @@ namespace BetterLyrics.WinUI3.Services { var response = await Lyricify.Lyrics.Helpers.ProviderHelper.QQMusicApi.GetLyricsAsync(qqResult.Id); var original = response?.Lyrics; + var translated = response?.Trans; + if (!string.IsNullOrEmpty(translated)) + { + FileHelper.WriteLyricsCache( + title, + artist, + translated, + LyricsFormat.Lrc, + PathHelper.QQTranslationCacheDirectory + ); + } return original; } else if (result is NeteaseSearchResult neteaseResult) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs index c84f0c3..2ef4bff 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/PlaybackService.cs @@ -255,6 +255,42 @@ namespace BetterLyrics.WinUI3.Services }); } + public async Task PlayAsync() + { + var focusedSession = _mediaManager.GetFocusedSession(); + if (focusedSession != null) + { + await focusedSession.ControlSession.TryPlayAsync(); + } + } + + public async Task PauseAsync() + { + var focusedSession = _mediaManager.GetFocusedSession(); + if (focusedSession != null) + { + await focusedSession.ControlSession.TryPauseAsync(); + } + } + + public async Task PreviousAsync() + { + var focusedSession = _mediaManager.GetFocusedSession(); + if (focusedSession != null) + { + await focusedSession.ControlSession.TrySkipPreviousAsync(); + } + } + + public async Task NextAsync() + { + var focusedSession = _mediaManager.GetFocusedSession(); + if (focusedSession != null) + { + await focusedSession.ControlSession.TrySkipNextAsync(); + } + } + public void Receive(PropertyChangedMessage> message) { if (message.Sender is SettingsPageViewModel) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs index ef2cebd..0ebb81a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/SettingsService.cs @@ -83,6 +83,14 @@ namespace BetterLyrics.WinUI3.Services public const string TimelineSyncThresholdKey = "TimelineSyncThreshold"; + private const string IsLyricsFloatAnimationEnabledKey = "IsLyricsFloatAnimationEnabled"; + + private const string ResetPositionOffsetOnSongChangedKey = "ResetPositionOffsetOnSongChanged"; + + private const string PositionOffsetKey = "PositionOffset"; + + private const string LockHotKeyIndexKey = "LockHotKeyIndex"; + private readonly ApplicationDataContainer _localSettings; public SettingsService() @@ -186,7 +194,7 @@ namespace BetterLyrics.WinUI3.Services SetDefault(LibreTranslateServerKey, ""); SetDefault(IsTranslationEnabledKey, false); - SetDefault(SelectedTargetLanguageIndexKey, 6); + SetDefault(SelectedTargetLanguageIndexKey, LanguageHelper.GetDefaultTargetLanguageIndex()); SetDefault(LyricsFontStrokeWidthKey, 3); SetDefault(IgnoreFullscreenWindowKey, false); @@ -195,6 +203,18 @@ namespace BetterLyrics.WinUI3.Services SetDefault(LyricsScrollEasingTypeKey, (int)EasingType.EaseInOutQuad); SetDefault(LyricsScrollDurationKey, 500); // 500ms SetDefault(TimelineSyncThresholdKey, 0); // 0ms + + SetDefault(IsLyricsFloatAnimationEnabledKey, false); + + SetDefault(ResetPositionOffsetOnSongChangedKey, false); + SetDefault(PositionOffsetKey, 0); + SetDefault(LockHotKeyIndexKey, 'U' - 'A'); + } + + public int LockHotKeyIndex + { + get => GetValue(LockHotKeyIndexKey); + set => SetValue(LockHotKeyIndexKey, value); } public EasingType LyricsScrollEasingType @@ -523,6 +543,24 @@ namespace BetterLyrics.WinUI3.Services set => SetValue(TimelineSyncThresholdKey, value); } + public bool IsLyricsFloatAnimationEnabled + { + get => GetValue(IsLyricsFloatAnimationEnabledKey); + set => SetValue(IsLyricsFloatAnimationEnabledKey, value); + } + + public bool ResetPositionOffsetOnSongChanged + { + get => GetValue(ResetPositionOffsetOnSongChangedKey); + set => SetValue(ResetPositionOffsetOnSongChangedKey, value); + } + + public int PositionOffset + { + get => GetValue(PositionOffsetKey); + set => SetValue(PositionOffsetKey, value); + } + private T? GetValue(string key) { if (_localSettings.Values.TryGetValue(key, out object? value)) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs index ab40cb8..ef88d7d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/TranslateService.cs @@ -18,7 +18,7 @@ namespace BetterLyrics.WinUI3.Services { private readonly HttpClient _httpClient; - public TranslateService(ISettingsService settingsService) :base(settingsService) + public TranslateService(ISettingsService settingsService) : base(settingsService) { _httpClient = new HttpClient(); } @@ -76,18 +76,18 @@ namespace BetterLyrics.WinUI3.Services public int SearchTranslatedLyricsItself(List lyricsDataArr) { - string targetLangCode = LanguageHelper.GetUserTargetLanguageCode(); + string targetLangCode = LanguageHelper.GetUserTargetLanguageCode().Substring(0, 2); if (lyricsDataArr.Count > 1) { - for (int i = 1; i < lyricsDataArr.Count; i++) + for (int i = 1; i < lyricsDataArr.Count; i++) { - if (lyricsDataArr[i].LanguageCode == targetLangCode) + if (lyricsDataArr[i].LanguageCode?.Substring(0, 2) == targetLangCode) { return i; // Translation lyrics data found } } } return -1; // No translation lyrics data found - } + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw index 6132af7..b9c1365 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw @@ -288,9 +288,6 @@ Glow effect - - Glow effect scope - Configure lyrics source @@ -528,8 +525,8 @@ Lock - - To unlock after locking, go to the system tray to unlock + + To unlock after locking, go to the system tray to unlock or press Fan lyrics @@ -649,7 +646,7 @@ Translate server is not set, please configure it in settings first - Will automatically reset to 0 when switching songs + Reset to 0 when switching songs The translation in the lyrics will be read first. If there is no match, the machine translation will be requested from the LibreTranslate server @@ -735,4 +732,13 @@ Join now + + Floating animation + + + Scope + + + Unlock and lock shortcut keys + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw index 002b876..c2c7208 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw @@ -288,9 +288,6 @@ グロー効果 - - グローエフェクトスコープ - 歌詞ソースを構æˆã—ã¾ã™ @@ -528,8 +525,8 @@ ロック - - ロック後ã«ãƒ­ãƒƒã‚¯ã‚’解除ã™ã‚‹ã«ã¯ã€ã‚·ã‚¹ãƒ†ãƒ ãƒˆãƒ¬ã‚¤ã«ç§»å‹•ã—ã¦ãƒ­ãƒƒã‚¯ã‚’解除ã—ã¾ã™ + + ロック後ã«ãƒ­ãƒƒã‚¯ã‚’解除ã™ã‚‹ã«ã¯ã€ã‚·ã‚¹ãƒ†ãƒ ãƒˆãƒ¬ã‚¤ã«ç§»å‹•ã—ã¦ãƒ­ãƒƒã‚¯ã‚’解除ã¾ãŸã¯æŠ¼ã—ã¾ã™ ãƒ•ã‚¡ãƒ³ã®æ­Œè©ž @@ -649,7 +646,7 @@ 翻訳サーãƒãƒ¼ã¯è¨­å®šã•れã¦ã„ã¾ã›ã‚“。最åˆã«è¨­å®šã§æ§‹æˆã—ã¦ãã ã•ã„ - 曲を切り替ãˆã‚‹ã¨ã€0 ã«è‡ªå‹•çš„ã«ãƒªã‚»ãƒƒãƒˆã•れã¾ã™ + 曲を切り替ãˆã‚‹ã¨ãã«0ã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã™ 歌詞ã®ç¿»è¨³ã¯æœ€åˆã«èª­ã¾ã‚Œã¾ã™ã€‚一致ã—ã¦ã„ãªã„å ´åˆã€æ©Ÿæ¢°ã®ç¿»è¨³ã¯Libretranslate Serverã‹ã‚‰è¦æ±‚ã•れã¾ã™ @@ -735,4 +732,13 @@ 今ã™ãå‚加ã—ã¦ãã ã•ã„ + + フローティングアニメーション + + + 範囲 + + + ショートカットキーã®ãƒ­ãƒƒã‚¯ã‚’解除ãŠã‚ˆã³ãƒ­ãƒƒã‚¯ã—ã¾ã™ + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw index b6c61de..6815c92 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw @@ -288,9 +288,6 @@ 글로우 효과 - - 글로우 효과 범위 - 가사 소스를 구성하십시오 @@ -528,8 +525,8 @@ 잠금 - - 잠금 ìž ê¸ˆì„ í•´ì œí•˜ë ¤ë©´ 시스템 트레ì´ë¡œ ì´ë™í•˜ì—¬ ìž ê¸ˆì„ í•´ì œí•˜ì‹­ì‹œì˜¤. + + 잠금 ìž ê¸ˆì„ í•´ì œí•˜ë ¤ë©´ 시스템 트레ì´ë¡œ ì´ë™í•˜ì—¬ ìž ê¸ˆì„ í•´ì œí•˜ê±°ë‚˜ 누릅니다. 팬 가사 @@ -649,7 +646,7 @@ 번역 서버가 설정ë˜ì§€ 않았습니다. 먼저 설정으로 구성하십시오. - 노래를 전환 í•  때 ìžë™ìœ¼ë¡œ 0 으로 재설정ë©ë‹ˆë‹¤ + 노래를 전환 í•  때 0 으로 재설정하십시오 ê°€ì‚¬ì˜ ë²ˆì—­ì€ ë¨¼ì € ì½ìŠµë‹ˆë‹¤. ì¼ì¹˜í•˜ì§€ 않으면 LibreTranslate 서버ì—서 기계 ë²ˆì—­ì´ ìš”ì²­ë©ë‹ˆë‹¤. @@ -735,4 +732,13 @@ 지금 가입하십시오 + + ë–  다니는 애니메ì´ì…˜ + + + 범위 + + + 바로 가기 키를 잠금 해제하고 잠그십시오 + \ 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 7038654..594253d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw @@ -288,9 +288,6 @@ 辉光效果 - - 辉光效果作用范围 - é…ç½®æ­Œè¯æº @@ -528,8 +525,8 @@ é”定 - - é”定åŽè§£é”ï¼Œè¯·è½¬åˆ°ç³»ç»Ÿæ‰˜ç›˜è§£é” + + é”定åŽè§£é”ï¼Œè¯·è½¬åˆ°ç³»ç»Ÿæ‰˜ç›˜è§£é”æˆ–按下 æ‰‡å½¢æ­Œè¯ @@ -649,7 +646,7 @@ 未设置翻译æœåŠ¡å™¨ï¼Œè¯·å…ˆåœ¨è®¾ç½®ä¸­è¿›è¡Œé…ç½® - åˆ‡æ¢æ­Œæ›²æ—¶å°†è‡ªåЍé‡ç½®ä¸º 0 + åˆ‡æ¢æ­Œæ›²æ—¶é‡ç½®ä¸º 0 å°†ä¼˜å…ˆè¯»å–æ­Œè¯å†…翻译,若无匹é…åˆ™å‘ LibreTranslate æœåŠ¡å™¨è¯·æ±‚æœºå™¨ç¿»è¯‘ @@ -735,4 +732,13 @@ ç«‹å³åŠ å…¥ + + 浮动动画 + + + 范围 + + + è§£é”å’Œé”定快æ·é”® + \ 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 e210a20..09312e3 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw @@ -288,9 +288,6 @@ è¼å…‰æ•ˆæžœ - - è¼å…‰æ•ˆæžœä½œç”¨ç¯„åœ - é…ç½®æ­Œè©žæº @@ -528,8 +525,8 @@ 鎖定 - - 鎖定後解鎖,請轉到系統托盤解鎖 + + 鎖定後解鎖,請轉到系統托盤解鎖或按下 扇形歌詞 @@ -649,7 +646,7 @@ 未設定翻譯伺æœå™¨ï¼Œè«‹å…ˆåœ¨è¨­å®šä¸­é€²è¡Œé…ç½® - å°‡åœ¨åˆ‡æ›æ­Œæ›²æ™‚自動é‡è¨­ç‚º 0 + åˆ‡æ›æ­Œæ›²æ™‚é‡ç½®ç‚º 0 å°‡å„ªå…ˆè®€å–æ­Œè©žå…§ç¿»è­¯ï¼Œè‹¥ç„¡åŒ¹é…å‰‡å‘ LibreTranslate 伺æœå™¨è«‹æ±‚機器翻譯 @@ -735,4 +732,13 @@ ç«‹å³åŠ å…¥ + + 浮動動畫 + + + ç¯„åœ + + + 解鎖和鎖定快æ·éµ + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs index 5401973..07ad440 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs @@ -9,8 +9,6 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging.Messages; -using Microsoft.UI.Xaml; -using System.Diagnostics; using System.Threading.Tasks; namespace BetterLyrics.WinUI3.ViewModels @@ -26,18 +24,40 @@ namespace BetterLyrics.WinUI3.ViewModels IsFirstRun = _settingsService.IsFirstRun; IsTranslationEnabled = _settingsService.IsTranslationEnabled; PreferredDisplayType = _settingsService.PreferredDisplayType; + ResetPositionOffsetOnSongChanged = _settingsService.ResetPositionOffsetOnSongChanged; + PositionOffset = _settingsService.PositionOffset; + + //Volume = SystemVolumeHelper.GetMasterVolume(); + //SystemVolumeHelper.VolumeChanged += SystemVolumeHelper_VolumeChanged; _playbackService = playbackService; _playbackService.SongInfoChanged += PlaybackService_SongInfoChanged; + _playbackService.IsPlayingChanged += PlaybackService_IsPlayingChanged; + } + + //private void SystemVolumeHelper_VolumeChanged(int volume) + //{ + // Volume = volume; + //} + + private void PlaybackService_IsPlayingChanged(object? sender, Events.IsPlayingChangedEventArgs e) + { + IsSongPlaying = e.IsPlaying; } private void PlaybackService_SongInfoChanged(object? sender, Events.SongInfoChangedEventArgs e) { SongInfo = e.SongInfo; - PositionOffset = 0; // Reset position offset when song changes + if (ResetPositionOffsetOnSongChanged) + { + PositionOffset = 0; + } TrySwitchToPreferredDisplayType(e.SongInfo); } + //[ObservableProperty] + //public partial int Volume { get; set; } + [ObservableProperty] [NotifyPropertyChangedRecipients] public partial LyricsDisplayType DisplayType { get; set; } = LyricsDisplayType.PlaceholderOnly; @@ -56,21 +76,18 @@ namespace BetterLyrics.WinUI3.ViewModels [ObservableProperty] [NotifyPropertyChangedRecipients] - public partial int PositionOffset { get; set; } = 0; + public partial int PositionOffset { get; set; } [ObservableProperty] [NotifyPropertyChangedRecipients] public partial bool IsTranslationEnabled { get; set; } - partial void OnIsTranslationEnabledChanged(bool value) - { - _settingsService.IsTranslationEnabled = value; - } + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial bool ResetPositionOffsetOnSongChanged { get; set; } - partial void OnPreferredDisplayTypeChanged(LyricsDisplayType value) - { - _settingsService.PreferredDisplayType = value; - } + [ObservableProperty] + public partial bool IsSongPlaying { get; set; } public void Receive(PropertyChangedMessage message) { @@ -95,6 +112,30 @@ namespace BetterLyrics.WinUI3.ViewModels WindowHelper.OpenOrShowWindow(); } + [RelayCommand] + private async Task PlaySongAsync() + { + await _playbackService.PlayAsync(); + } + + [RelayCommand] + private async Task PauseSongAsync() + { + await _playbackService.PauseAsync(); + } + + [RelayCommand] + private async Task PreviousSongAsync() + { + await _playbackService.PreviousAsync(); + } + + [RelayCommand] + private async Task NextSongAsync() + { + await _playbackService.NextAsync(); + } + private void SetNonStandardModePreferredDisplayType(bool isEnabled) { if (isEnabled) @@ -134,5 +175,25 @@ namespace BetterLyrics.WinUI3.ViewModels IsWelcomeTeachingTipOpen = value; _settingsService.IsFirstRun = false; } + + partial void OnIsTranslationEnabledChanged(bool value) + { + _settingsService.IsTranslationEnabled = value; + } + + partial void OnPreferredDisplayTypeChanged(LyricsDisplayType value) + { + _settingsService.PreferredDisplayType = value; + } + + partial void OnPositionOffsetChanged(int value) + { + _settingsService.PositionOffset = value; + } + + //partial void OnVolumeChanged(int value) + //{ + // SystemVolumeHelper.SetMasterVolume(value); + //} } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs index daaf80c..aa4c60a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Ctor.cs @@ -51,6 +51,8 @@ namespace BetterLyrics.WinUI3.ViewModels _canvasYScrollTransition.SetDuration(_settingsService.LyricsScrollDuration / 1000f); _canvasYScrollTransition.SetEasingType(_settingsService.LyricsScrollEasingType); + _isLyricsFloatAnimationEnabled = _settingsService.IsLyricsFloatAnimationEnabled; + _libWatcherService.MusicLibraryFilesChanged += LibWatcherService_MusicLibraryFilesChanged; diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs index 23b57d3..054ea4d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Draw.cs @@ -1,6 +1,5 @@ using BetterLyrics.WinUI3.Enums; using BetterLyrics.WinUI3.Helper; -using BetterLyrics.WinUI3.Models; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Brushes; using Microsoft.Graphics.Canvas.Effects; @@ -8,17 +7,12 @@ using Microsoft.Graphics.Canvas.Geometry; using Microsoft.Graphics.Canvas.Text; using Microsoft.Graphics.Canvas.UI.Xaml; using Microsoft.UI; -using Microsoft.UI.Text; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Media; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using Windows.Foundation; -using Windows.Graphics.Imaging; using Windows.UI; -using Windows.UI.Text; namespace BetterLyrics.WinUI3.ViewModels { @@ -286,28 +280,17 @@ namespace BetterLyrics.WinUI3.ViewModels for (int i = _startVisibleLineIndex; i <= _endVisibleLineIndex; i++) { var line = _lyricsDataArr.ElementAtOrDefault(_langIndex)?.LyricsLines.ElementAtOrDefault(i); - - if (line == null) - { - continue; - } + if (line == null) continue; var textLayout = line.CanvasTextLayout; - - if (textLayout == null) - { - continue; - } + if (textLayout == null) continue; var position = new Vector2(line.Position.X, line.Position.Y); float layoutWidth = (float)textLayout.LayoutBounds.Width; float layoutHeight = (float)textLayout.LayoutBounds.Height; - if (layoutWidth <= 0 || layoutHeight <= 0) - { - continue; - } + if (layoutWidth <= 0 || layoutHeight <= 0) continue; float centerX = position.X; float centerY = position.Y + layoutHeight / 2; @@ -329,11 +312,14 @@ namespace BetterLyrics.WinUI3.ViewModels break; } + float xOffset = _lyricsXTransition.Value; + float yOffset = _canvasYScrollTransition.Value + _canvasHeight / 2; + // 组åˆå˜æ¢ï¼šç¼©æ”¾ -> 旋转 -> 平移 ds.Transform = Matrix3x2.CreateScale(line.ScaleTransition.Value, new Vector2(centerX, centerY)) * Matrix3x2.CreateRotation(line.AngleTransition.Value, currentPlayingLine.Position) - * Matrix3x2.CreateTranslation(_lyricsXTransition.Value, _canvasYScrollTransition.Value + _canvasHeight / 2); + * Matrix3x2.CreateTranslation(xOffset, yOffset); // Create the background lyrics line with stroke and fill using var bgLyrics = new CanvasCommandList(control.Device); @@ -344,22 +330,23 @@ namespace BetterLyrics.WinUI3.ViewModels using var fgLyricsDs = fgLyrics.CreateDrawingSession(); // 创建文字几何体 - using (var textGeometry = CanvasGeometry.CreateText(textLayout)) + using var textGeometry = CanvasGeometry.CreateText(textLayout); + if (_isDesktopMode) { - if (_isDesktopMode) - { - bgLyricsDs.DrawGeometry(textGeometry, position, _strokeFontColor, _lyricsFontStrokeWidth); // 背景æè¾¹ - fgLyricsDs.DrawGeometry(textGeometry, position, _strokeFontColor, _lyricsFontStrokeWidth); // 剿™¯æè¾¹ - } - - bgLyricsDs.FillGeometry(textGeometry, position, _bgFontColor); // 背景填充 - fgLyricsDs.FillGeometry(textGeometry, position, _fgFontColor); // 剿™¯å¡«å…… + bgLyricsDs.DrawGeometry(textGeometry, position, _strokeFontColor, _lyricsFontStrokeWidth); // 背景æè¾¹ + fgLyricsDs.DrawGeometry(textGeometry, position, _strokeFontColor, _lyricsFontStrokeWidth); // 剿™¯æè¾¹ } + bgLyricsDs.FillGeometry(textGeometry, position, _bgFontColor); // 背景填充 + fgLyricsDs.FillGeometry(textGeometry, position, _fgFontColor); // 剿™¯å¡«å…… + + using var combined = new CanvasCommandList(control.Device); + using var combinedDs = combined.CreateDrawingSession(); + // Mock gradient blurred lyrics layer // å…ˆé“ºä¸€å±‚å¸¦é»˜è®¤é€æ˜Žåº¦çš„å·²ç»åŠ äº†æ¨¡ç³Šæ•ˆæžœçš„æ­Œè¯ä½œä¸ºæœ€åº•层(背景歌è¯å±‚次) // Current line will not be blurred - ds.DrawImage( + combinedDs.DrawImage( new GaussianBlurEffect { Source = new OpacityEffect { Source = bgLyrics, Opacity = line.OpacityTransition.Value * _lyricsOpacityTransition.Value }, @@ -402,7 +389,7 @@ namespace BetterLyrics.WinUI3.ViewModels region.LayoutBounds.Width, region.LayoutBounds.Height ); - maskDs.FillRectangle(rect, Colors.Black); + maskDs.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128)); } } @@ -447,7 +434,7 @@ namespace BetterLyrics.WinUI3.ViewModels fadingWidth ); - maskDs.FillRectangle(highlightRect, Colors.White); + maskDs.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128)); maskDs.FillRectangle(fadeOutRect, fadeOutBrush); highlightMaskDs.FillRectangle(fadeInRect, fadeInBrush); @@ -456,7 +443,7 @@ namespace BetterLyrics.WinUI3.ViewModels else { float height = 0f; - var regions = textLayout.GetCharacterRegions(0, string.Join("", line.CharTimings.Select(x => x.Text)).Length); + var regions = textLayout.GetCharacterRegions(0, string.Join("", line.LyricsChars.Select(x => x.Text)).Length); if (regions.Length > 0) { height = (float)regions[^1].LayoutBounds.Bottom - (float)regions[0].LayoutBounds.Top; @@ -473,12 +460,11 @@ namespace BetterLyrics.WinUI3.ViewModels ); } - ds.DrawImage( - new OpacityEffect + using var opacityEffect = new OpacityEffect + { + Source = new BlendEffect { - Source = new BlendEffect - { - Background = _isLyricsGlowEffectEnabled + Background = _isLyricsGlowEffectEnabled ? new GaussianBlurEffect { Source = new AlphaMaskEffect @@ -496,21 +482,49 @@ namespace BetterLyrics.WinUI3.ViewModels Optimization = EffectOptimization.Quality, } : new CanvasCommandList(control.Device), - Foreground = new AlphaMaskEffect + Foreground = new AlphaMaskEffect + { + Source = fgLyrics, + AlphaMask = _lyricsHighlightScope switch { - Source = fgLyrics, - AlphaMask = _lyricsHighlightScope switch - { - LineRenderingType.CurrentChar => highlightMask, - LineRenderingType.LineStartToCurrentChar => mask, - LineRenderingType.CurrentLine => fgLyrics, - _ => mask, - }, + LineRenderingType.CurrentChar => highlightMask, + LineRenderingType.LineStartToCurrentChar => mask, + LineRenderingType.CurrentLine => fgLyrics, + _ => mask, }, }, - Opacity = line.HighlightOpacityTransition.Value * _lyricsOpacityTransition.Value, + }, + Opacity = line.HighlightOpacityTransition.Value * _lyricsOpacityTransition.Value, + }; + + combinedDs.DrawImage(opacityEffect); + + if (i == _playingLineIndex) + { + if (_isLyricsFloatAnimationEnabled) + { + ds.DrawImage(new DisplacementMapEffect + { + Source = combined, + Displacement = mask, + XChannelSelect = EffectChannelSelect.Red, + YChannelSelect = EffectChannelSelect.Alpha, + Amount = 2f + }); } - ); + else + { + ds.DrawImage(combined); + } + } + else + { + ds.DrawImage(combined); + } + } + else + { + ds.DrawImage(combined); } // Reset scale @@ -548,7 +562,7 @@ namespace BetterLyrics.WinUI3.ViewModels .Select(stops => new CanvasGradientStop { Position = stops.position, - Color = Color.FromArgb((byte)(stops.opacity * 255), 0, 0, 0), + Color = Color.FromArgb((byte)(stops.opacity * 255), 128, 128, 128), }) .ToArray() ) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs index d3e6696..3f7dc79 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Messages.cs @@ -78,6 +78,10 @@ namespace BetterLyrics.WinUI3.ViewModels _isFanLyricsEnabled = message.NewValue; _isLayoutChanged = true; } + else if (message.PropertyName == nameof(SettingsPageViewModel.IsLyricsFloatAnimationEnabled)) + { + _isLyricsFloatAnimationEnabled = message.NewValue; + } } else if (message.Sender is LyricsWindowViewModel) { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs index 1e9d106..7a8b61a 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.Update.cs @@ -19,7 +19,7 @@ namespace BetterLyrics.WinUI3.ViewModels private bool _isCanvasHeightChanged = false; private bool _isDisplayTypeChanged = false; - + private bool _isPlayingLineChanged = false; private bool _isVisibleLinesBoundaryChanged = false; @@ -297,7 +297,8 @@ namespace BetterLyrics.WinUI3.ViewModels if (_adaptiveGrayedFontColor == _lightColor) { grayedEnvironmentalColor = _darkColor; - } else if (_adaptiveGrayedFontColor == _darkColor) + } + else if (_adaptiveGrayedFontColor == _darkColor) { grayedEnvironmentalColor = _lightColor; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs index 10f647b..4c2ed9c 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsRendererViewModel.cs @@ -9,6 +9,7 @@ using BetterLyrics.WinUI3.Services; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.DependencyInjection; using Lyricify.Lyrics.Helpers.General; +using Lyricify.Lyrics.Providers; using Microsoft.Extensions.Logging; using Microsoft.Graphics.Canvas; using Microsoft.Graphics.Canvas.Text; @@ -131,6 +132,8 @@ namespace BetterLyrics.WinUI3.ViewModels private bool _isDynamicCoverOverlayEnabled; private bool _isLyricsGlowEffectEnabled; + private bool _isLyricsFloatAnimationEnabled; + private bool _isLayoutChanged = true; private int _langIndex = 0; @@ -227,12 +230,12 @@ namespace BetterLyrics.WinUI3.ViewModels } // 3. 有é€å­—æ—¶é—´è½´ - if (line.CharTimings != null && line.CharTimings.Count > 0) + if (line.LyricsChars != null && line.LyricsChars.Count > 0) { - int charTimingsCount = line.CharTimings.Count; + int charTimingsCount = line.LyricsChars.Count; for (int i = 0; i < charTimingsCount; i++) { - var timing = line.CharTimings[i]; + var timing = line.LyricsChars[i]; // 当剿—¶é—´åœ¨æŸä¸ªå­—的高亮区间 if (now >= timing.StartMs && now <= timing.EndMs) @@ -342,6 +345,9 @@ namespace BetterLyrics.WinUI3.ViewModels private void UpdateTranslations() { + _lyricsDataArr.ElementAtOrDefault(0)?.SetDisplayedTextInOriginalText(); + _isLayoutChanged = true; + IsTranslating = true; if (_isTranslationEnabled) { @@ -354,7 +360,7 @@ namespace BetterLyrics.WinUI3.ViewModels } else { - _lyricsDataArr[0].SetDisplayedTextInOriginalText(); + _lyricsDataArr.ElementAtOrDefault(0)?.SetDisplayedTextInOriginalText(); IsTranslating = false; _isLayoutChanged = true; } @@ -382,10 +388,13 @@ namespace BetterLyrics.WinUI3.ViewModels } else { - var translated = await _translateService.TranslateTextAsync(originalText, targetLangCode, token); - token.ThrowIfCancellationRequested(); - - _lyricsDataArr[0].SetDisplayedTextAlongWith(translated); + try + { + var translated = await _translateService.TranslateTextAsync(originalText, targetLangCode, token); + token.ThrowIfCancellationRequested(); + _lyricsDataArr[0].SetDisplayedTextAlongWith(translated); + } + catch (Exception) { } } } } @@ -398,10 +407,11 @@ namespace BetterLyrics.WinUI3.ViewModels _isLayoutChanged = true; string? lyricsRaw = null; + LyricsSearchProvider? provider = null; if (SongInfo != null) { - lyricsRaw = await _lyrcsSearchService.SearchAsync( + (lyricsRaw, provider) = await _lyrcsSearchService.SearchAsync( SongInfo.Title, SongInfo.Artist, SongInfo.Album ?? "", @@ -410,13 +420,14 @@ namespace BetterLyrics.WinUI3.ViewModels ); _logger.LogInformation("Lyrics search result: {LyricsRaw}", lyricsRaw ?? "null"); token.ThrowIfCancellationRequested(); + _lyricsDataArr = new LyricsParser().Parse(lyricsRaw, (int?)SongInfo?.DurationMs); + FillTranslationFromCache(provider); } else { _logger.LogWarning("SongInfo is null, cannot search lyrics."); } - _lyricsDataArr = new LyricsParser().Parse(lyricsRaw, (int?)SongInfo?.DurationMs); _logger.LogInformation("Parsed lyrics: {MultiLangLyricsCount} languages", _lyricsDataArr.Count); // This ensures that original lyrics are always shown while waiting for translations @@ -425,5 +436,43 @@ namespace BetterLyrics.WinUI3.ViewModels UpdateTranslations(); } + + private void FillTranslationFromCache(LyricsSearchProvider? provider) + { + string? translationRaw = null; + switch (provider) + { + case LyricsSearchProvider.QQ: + translationRaw = FileHelper.ReadLyricsCache(SongInfo!.Title, SongInfo.Artist, LyricsFormat.Lrc, PathHelper.QQTranslationCacheDirectory); + break; + case LyricsSearchProvider.Kugou: + break; + case LyricsSearchProvider.Netease: + break; + case LyricsSearchProvider.LrcLib: + break; + case LyricsSearchProvider.AmllTtmlDb: + break; + case LyricsSearchProvider.LocalMusicFile: + break; + case LyricsSearchProvider.LocalLrcFile: + break; + case LyricsSearchProvider.LocalEslrcFile: + break; + case LyricsSearchProvider.LocalTtmlFile: + break; + default: + break; + } + if (translationRaw != null) + { + var translationData = new LyricsParser().Parse(translationRaw, (int?)SongInfo?.DurationMs); + foreach (var data in translationData) + { + data.LyricsLines = data.LyricsLines.Where(line => !string.IsNullOrWhiteSpace(line.OriginalText)).ToList(); + } + _lyricsDataArr = _lyricsDataArr.Concat(translationData).ToList(); + } + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs index 92add0a..8ff92d7 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsWindowViewModel.cs @@ -15,6 +15,8 @@ using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using System.Diagnostics; using System.Threading.Tasks; +using Vanara.PInvoke; +using Windows.System; using Windows.UI; using WinRT.Interop; using WinUIEx; @@ -61,6 +63,9 @@ namespace BetterLyrics.WinUI3 [NotifyPropertyChangedRecipients] public partial bool IsMouseWithinWindow { get; set; } = false; + [ObservableProperty] + public partial string LockHotKey { get; set; } + public void Receive(PropertyChangedMessage message) { if (message.Sender is SystemTrayViewModel) @@ -107,9 +112,37 @@ namespace BetterLyrics.WinUI3 DockModeHelper.UpdateAppBarHeight(WindowNative.GetWindowHandle(window), message.NewValue * 4); } } + else if (message.Sender is SettingsPageViewModel) + { + if (message.PropertyName == nameof(SettingsPageViewModel.LockHotKeyIndex)) + { + UpdateLockHotKey(message.NewValue); + } + } } } + private void UpdateLockHotKey(int hotKeyIndex) + { + var window = WindowHelper.GetWindowByWindowType(); + if (window == null) return; + + GlobalHotKeyHelper.UnregisterAllHotKeys(window); + GlobalHotKeyHelper.RegisterHotKey( + window, + User32.HotKeyModifiers.MOD_CONTROL | User32.HotKeyModifiers.MOD_ALT, + (uint)(hotKeyIndex + (int)VirtualKey.A), + () => + { + if (IsDesktopMode) + { + ToggleLockWindowCommand.Execute(null); + } + } + ); + LockHotKey = ((VirtualKey)(hotKeyIndex + (int)VirtualKey.A)).ToString(); + } + public void StartWatchWindowColorChange(WindowPixelSampleMode mode) { var window = WindowHelper.GetWindowByWindowType(); @@ -142,14 +175,27 @@ namespace BetterLyrics.WinUI3 ActivatedWindowAccentColor = Helper.ColorHelper.GetAccentColor(hwnd, mode).ToColor(); } + public void InitLockHotKey() + { + UpdateLockHotKey(_settingsService.LockHotKeyIndex); + } + [RelayCommand] - private void LockWindow() + private void ToggleLockWindow() { var window = WindowHelper.GetWindowByWindowType(); if (window == null) return; - DesktopModeHelper.SetClickThrough(window, true); - IsLyricsWindowLocked = true; + if (IsLyricsWindowLocked) + { + DesktopModeHelper.SetClickThrough(window, false); + IsLyricsWindowLocked = false; + } + else + { + DesktopModeHelper.SetClickThrough(window, true); + IsLyricsWindowLocked = true; + } } [RelayCommand] diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs index 8510cbe..c52c937 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/SettingsPageViewModel.cs @@ -89,6 +89,10 @@ namespace BetterLyrics.WinUI3.ViewModels LyricsScrollDuration = _settingsService.LyricsScrollDuration; TimelineSyncThreshold = _settingsService.TimelineSyncThreshold; + IsLyricsFloatAnimationEnabled = _settingsService.IsLyricsFloatAnimationEnabled; + ResetPositionOffsetOnSongChanged = _settingsService.ResetPositionOffsetOnSongChanged; + LockHotKeyIndex = _settingsService.LockHotKeyIndex; + _playbackService.MediaSourceProvidersInfoChanged += PlaybackService_SessionIdsChanged; Task.Run(async () => @@ -102,6 +106,10 @@ namespace BetterLyrics.WinUI3.ViewModels MediaSourceProvidersInfo = [.. e.MediaSourceProviersInfo]; } + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial int LockHotKeyIndex { get; set; } + [ObservableProperty] [NotifyPropertyChangedRecipients] public partial ElementTheme LyricsBackgroundTheme { get; set; } @@ -224,6 +232,14 @@ namespace BetterLyrics.WinUI3.ViewModels [ObservableProperty] public partial object NavViewSelectedItemTag { get; set; } + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial bool ResetPositionOffsetOnSongChanged { get; set; } + + [ObservableProperty] + [NotifyPropertyChangedRecipients] + public partial bool IsLyricsFloatAnimationEnabled { get; set; } + public string Version { get; set; } = MetadataHelper.AppVersion; public string BuildDate { get; set; } = string.Empty; @@ -597,6 +613,13 @@ namespace BetterLyrics.WinUI3.ViewModels { _settingsService.TimelineSyncThreshold = value; } - + partial void OnIsLyricsFloatAnimationEnabledChanged(bool value) + { + _settingsService.IsLyricsFloatAnimationEnabled = value; + } + partial void OnResetPositionOffsetOnSongChangedChanged(bool value) + { + _settingsService.ResetPositionOffsetOnSongChanged = value; + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml index 5d8c47f..3637924 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml @@ -55,6 +55,72 @@ + + + + + + + + + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs index 885da5b..937d207 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsWindow.xaml.cs @@ -10,13 +10,19 @@ using CommunityToolkit.Mvvm.Messaging.Messages; using Microsoft.UI.Windowing; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Input; +using System.Drawing; using System.Threading.Tasks; +using System.Windows.Forms; +using Vanara.PInvoke; +using Windows.System; +using WinUIEx.Messaging; namespace BetterLyrics.WinUI3.Views { public sealed partial class LyricsWindow : Window { private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService(); + private readonly WindowMessageMonitor _wmm; public LyricsWindow() { @@ -28,6 +34,18 @@ namespace BetterLyrics.WinUI3.Views AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed; Title = App.ResourceLoader!.GetString("LyricsPageTitle"); SetTitleBar(TopCommandGrid); + + _wmm = new WindowMessageMonitor(this); + _wmm.WindowMessageReceived += Wmm_WindowMessageReceived; + } + + private void Wmm_WindowMessageReceived(object? sender, WindowMessageEventArgs e) + { + if (e.Message.MessageId == (uint)User32.WindowMessage.WM_HOTKEY) + { + int id = (int)e.Message.WParam; + GlobalHotKeyHelper.TryInvokeAction(id); + } } public LyricsWindowViewModel ViewModel { get; private set; } = Ioc.Default.GetRequiredService(); @@ -54,7 +72,7 @@ namespace BetterLyrics.WinUI3.Views ViewModel.ToggleDesktopModeCommand.Execute(null); if (autoLook == null && _settingsService.AutoLockOnDesktopMode) { - ViewModel.LockWindowCommand.Execute(null); + ViewModel.ToggleLockWindowCommand.Execute(null); } break; default: @@ -189,7 +207,6 @@ namespace BetterLyrics.WinUI3.Views Visibility.Collapsed; ClickThroughButton.Visibility = Visibility.Visible; - } else { @@ -255,7 +272,7 @@ namespace BetterLyrics.WinUI3.Views private void TopCommandGrid_PointerEntered(object sender, PointerRoutedEventArgs e) { - TopCommandGrid.Opacity = 1; + TopCommandGrid.Opacity = 0.5; } private void TopCommandGrid_PointerExited(object sender, PointerRoutedEventArgs e) @@ -277,5 +294,21 @@ namespace BetterLyrics.WinUI3.Views { ViewModel.IsMouseWithinWindow = false; } + + private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) + { + if (ClickThroughButton == null) return; + + // »ñÈ¡Ëø¿Ø¼þÔÚ´°¿ÚÖеÄλÖã¨Ïà¶ÔÓÚ´°¿Ú×óÉϽǣ© + var transform = ClickThroughButton.TransformToVisual(Content); + var point = transform.TransformPoint(new Windows.Foundation.Point(0, 0)); + var btnRect = new Rectangle( + (int)point.X, + (int)point.Y, + (int)ClickThroughButton.ActualWidth, + (int)ClickThroughButton.ActualHeight + ); + DesktopModeHelper.SetInteractiveRects([btnRect]); + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml index 5da2387..eb0c7af 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml @@ -138,6 +138,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -668,7 +705,7 @@ IsExpanded="{x:Bind ViewModel.IsLyricsGlowEffectEnabled, Mode=OneWay}"> - + @@ -678,6 +715,10 @@ + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs index 38d5fc8..53439f4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/SettingsPage.xaml.cs @@ -7,14 +7,13 @@ using CommunityToolkit.Mvvm.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using System; +using System.Windows.Forms; using Windows.System; namespace BetterLyrics.WinUI3.Views { public sealed partial class SettingsPage : Page { - private bool _isUserToggle; - public SettingsPage() { this.InitializeComponent();