From bbda1cd7973995afe3c884e39f50af74bbd87251 Mon Sep 17 00:00:00 2001 From: Zhe Fang Date: Fri, 28 Nov 2025 18:25:20 -0500 Subject: [PATCH] refactor --- .../Package.appxmanifest | 2 +- .../BetterLyrics.WinUI3.csproj | 7 + .../Constants/ExtendedGenreFiled.cs | 1 + .../BetterLyrics.WinUI3/Constants/Time.cs | 4 +- .../AlbumArtLayoutSettingsControl.xaml | 35 +- .../BetterLyrics.WinUI3/Controls/Dragger.xaml | 25 + .../Controls/Dragger.xaml.cs | 136 ++++ .../Controls/LyricsStyleSettingsControl.xaml | 6 +- .../Controls/LyricsWindowSettingsControl.xaml | 220 ++++-- .../Controls/NowPlayingCanvas.xaml.cs | 192 ++++- .../Helper/CanvasHelper.cs | 332 --------- .../Logic/LyricsAnimator.cs | 9 +- .../Logic/LyricsLayoutManager.cs | 54 +- .../Logic/LyricsSynchronizer.cs | 14 +- .../BetterLyrics.WinUI3/Models/LyricsLine.cs | 44 +- .../Models/LyricsWindowStatus.cs | 34 + .../Models/Settings/AlbumArtLayoutSettings.cs | 11 +- .../Renderer/LyricsRenderer.cs | 94 +-- .../Renderer/PlayingLineRenderer.cs | 19 +- .../Renderer/UnplayingLineRenderer.cs | 7 +- .../LyricsSearchService.cs | 6 +- .../MediaSessionsService.LyricsUpdater.cs | 11 +- .../MediaSessionsService.cs | 6 + .../Strings/en-US/Resources.resw | 73 +- .../Strings/ja-JP/Resources.resw | 77 +- .../Strings/ko-KR/Resources.resw | 77 +- .../Strings/zh-CN/Resources.resw | 77 +- .../Strings/zh-TW/Resources.resw | 79 +- .../ViewModels/LyricsPageViewModel.cs | 68 +- .../BetterLyrics.WinUI3/Views/LyricsPage.xaml | 417 ++++++----- .../Views/LyricsPage.xaml.cs | 692 +++++++++++++----- 31 files changed, 1758 insertions(+), 1071 deletions(-) create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml create mode 100644 BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml.cs diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest index bfceb91..b95352e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3 (Package)/Package.appxmanifest @@ -12,7 +12,7 @@ + Version="1.0.151.0" /> diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj index 5c514fc..ce8e661 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj @@ -26,6 +26,7 @@ + @@ -57,6 +58,7 @@ + @@ -334,6 +336,11 @@ + + + MSBuild:Compile + + MSBuild:Compile diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/ExtendedGenreFiled.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/ExtendedGenreFiled.cs index 2ff2cbc..b9ce654 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/ExtendedGenreFiled.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/ExtendedGenreFiled.cs @@ -3,6 +3,7 @@ public class ExtendedGenreFiled { public const string NetEaseCloudMusicTrackID = "NCM-"; + public const string QQMusicTrackID = "QQ-"; public const string FileName = "FILENAME-"; } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Time.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Time.cs index 634ce25..d4ff786 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Time.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Constants/Time.cs @@ -4,7 +4,7 @@ namespace BetterLyrics.WinUI3.Constants { public static class Time { - public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(300); - public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(500); + public static readonly TimeSpan DebounceTimeout = TimeSpan.FromMilliseconds(250); + public static readonly TimeSpan AnimationDuration = TimeSpan.FromMilliseconds(250); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/AlbumArtLayoutSettingsControl.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/AlbumArtLayoutSettingsControl.xaml index 674b5f1..a3adeb3 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/AlbumArtLayoutSettingsControl.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/AlbumArtLayoutSettingsControl.xaml @@ -18,26 +18,13 @@ - - - - - - - - - - + + + + + + + - + - - - + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml new file mode 100644 index 0000000..2d9edbe --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml.cs new file mode 100644 index 0000000..0e423c8 --- /dev/null +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/Dragger.xaml.cs @@ -0,0 +1,136 @@ +using Microsoft.UI.Input; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using System; +using Windows.Foundation; + +namespace BetterLyrics.WinUI3.Controls +{ + public class DragDeltaEventArgs : EventArgs + { + public double HorizontalChange { get; } + public double VerticalChange { get; } + + public DragDeltaEventArgs(double hChange, double vChange) + { + HorizontalChange = hChange; + VerticalChange = vChange; + } + } + + public sealed partial class Dragger : UserControl + { + public event EventHandler DragStarted; + public event EventHandler DragDelta; + public event EventHandler DragCompleted; + + private bool _isDragging = false; + private Point _lastPoint; + + public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(Dragger), + new PropertyMetadata(Orientation.Vertical, OnOrientationChanged)); + + public Orientation Orientation + { + get => (Orientation)GetValue(OrientationProperty); + set => SetValue(OrientationProperty, value); + } + + private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (Dragger)d; + control.UpdateVisuals(); + } + + public Dragger() + { + this.InitializeComponent(); + this.Loaded += (s, e) => UpdateVisuals(); + } + + private void UpdateVisuals() + { + if (Orientation == Orientation.Vertical) + { + this.ProtectedCursor = InputSystemCursor.Create(InputSystemCursorShape.SizeWestEast); + + this.Width = 16; + this.Height = double.NaN; // Auto + + if (HitArea != null && HandlePill != null) + { + HitArea.Width = 16; + HitArea.Height = double.NaN; + + HandlePill.Width = 8; + HandlePill.Height = 32; + } + } + else + { + this.ProtectedCursor = InputSystemCursor.Create(InputSystemCursorShape.SizeNorthSouth); + + this.Height = 16; + this.Width = double.NaN; // Auto + + if (HitArea != null && HandlePill != null) + { + HitArea.Height = 16; + HitArea.Width = double.NaN; + + HandlePill.Height = 8; + HandlePill.Width = 32; + } + } + } + + private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e) + { + } + + private void Grid_PointerExited(object sender, PointerRoutedEventArgs e) + { + } + + private void Grid_PointerPressed(object sender, PointerRoutedEventArgs e) + { + var element = sender as UIElement; + if (element.CapturePointer(e.Pointer)) + { + _isDragging = true; + _lastPoint = e.GetCurrentPoint(this.XamlRoot.Content).Position; + DragStarted?.Invoke(this, EventArgs.Empty); + } + } + + private void Grid_PointerMoved(object sender, PointerRoutedEventArgs e) + { + if (_isDragging) + { + var currentPoint = e.GetCurrentPoint(this.XamlRoot.Content).Position; + double dx = currentPoint.X - _lastPoint.X; + double dy = currentPoint.Y - _lastPoint.Y; + + if (dx != 0 || dy != 0) + { + DragDelta?.Invoke(this, new DragDeltaEventArgs(dx, dy)); + _lastPoint = currentPoint; + } + } + } + + private void Grid_PointerReleased(object sender, PointerRoutedEventArgs e) + { + if (_isDragging) + { + var element = sender as UIElement; + _isDragging = false; + element.ReleasePointerCapture(e.Pointer); + DragCompleted?.Invoke(this, EventArgs.Empty); + } + } + } +} \ No newline at end of file diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsStyleSettingsControl.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsStyleSettingsControl.xaml index 08809b1..421a58d 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsStyleSettingsControl.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsStyleSettingsControl.xaml @@ -23,9 +23,9 @@ - - - + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsWindowSettingsControl.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsWindowSettingsControl.xaml index 2275147..a046f37 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsWindowSettingsControl.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/LyricsWindowSettingsControl.xaml @@ -171,6 +171,15 @@ + + + + + + - - - - - - @@ -228,7 +228,7 @@ - + @@ -246,26 +246,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -431,6 +380,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/NowPlayingCanvas.xaml.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/NowPlayingCanvas.xaml.cs index b5d153d..2993dba 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/NowPlayingCanvas.xaml.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Controls/NowPlayingCanvas.xaml.cs @@ -5,11 +5,13 @@ using BetterLyrics.WinUI3.Enums; using BetterLyrics.WinUI3.Helper; using BetterLyrics.WinUI3.Logic; using BetterLyrics.WinUI3.Models; +using BetterLyrics.WinUI3.Models.Settings; using BetterLyrics.WinUI3.Renderer; using BetterLyrics.WinUI3.Services.LastFMService; using BetterLyrics.WinUI3.Services.LiveStatesService; using BetterLyrics.WinUI3.Services.MediaSessionsService; using BetterLyrics.WinUI3.Services.SettingsService; +using BetterLyrics.WinUI3.ViewModels; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging.Messages; @@ -23,17 +25,23 @@ using Microsoft.UI.Xaml.Media.Imaging; using System; using System.Diagnostics; using System.Linq; +using System.Numerics; using Windows.Foundation; using Windows.UI; namespace BetterLyrics.WinUI3.Controls { public sealed partial class NowPlayingCanvas : UserControl, + IRecipient>, IRecipient>, IRecipient>, IRecipient>, IRecipient>, - IRecipient> + IRecipient>, + IRecipient>, + IRecipient>, + IRecipient>, + IRecipient> { private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService(); private readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService(); @@ -100,6 +108,8 @@ namespace BetterLyrics.WinUI3.Controls private double _renderLyricsHeight = 0; private double _renderLyricsOpacity = 0; + private LyricsData? _lyricsData; + private bool _isLayoutChanged = true; private int _playingLineIndex; private (int Start, int End) _visibleRange; @@ -162,11 +172,16 @@ namespace BetterLyrics.WinUI3.Controls { InitializeComponent(); + WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); _themeManager = new(_mediaSessionsService); } @@ -196,7 +211,7 @@ namespace BetterLyrics.WinUI3.Controls canvas._renderLyricsOpacity = Convert.ToDouble(e.NewValue); } - canvas.TriggerRelayout(); + canvas._isLayoutChanged = true; } } @@ -212,7 +227,7 @@ namespace BetterLyrics.WinUI3.Controls var lyricsStyle = status.LyricsStyleSettings; var lyricsEffect = status.LyricsEffectSettings; - var lyricsData = _mediaSessionsService.CurrentLyricsData; + var lyricsData = _lyricsData; double songDuration = _mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0; bool isForceWordByWord = _settingsService.AppSettings.GeneralSettings.IsForceWordByWordEffect; @@ -253,13 +268,15 @@ namespace BetterLyrics.WinUI3.Controls _lyricsRenderer.Draw( control: sender, ds: args.DrawingSession, - lyricsData: _mediaSessionsService.CurrentLyricsData, + lyricsData: _lyricsData, playingLineIndex: _playingLineIndex, startVisibleIndex: _visibleRange.Start, endVisibleIndex: _visibleRange.End, - canvasHeight: sender.Size.Height, lyricsX: _renderLyricsStartX, + lyricsY: _renderLyricsStartY, lyricsWidth: _renderLyricsWidth, + lyricsHeight: _renderLyricsHeight, + lyricsOpacity: _renderLyricsOpacity, windowStatus: status, strokeColor: _currentThemeColors.StrokeFontColor, bgColor: _currentThemeColors.BgFontColor, @@ -297,6 +314,19 @@ namespace BetterLyrics.WinUI3.Controls ); } +#if DEBUG + args.DrawingSession.DrawText( + $"[DEBUG]\n" + + $"Lyrics start pos: ({(int)_renderLyricsStartX}, {(int)_renderLyricsStartY})\n" + + $"Lyrics size: [{(int)_renderLyricsWidth} x {(int)_renderLyricsHeight}]\n" + + $"Playing line (idx): {_playingLineIndex}\n" + + $"Visible lines range (idx): [{_visibleRange.Start}, {_visibleRange.End}]\n" + + $"Total line count: {GetMaxLyricsLineIndexBoundaries().Item2 + 1}\n" + + $"Played: {TimeSpan.FromMilliseconds(fixedSongPositionMs)} / {TimeSpan.FromMilliseconds(_mediaSessionsService.CurrentSongInfo?.DurationMs ?? 0)}\n" + + $"Y offset: {_canvasYScrollTransition.Value}", + new Vector2(10, 40), Colors.Red); +#endif + } private void Canvas_Update(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args) @@ -316,9 +346,11 @@ namespace BetterLyrics.WinUI3.Controls UpdatePlaybackState(elapsedTime); + TriggerRelayout(); + #region UpdatePlayingLineIndex - int newPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPosition.TotalMilliseconds, _mediaSessionsService.CurrentLyricsData); + int newPlayingIndex = _synchronizer.GetCurrentLineIndex(_songPosition.TotalMilliseconds, _lyricsData); bool isPlayingLineChanged = newPlayingIndex != _playingLineIndex; _playingLineIndex = newPlayingIndex; @@ -326,22 +358,27 @@ namespace BetterLyrics.WinUI3.Controls #region UpdateTargetScrollOffset - var targetScroll = _layoutManager.CalculateTargetScrollOffset(_mediaSessionsService.CurrentLyricsData, _playingLineIndex); - if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value; + if (isPlayingLineChanged || _isLayoutChanged) + { + var targetScroll = _layoutManager.CalculateTargetScrollOffset(_lyricsData, _playingLineIndex); + if (targetScroll.HasValue) _canvasTargetScrollOffset = targetScroll.Value; - _canvasYScrollTransition.StartTransition(_canvasTargetScrollOffset); + _canvasYScrollTransition.StartTransition(_canvasTargetScrollOffset, _isLayoutChanged); + } _canvasYScrollTransition.Update(elapsedTime); #endregion _visibleRange = _layoutManager.CalculateVisibleRange( - _mediaSessionsService.CurrentLyricsData?.LyricsLines, + _lyricsData?.LyricsLines, _canvasYScrollTransition.Value, // ǰλ + _renderLyricsStartY, + _renderLyricsHeight, sender.Size.Height ); _animator.UpdateVisibleLines( - _mediaSessionsService.CurrentLyricsData, + _lyricsData, _visibleRange.Start, _visibleRange.End, _playingLineIndex, @@ -415,6 +452,7 @@ namespace BetterLyrics.WinUI3.Controls _snowRenderer.LoadResources(); _fogRenderer.LoadResources(); + _isLayoutChanged = true; TriggerRelayout(); } @@ -450,19 +488,18 @@ namespace BetterLyrics.WinUI3.Controls private void TriggerRelayout() { - if (_layoutManager == null || _mediaSessionsService.CurrentLyricsData == null) return; + if (_layoutManager == null || _lyricsData == null || !_isLayoutChanged) return; _layoutManager.MeasureAndArrange( resourceCreator: Canvas, - lyricsData: _mediaSessionsService.CurrentLyricsData, + lyricsData: _lyricsData, status: _liveStatesService.LiveStates.LyricsWindowStatus, appSettings: _settingsService.AppSettings, canvasWidth: Canvas.Size.Width, canvasHeight: Canvas.Size.Height, - lyricsWidth: _renderLyricsWidth + lyricsWidth: _renderLyricsWidth, + lyricsHeight: _renderLyricsHeight ); - - _isLayoutChanged = true; } private void UpdatePlaybackState(TimeSpan elapsedTime) @@ -500,13 +537,13 @@ namespace BetterLyrics.WinUI3.Controls private Tuple GetMaxLyricsLineIndexBoundaries() { if (_mediaSessionsService.CurrentSongInfo == null - || _mediaSessionsService.CurrentLyricsData == null - || _mediaSessionsService.CurrentLyricsData.LyricsLines.Count == 0) + || _lyricsData == null + || _lyricsData.LyricsLines.Count == 0) { return new Tuple(-1, -1); } - return new Tuple(0, _mediaSessionsService.CurrentLyricsData.LyricsLines.Count - 1); + return new Tuple(0, _lyricsData.LyricsLines.Count - 1); } public void Receive(PropertyChangedMessage message) @@ -575,13 +612,8 @@ namespace BetterLyrics.WinUI3.Controls { if (message.PropertyName == nameof(IMediaSessionsService.CurrentLyricsData)) { - DispatcherQueue.TryEnqueue(() => - { - if (IsLoaded) - { - TriggerRelayout(); - } - }); + _lyricsData = message.NewValue; + _isLayoutChanged = true; } } } @@ -592,16 +624,110 @@ namespace BetterLyrics.WinUI3.Controls { if (message.PropertyName == nameof(LiveStates.LyricsWindowStatus)) { - DispatcherQueue.TryEnqueue(() => - { - if (IsLoaded) - { - TriggerRelayout(); - } - }); + _isLayoutChanged = true; } } } + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsStyleSettings) + { + if (message.PropertyName == nameof(LyricsStyleSettings.PhoneticLyricsFontSize)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsStyleSettings.OriginalLyricsFontSize)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsStyleSettings.TranslatedLyricsFontSize)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsStyleSettings.LyricsFontStrokeWidth)) + { + _isLayoutChanged = true; + } + } + else if (message.Sender is LyricsEffectSettings) + { + if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollDuration)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollTopDuration)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollBottomDuration)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollTopDelay)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsEffectSettings.LyricsScrollBottomDelay)) + { + _isLayoutChanged = true; + } + else if (message.PropertyName == nameof(LyricsEffectSettings.FanLyricsAngle)) + { + _isLayoutChanged = true; + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsStyleSettings) + { + if (message.PropertyName == nameof(LyricsStyleSettings.LyricsLineSpacingFactor)) + { + _isLayoutChanged = true; + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsEffectSettings) + { + if (message.PropertyName == nameof(LyricsEffectSettings.IsFanLyricsEnabled)) + { + _isLayoutChanged = true; + } + } + else if (message.Sender is LyricsStyleSettings) + { + if (message.PropertyName == nameof(LyricsStyleSettings.IsDynamicLyricsFontSize)) + { + _isLayoutChanged = true; + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsStyleSettings) + { + if (message.PropertyName == nameof(LyricsStyleSettings.LyricsAlignmentType)) + { + _isLayoutChanged = true; + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is IMediaSessionsService) + { + if (message.PropertyName == nameof(IMediaSessionsService.CurrentSongInfo)) + { + ResetPlaybackState(); + } + } + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CanvasHelper.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CanvasHelper.cs index 4a2a2bc..a7bc233 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CanvasHelper.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/CanvasHelper.cs @@ -17,314 +17,6 @@ namespace BetterLyrics.WinUI3.Helper { public class CanvasHelper { - public static CanvasLinearGradientBrush CreateHorizontalFillBrush( - ICanvasAnimatedControl control, - List<(double position, double opacity)> stops, - double startX, - double width - ) - { - return new CanvasLinearGradientBrush(control, stops.Select(stops => new CanvasGradientStop - { - Position = (float)stops.position, - Color = Color.FromArgb((byte)(stops.opacity * 255), 128, 128, 128), - }).ToArray()) - { - StartPoint = new Vector2((float)startX, 0), - EndPoint = new Vector2((float)(startX + width), 0), - }; - } - - /// - /// 背景层 - /// - /// _lyricsOpacityTransition.Value - public static OpacityEffect CreateBackgroundEffect(LyricsLine lyricsLine, CanvasCommandList backgroundFontEffect, double lyricsLayerOpacity) - { - if (lyricsLine.BlurAmountTransition.Value == 0) - { - return new OpacityEffect - { - Source = backgroundFontEffect, - Opacity = (float)Math.Clamp(lyricsLine.OriginalTextOpacityTransition.Value * lyricsLayerOpacity, 0, 1), - }; - } - else - { - return new OpacityEffect - { - Source = new GaussianBlurEffect - { - Source = backgroundFontEffect, - BlurAmount = (float)Math.Max(lyricsLine.BlurAmountTransition.Value, 0), - BorderMode = EffectBorderMode.Soft, - Optimization = EffectOptimization.Speed, - }, - Opacity = (float)Math.Clamp(lyricsLine.OriginalTextOpacityTransition.Value * lyricsLayerOpacity, 0, 1), - }; - } - } - - public static CanvasCommandList CreateFontEffect(LyricsLine lyricsLine, ICanvasAnimatedControl control, Color strokeColor, int strokeWidth, Color fontColor) - { - CanvasCommandList list = new(control); - using var ds = list.CreateDrawingSession(); - - return list; - } - - /// - /// 创建辉光效果层 - /// 仅需在布局重构 (Relayout) 时调用 - /// - /// _lyricsGlowEffectScope - /// _lyricsGlowEffectAmount - public static GaussianBlurEffect CreateForegroundBlurEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double glowEffectAmount) - { - return new GaussianBlurEffect - { - Source = new AlphaMaskEffect - { - Source = foregroundFontEffect, - AlphaMask = mask, - }, - BlurAmount = (float)Math.Clamp(glowEffectAmount, 0, 100), - Optimization = EffectOptimization.Speed, - }; - } - - public static CanvasCommandList CreateCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress) - { - var mask = new CanvasCommandList(control); - using var ds = mask.CreateDrawingSession(); - - if (lyricsLine.OriginalCanvasTextLayout == null) - { - return mask; - } - - var highlightRegion = lyricsLine.OriginalCanvasTextLayout.GetCharacterRegions(charStartIndex, charLength).FirstOrDefault(); - - double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width; - // Draw the highlight for the current character - double highlightWidth = highlightTotalWidth * charProgress; - - double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2; - - // Rects - var highlightRect = new Rect( - highlightRegion.LayoutBounds.X, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - highlightWidth, - highlightRegion.LayoutBounds.Height - ); - - var fadeInRect = new Rect( - highlightRect.Right - fadingWidth, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - fadingWidth, - highlightRegion.LayoutBounds.Height - ); - var fadeOutRect = new Rect( - highlightRect.Right, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - fadingWidth, - highlightRegion.LayoutBounds.Height - ); - - // Brushes - using var fadeInBrush = CanvasHelper.CreateHorizontalFillBrush( - control, - [(0f, 0f), (1f, 1f)], - (double)highlightRect.Right - fadingWidth, - fadingWidth - ); - using var fadeOutBrush = CanvasHelper.CreateHorizontalFillBrush( - control, - [(0f, 1f), (1f, 0f)], - (double)highlightRect.Right, - fadingWidth - ); - - ds.FillRectangle(fadeInRect, fadeInBrush); - ds.FillRectangle(fadeOutRect, fadeOutBrush); - - return mask; - } - - public static CanvasCommandList CreateLineStartToCharMask(ICanvasAnimatedControl control, LyricsLine lyricsLine, int charStartIndex, int charLength, double charProgress, bool fade) - { - var mask = new CanvasCommandList(control); - - if (lyricsLine.OriginalCanvasTextLayout == null) - { - return mask; - } - - using var ds = mask.CreateDrawingSession(); - - var regions = lyricsLine.OriginalCanvasTextLayout.GetCharacterRegions(0, charStartIndex); - var highlightRegion = lyricsLine.OriginalCanvasTextLayout - .GetCharacterRegions(charStartIndex, charLength) - .FirstOrDefault(); - if (regions.Length > 0) - { - // Draw the mask for the current line - for (int j = 0; j < regions.Length; j++) - { - var region = regions[j]; - var rect = new Rect( - region.LayoutBounds.X, - region.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - region.LayoutBounds.Width, - region.LayoutBounds.Height - ); - ds.FillRectangle(rect, Color.FromArgb(255, 128, 128, 128)); - } - } - - double highlightTotalWidth = (double)highlightRegion.LayoutBounds.Width; - // Draw the highlight for the current character - double highlightWidth = highlightTotalWidth * charProgress; - - double fadingWidth = (double)highlightRegion.LayoutBounds.Height / 2; - - // Rects - var highlightRect = new Rect( - highlightRegion.LayoutBounds.X, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - highlightWidth, - highlightRegion.LayoutBounds.Height - ); - - var fadeInRect = new Rect( - highlightRect.Right - fadingWidth, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - fadingWidth, - highlightRegion.LayoutBounds.Height - ); - - ds.FillRectangle(highlightRect, Color.FromArgb(255, 128, 128, 128)); - - if (fade) - { - var fadeOutRect = new Rect( - highlightRect.Right, - highlightRegion.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - fadingWidth, - highlightRegion.LayoutBounds.Height - ); - using var fadeOutBrush = CreateHorizontalFillBrush( - control, - [(0f, 1f), (1f, 0f)], - (double)highlightRect.Right, - fadingWidth - ); - ds.FillRectangle(fadeOutRect, fadeOutBrush); - } - - return mask; - } - - //public static Rect? GetLineRect(LyricsLine lyricsLine) - //{ - // if (lyricsLine.OriginalCanvasTextLayout == null) return null; - - // var regions = lyricsLine.OriginalCanvasTextLayout.GetCharacterRegions(0, lyricsLine.OriginalText.Length); - // if (regions.Length > 0) - // { - // for (int j = 0; j < regions.Length; j++) - // { - // var region = regions[j]; - // var rect = new Rect( - // region.LayoutBounds.X, - // region.LayoutBounds.Y + lyricsLine.OriginalPosition.Y, - // region.LayoutBounds.Width, - // region.LayoutBounds.Height - // ); - // ds.FillRectangle(rect, Colors.White); - // } - // } - - // return mask; - //} - - public static CanvasCommandList CreatePhoneticHighlightMask(ICanvasAnimatedControl control, LyricsLine lyricsLine) - { - var mask = new CanvasCommandList(control); - using var ds = mask.CreateDrawingSession(); - - if (lyricsLine.PhoneticCanvasTextLayout == null) - { - return mask; - } - - var regions = lyricsLine.PhoneticCanvasTextLayout.GetCharacterRegions(0, lyricsLine.PhoneticText.Length); - if (regions.Length > 0) - { - for (int j = 0; j < regions.Length; j++) - { - var region = regions[j]; - var rect = new Rect( - region.LayoutBounds.X, - region.LayoutBounds.Y + lyricsLine.PhoneticPosition.Y, - region.LayoutBounds.Width, - region.LayoutBounds.Height - ); - ds.FillRectangle(rect, Colors.White); - } - } - - return mask; - } - - public static CanvasCommandList CreateTranslatedHighlightMask(ICanvasAnimatedControl control, LyricsLine lyricsLine) - { - var mask = new CanvasCommandList(control); - using var ds = mask.CreateDrawingSession(); - - if (lyricsLine.TranslatedCanvasTextLayout == null) - { - return mask; - } - - var regions = lyricsLine.TranslatedCanvasTextLayout.GetCharacterRegions(0, lyricsLine.TranslatedText.Length); - if (regions.Length > 0) - { - for (int j = 0; j < regions.Length; j++) - { - var region = regions[j]; - var rect = new Rect( - region.LayoutBounds.X, - region.LayoutBounds.Y + lyricsLine.TranslatedPosition.Y, - region.LayoutBounds.Width, - region.LayoutBounds.Height - ); - ds.FillRectangle(rect, Colors.White); - } - } - - return mask; - } - - /// - /// 创建高亮效果层 - /// - /// - /// - public static OpacityEffect CreateForegroundHighlightEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity) - { - return new OpacityEffect - { - Source = new AlphaMaskEffect - { - Source = foregroundFontEffect, - AlphaMask = mask, - }, - Opacity = (float)Math.Clamp(opacity, 0, 1), - }; - } - public static ShadowEffect CreateForegroundShadowEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, Color shadowColor, double shadowAmount) { return new ShadowEffect @@ -340,29 +32,5 @@ namespace BetterLyrics.WinUI3.Helper }; } - public static OpacityEffect CreateForegroundTranslationEffect(CanvasCommandList foregroundFontEffect, IGraphicsEffectSource mask, double opacity) - { - return new OpacityEffect - { - Source = new AlphaMaskEffect - { - Source = foregroundFontEffect, - AlphaMask = mask, - }, - Opacity = (float)Math.Clamp(opacity, 0, 1), - }; - } - - public static IGraphicsEffectSource GetAlphaMask(ICanvasAnimatedControl control, IGraphicsEffectSource charMask, IGraphicsEffectSource lineStartToCharMask, IGraphicsEffectSource lineMask, LineRenderingType lineRenderingType) - { - var result = lineRenderingType switch - { - LineRenderingType.CurrentChar => charMask, - LineRenderingType.LineStartToCurrentChar => lineStartToCharMask, - LineRenderingType.CurrentLine => lineMask, - _ => new CanvasCommandList(control), - }; - return result; - } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsAnimator.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsAnimator.cs index acaefdc..9d2bfe9 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsAnimator.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsAnimator.cs @@ -54,9 +54,7 @@ namespace BetterLyrics.WinUI3.Logic line.BlurAmountTransition.StartTransition(5 * distanceFactor); line.ScaleTransition.StartTransition(_highlightedScale - distanceFactor * (_highlightedScale - _defaultScale)); - line.PhoneticTextOpacityTransition.StartTransition(absLineCountDelta == 0 ? 0.3 : (1 - distanceFactor) * 0.3); - line.OriginalTextOpacityTransition.StartTransition(absLineCountDelta == 0 ? 1 : (1 - distanceFactor) * 0.3); - line.TranslatedTextOpacityTransition.StartTransition(absLineCountDelta == 0 ? 0.3 : (1 - distanceFactor) * 0.3); + line.OpacityTransition.StartTransition(absLineCountDelta == 0 ? 1 : (1 - distanceFactor) * 0.3); double yScrollDuration; double yScrollDelay; @@ -88,16 +86,13 @@ namespace BetterLyrics.WinUI3.Logic line.YOffsetTransition.SetEasingType(canvasYScrollTransition.EasingType); line.YOffsetTransition.SetDuration(yScrollDuration); line.YOffsetTransition.SetDelay(yScrollDelay); - //line.YOffsetTransition.StartTransition(_canvasTargetYScrollOffset, _isLayoutChanged); line.YOffsetTransition.StartTransition(targetYScrollOffset); } line.AngleTransition.Update(elapsedTime); line.ScaleTransition.Update(elapsedTime); line.BlurAmountTransition.Update(elapsedTime); - line.PhoneticTextOpacityTransition.Update(elapsedTime); - line.OriginalTextOpacityTransition.Update(elapsedTime); - line.TranslatedTextOpacityTransition.Update(elapsedTime); + line.OpacityTransition.Update(elapsedTime); line.YOffsetTransition.Update(elapsedTime); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsLayoutManager.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsLayoutManager.cs index ed7cf42..b8226fb 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsLayoutManager.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsLayoutManager.cs @@ -12,6 +12,17 @@ namespace BetterLyrics.WinUI3.Logic { public class LyricsLayoutManager { + /// + /// 重排歌词,Y 轴从 0 刻度开始算 + /// + /// + /// + /// + /// + /// + /// + /// + /// public void MeasureAndArrange( ICanvasAnimatedControl resourceCreator, LyricsData? lyricsData, @@ -19,7 +30,8 @@ namespace BetterLyrics.WinUI3.Logic AppSettings appSettings, double canvasWidth, double canvasHeight, - double lyricsWidth) + double lyricsWidth, + double lyricsHeight) { if (lyricsData == null || resourceCreator == null) return; @@ -55,13 +67,16 @@ namespace BetterLyrics.WinUI3.Logic phoneticFontSize, originalFontSize, translatedFontSize, fontWeight, style.LyricsCJKFontFamily, style.LyricsWesternFontFamily, - lyricsWidth, canvasHeight, style.LyricsAlignmentType + lyricsWidth, lyricsHeight, style.LyricsAlignmentType ); line.RecreateTextGeometry(); + // 顶部坐标 + line.TopPosition = new Vector2(0, (float)currentY); + // 注音层 - line.PhoneticPosition = new Vector2(0, (float)currentY); + line.PhoneticPosition = line.TopPosition; if (line.PhoneticCanvasTextLayout != null) { currentY += line.PhoneticCanvasTextLayout.LayoutBounds.Height; @@ -88,6 +103,9 @@ namespace BetterLyrics.WinUI3.Logic currentY += line.TranslatedCanvasTextLayout.LayoutBounds.Height; } + // 底部坐标 + line.BottomPosition = new Vector2(0, (float)currentY); + // 行间距 if (line.OriginalCanvasTextLayout != null) { @@ -100,7 +118,7 @@ namespace BetterLyrics.WinUI3.Logic } /// - /// 计算当前应该滚动到的目标 Y 轴偏移量 + /// 计算为了让当前歌词行的竖直几何中心点对齐到 0(原点),画布应该移动的距离(从画布最初始状态计算的值) /// public double? CalculateTargetScrollOffset( LyricsData? lyricsData, @@ -115,10 +133,10 @@ namespace BetterLyrics.WinUI3.Logic if (currentLine?.OriginalCanvasTextLayout == null || firstLine == null) return null; return -currentLine.OriginalPosition.Y - + firstLine.OriginalPosition.Y - - (currentLine.TranslatedPosition.Y - + (currentLine.TranslatedCanvasTextLayout?.LayoutBounds.Height ?? 0) - - currentLine.PhoneticPosition.Y) / 2.0; + + firstLine.OriginalPosition.Y + - (currentLine.TranslatedPosition.Y + + (currentLine.TranslatedCanvasTextLayout?.LayoutBounds.Height ?? 0) + - currentLine.PhoneticPosition.Y) / 2.0; } /// @@ -128,14 +146,16 @@ namespace BetterLyrics.WinUI3.Logic public (int Start, int End) CalculateVisibleRange( IList? lines, double currentScrollOffset, + double lyricsY, + double lyricsHeight, double canvasHeight) { if (lines == null || lines.Count == 0) return (-1, -1); - double offset = currentScrollOffset + canvasHeight / 2; + double offset = currentScrollOffset + lyricsY + lyricsHeight / 2; - int start = FindFirstVisibleLine(lines, offset); - int end = FindLastVisibleLine(lines, offset, canvasHeight); + int start = FindFirstVisibleLine(lines, offset, lyricsY); + int end = FindLastVisibleLine(lines, offset, lyricsY, lyricsHeight, canvasHeight); // 修正边界情况 if (start != -1 && end == -1) @@ -146,7 +166,7 @@ namespace BetterLyrics.WinUI3.Logic return (start, end); } - private int FindFirstVisibleLine(IList lines, double offset) + private int FindFirstVisibleLine(IList lines, double offset, double lyricsY) { int left = 0, right = lines.Count - 1, result = -1; while (left <= right) @@ -154,14 +174,16 @@ namespace BetterLyrics.WinUI3.Logic int mid = (left + right) / 2; var line = lines[mid]; if (line.OriginalCanvasTextLayout == null) break; - double value = offset + line.OriginalPosition.Y + (double)line.OriginalCanvasTextLayout.LayoutBounds.Height; + double value = offset + line.BottomPosition.Y; + // 理论上说应该使用下面这一行来精确计算视野内的首个可见行,但是考虑到动画视觉效果,还是注释掉了 + //if (value >= lyricsY) { result = mid; right = mid - 1; } if (value >= 0) { result = mid; right = mid - 1; } else { left = mid + 1; } } return result; } - private int FindLastVisibleLine(IList lines, double offset, double canvasHeight) + private int FindLastVisibleLine(IList lines, double offset, double lyricsY, double lyricsHeight, double canvasHeight) { int left = 0, right = lines.Count - 1, result = -1; while (left <= right) @@ -169,7 +191,9 @@ namespace BetterLyrics.WinUI3.Logic int mid = (left + right) / 2; var line = lines[mid]; if (line.OriginalCanvasTextLayout == null) break; - double value = offset + line.OriginalPosition.Y + (double)line.OriginalCanvasTextLayout.LayoutBounds.Height; + double value = offset + line.BottomPosition.Y; + // 同理 + //if (value >= lyricsY + lyricsHeight) { result = mid; right = mid - 1; } if (value >= canvasHeight) { result = mid; right = mid - 1; } else { left = mid + 1; } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsSynchronizer.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsSynchronizer.cs index 4762fbb..4636c86 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsSynchronizer.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Logic/LyricsSynchronizer.cs @@ -19,13 +19,13 @@ namespace BetterLyrics.WinUI3.Logic if (lyricsData == null || lyricsData.LyricsLines.Count == 0) return 0; var lines = lyricsData.LyricsLines; - //// Cache hit - //if (IsTimeInLine(currentTimeMs, lines, _lastFoundIndex)) return _lastFoundIndex; - //if (_lastFoundIndex + 1 < lines.Count && IsTimeInLine(currentTimeMs, lines, _lastFoundIndex + 1)) - //{ - // _lastFoundIndex++; - // return _lastFoundIndex; - //} + // Cache hit + if (IsTimeInLine(currentTimeMs, lines, _lastFoundIndex)) return _lastFoundIndex; + if (_lastFoundIndex + 1 < lines.Count && IsTimeInLine(currentTimeMs, lines, _lastFoundIndex + 1)) + { + _lastFoundIndex++; + return _lastFoundIndex; + } // Cache miss for (int i = 0; i < lines.Count; i++) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs index 10ab5ec..3f2a79e 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsLine.cs @@ -17,9 +17,7 @@ namespace BetterLyrics.WinUI3.Models public double AnimationDuration { get; set; } = 0.3; public ValueTransition AngleTransition { get; set; } public ValueTransition BlurAmountTransition { get; set; } - public ValueTransition PhoneticTextOpacityTransition { get; set; } - public ValueTransition OriginalTextOpacityTransition { get; set; } - public ValueTransition TranslatedTextOpacityTransition { get; set; } + public ValueTransition OpacityTransition { get; set; } public ValueTransition ScaleTransition { get; set; } public ValueTransition YOffsetTransition { get; set; } @@ -27,20 +25,32 @@ namespace BetterLyrics.WinUI3.Models public CanvasTextLayout? TranslatedCanvasTextLayout { get; private set; } public CanvasTextLayout? PhoneticCanvasTextLayout { get; private set; } - public Vector2 CenterPosition { get; private set; } /// - /// 原文位置 + /// 原文坐标(相对于坐标原点) /// public Vector2 OriginalPosition { get; set; } /// - /// 译文位置 + /// 译文坐标(相对于坐标原点) /// public Vector2 TranslatedPosition { get; set; } /// - /// 注音位置 + /// 注音坐标(相对于坐标原点) /// public Vector2 PhoneticPosition { get; set; } + /// + /// 顶部坐标(相对于坐标原点) + /// + public Vector2 TopPosition { get; set; } + /// + /// 中心坐标(相对于坐标原点) + /// + public Vector2 CenterPosition { get; private set; } + /// + /// 底部坐标(相对于坐标原点) + /// + public Vector2 BottomPosition { get; set; } + public List LyricsSyllables { get; set; } = []; public int? DurationMs => EndMs - StartMs; @@ -76,17 +86,7 @@ namespace BetterLyrics.WinUI3.Models durationSeconds: AnimationDuration, easingType: EasingType.EaseInOutQuad ); - PhoneticTextOpacityTransition = new( - initialValue: 0, - durationSeconds: AnimationDuration, - easingType: EasingType.EaseInOutQuad - ); - OriginalTextOpacityTransition = new( - initialValue: 0, - durationSeconds: AnimationDuration, - easingType: EasingType.EaseInOutQuad - ); - TranslatedTextOpacityTransition = new( + OpacityTransition = new( initialValue: 0, durationSeconds: AnimationDuration, easingType: EasingType.EaseInOutQuad @@ -110,13 +110,13 @@ namespace BetterLyrics.WinUI3.Models return; } - double centerY = OriginalPosition.Y + (OriginalCanvasTextLayout?.LayoutBounds.Height ?? 0) / 2; + double centerY = (TopPosition.Y + BottomPosition.Y) / 2; CenterPosition = type switch { - TextAlignmentType.Left => new Vector2(OriginalPosition.X, (float)centerY), - TextAlignmentType.Center => new Vector2((float)(OriginalPosition.X + maxWidth / 2.0), (float)centerY), - TextAlignmentType.Right => new Vector2((float)(OriginalPosition.X + maxWidth), (float)centerY), + TextAlignmentType.Left => new Vector2(0, (float)centerY), + TextAlignmentType.Center => new Vector2((float)(0 + maxWidth / 2.0), (float)centerY), + TextAlignmentType.Right => new Vector2((float)(0 + maxWidth), (float)centerY), _ => throw new System.ArgumentOutOfRangeException(nameof(type), type, null), }; } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsWindowStatus.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsWindowStatus.cs index 758afc2..00aa636 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsWindowStatus.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsWindowStatus.cs @@ -3,6 +3,7 @@ using BetterLyrics.WinUI3.Hooks; using BetterLyrics.WinUI3.Models.Settings; using BetterLyrics.WinUI3.Views; using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.UI.Xaml; using System; using Windows.Foundation; @@ -35,11 +36,28 @@ namespace BetterLyrics.WinUI3.Models [ObservableProperty][NotifyPropertyChangedRecipients] public partial WindowPixelSampleMode EnvironmentSampleMode { get; set; } = WindowPixelSampleMode.WindowEdge; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoShowOrHideWindow { get; set; } = false; [ObservableProperty][NotifyPropertyChangedRecipients] public partial TitleBarArea TitleBarArea { get; set; } = TitleBarArea.Top; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowX { get; set; } = 100; [ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowY { get; set; } = 100; [ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowWidth { get; set; } = 800; [ObservableProperty][NotifyPropertyChangedRecipients] public partial double WindowHeight { get; set; } = 500; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LeftGapFactor { get; set; } = 12; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double TopGapFactor { get; set; } = 12; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double RightGapFactor { get; set; } = 12; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double BottomGapFactor { get; set; } = 12; + + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double MiddleColGapFactor { get; set; } = 12; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double MiddleRowGapFactor { get; set; } = 12; + + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double TrackSummaryColGapFactor { get; set; } = 38; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double TrackSummaryRowGapFactor { get; set; } = 19; + + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsColGapFactor { get; set; } = 38; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsRowGapFactor { get; set; } = 57; + + [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowLayoutIndicator { get; set; } = false; + public LyricsWindowStatus() { UpdateMonitorNameAndBounds(); @@ -191,11 +209,27 @@ namespace BetterLyrics.WinUI3.Models EnvironmentSampleMode = this.EnvironmentSampleMode, AutoShowOrHideWindow = this.AutoShowOrHideWindow, TitleBarArea = this.TitleBarArea, + WindowX = this.WindowX, WindowY = this.WindowY, WindowWidth = this.WindowWidth, WindowHeight = this.WindowHeight, + + LeftGapFactor = this.LeftGapFactor, + TopGapFactor = this.TopGapFactor, + RightGapFactor = this.RightGapFactor, + BottomGapFactor = this.BottomGapFactor, + + MiddleColGapFactor = this.MiddleColGapFactor, + MiddleRowGapFactor = this.MiddleRowGapFactor, + + TrackSummaryColGapFactor = this.TrackSummaryColGapFactor, + TrackSummaryRowGapFactor = this.TrackSummaryRowGapFactor, + + LyricsColGapFactor = this.LyricsColGapFactor, + LyricsRowGapFactor = this.LyricsRowGapFactor, }; + } } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Settings/AlbumArtLayoutSettings.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Settings/AlbumArtLayoutSettings.cs index 0b0f4c0..134ada4 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Settings/AlbumArtLayoutSettings.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/Settings/AlbumArtLayoutSettings.cs @@ -1,5 +1,6 @@ using BetterLyrics.WinUI3.Enums; using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.UI.Xaml; using System; namespace BetterLyrics.WinUI3.Models.Settings @@ -7,16 +8,17 @@ namespace BetterLyrics.WinUI3.Models.Settings public partial class AlbumArtLayoutSettings : ObservableRecipient, ICloneable { [ObservableProperty][NotifyPropertyChangedRecipients] public partial TextAlignmentType SongInfoAlignmentType { get; set; } = TextAlignmentType.Left; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial HorizontalAlignment AlbumArtAlignmentType { get; set; } = HorizontalAlignment.Center; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageRadius { get; set; } = 12; // 12 % of the cover image size [ObservableProperty][NotifyPropertyChangedRecipients] public partial int CoverImageShadowAmount { get; set; } = 12; + [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool IsAutoSongInfoFontSize { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial int SongInfoFontSize { get; set; } = 18; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowTitle { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowArtists { get; set; } = true; [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool ShowAlbum { get; set; } = false; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial int AlbumArtSize { get; set; } = 64; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial bool AutoAlbumArtSize { get; set; } = true; - + public AlbumArtLayoutSettings() { } public object Clone() @@ -24,6 +26,7 @@ namespace BetterLyrics.WinUI3.Models.Settings return new AlbumArtLayoutSettings { SongInfoAlignmentType = this.SongInfoAlignmentType, + AlbumArtAlignmentType = this.AlbumArtAlignmentType, CoverImageRadius = this.CoverImageRadius, CoverImageShadowAmount = this.CoverImageShadowAmount, IsAutoSongInfoFontSize = this.IsAutoSongInfoFontSize, @@ -31,8 +34,6 @@ namespace BetterLyrics.WinUI3.Models.Settings ShowTitle = this.ShowTitle, ShowArtists = this.ShowArtists, ShowAlbum = this.ShowAlbum, - AlbumArtSize = this.AlbumArtSize, - AutoAlbumArtSize = this.AutoAlbumArtSize, }; } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/LyricsRenderer.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/LyricsRenderer.cs index e0d3f33..74b53c3 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/LyricsRenderer.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/LyricsRenderer.cs @@ -28,59 +28,66 @@ namespace BetterLyrics.WinUI3.Renderer int playingLineIndex, int startVisibleIndex, int endVisibleIndex, - double canvasHeight, double lyricsX, + double lyricsY, double lyricsWidth, + double lyricsHeight, + double lyricsOpacity, LyricsWindowStatus windowStatus, Color strokeColor, Color bgColor, Func getPlaybackState) { - if (windowStatus.LyricsEffectSettings.Is3DLyricsEnabled) + using (var opacityLayer = ds.CreateLayer((float)lyricsOpacity)) { - using (var layer = new CanvasCommandList(control)) + if (windowStatus.LyricsEffectSettings.Is3DLyricsEnabled) { - using (var layerDs = layer.CreateDrawingSession()) + using (var layer = new CanvasCommandList(control)) { - DrawLyrics( - control, - layerDs, - lyricsData, - playingLineIndex, - startVisibleIndex, - endVisibleIndex, - canvasHeight, - lyricsX, - lyricsWidth, - windowStatus, - strokeColor, - bgColor, - getPlaybackState); - } + using (var layerDs = layer.CreateDrawingSession()) + { + DrawLyrics( + control, + layerDs, + lyricsData, + playingLineIndex, + startVisibleIndex, + endVisibleIndex, + lyricsX, + lyricsY, + lyricsWidth, + lyricsHeight, + windowStatus, + strokeColor, + bgColor, + getPlaybackState); + } - ds.DrawImage(new Transform3DEffect - { - Source = layer, - TransformMatrix = _threeDimMatrix - }); + ds.DrawImage(new Transform3DEffect + { + Source = layer, + TransformMatrix = _threeDimMatrix + }); + } + } + else + { + DrawLyrics( + control, + ds, + lyricsData, + playingLineIndex, + startVisibleIndex, + endVisibleIndex, + lyricsX, + lyricsY, + lyricsWidth, + lyricsHeight, + windowStatus, + strokeColor, + bgColor, + getPlaybackState); } - } - else - { - DrawLyrics( - control, - ds, - lyricsData, - playingLineIndex, - startVisibleIndex, - endVisibleIndex, - canvasHeight, - lyricsX, - lyricsWidth, - windowStatus, - strokeColor, - bgColor, - getPlaybackState); } } @@ -91,9 +98,10 @@ namespace BetterLyrics.WinUI3.Renderer int playingLineIndex, int startVisibleIndex, int endVisibleIndex, - double canvasHeight, double lyricsX, + double lyricsY, double lyricsWidth, + double lyricsHeight, LyricsWindowStatus windowStatus, Color strokeColor, Color bgColor, @@ -117,7 +125,7 @@ namespace BetterLyrics.WinUI3.Renderer if (line.OriginalCanvasTextLayout == null) continue; if (line.OriginalCanvasTextLayout.LayoutBounds.Width <= 0) continue; - double yOffset = line.YOffsetTransition.Value + canvasHeight / 2; + double yOffset = line.YOffsetTransition.Value + lyricsY + lyricsHeight / 2; var transform = Matrix3x2.CreateScale((float)line.ScaleTransition.Value, line.CenterPosition) * diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/PlayingLineRenderer.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/PlayingLineRenderer.cs index 7f11ffd..097354f 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/PlayingLineRenderer.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/PlayingLineRenderer.cs @@ -14,6 +14,7 @@ using System.Numerics; using System.Text; using Windows.Foundation; using Windows.UI; +using static Vanara.PInvoke.Kernel32; namespace BetterLyrics.WinUI3.Renderer { @@ -36,7 +37,7 @@ namespace BetterLyrics.WinUI3.Renderer { if (line.PhoneticCanvasTextLayout == null) return; - var opacity = line.PhoneticTextOpacityTransition.Value; + var opacity = line.OpacityTransition.Value * 0.3; var blur = line.BlurAmountTransition.Value; var bounds = line.PhoneticCanvasTextLayout.LayoutBounds; @@ -62,7 +63,7 @@ namespace BetterLyrics.WinUI3.Renderer { if (line.TranslatedCanvasTextLayout == null) return; - var opacity = line.TranslatedTextOpacityTransition.Value; + var opacity = line.OpacityTransition.Value * 0.3; var blur = line.BlurAmountTransition.Value; var bounds = line.TranslatedCanvasTextLayout.LayoutBounds; @@ -94,7 +95,7 @@ namespace BetterLyrics.WinUI3.Renderer { if (line.OriginalCanvasTextLayout == null) return; - var originalTextOpacity = line.OriginalTextOpacityTransition.Value; + var opacity = line.OpacityTransition.Value; var curCharIndex = state.SyllableStartIndex + state.SyllableLength * state.SyllableProgress; float fadeWidth = (1f / Math.Max(1, line.OriginalText.Length)) * 0.5f; @@ -103,7 +104,7 @@ namespace BetterLyrics.WinUI3.Renderer foreach (var subLineRegion in lineRegions) { - DrawSubLineRegion(resourceCreator, ds, source, line, subLineRegion, curCharIndex, fadeWidth, originalTextOpacity, state, settings); + DrawSubLineRegion(resourceCreator, ds, source, line, subLineRegion, curCharIndex, fadeWidth, opacity, state, settings); } } @@ -115,7 +116,7 @@ namespace BetterLyrics.WinUI3.Renderer CanvasTextLayoutRegion subLineRegion, double curCharIndex, float fadeWidth, - double originalTextOpacity, + double opacity, LinePlaybackState state, LyricsEffectSettings settings) { @@ -134,13 +135,13 @@ namespace BetterLyrics.WinUI3.Renderer float progressInRegion = (float)((curCharIndex - subLineRegion.CharacterIndex) / subLineRegion.CharacterCount); progressInRegion = Math.Clamp(progressInRegion, 0, 1 + fadeWidth); - var stop1 = Colors.White.WithAlpha((byte)(255 * originalTextOpacity)); - var stop2 = Color.FromArgb((byte)(255 * Math.Min(0.3, originalTextOpacity)), 255, 255, 255); + var stop1 = Colors.White.WithAlpha((byte)(255 * opacity)); + var stop2 = Color.FromArgb((byte)(255 * Math.Min(0.3, opacity)), 255, 255, 255); using (var maskBrush = new CanvasLinearGradientBrush(resourceCreator, [ - new CanvasGradientStop { Position = 0, Color = stop1 }, - new CanvasGradientStop { Position = progressInRegion, Color = stop1 }, + new CanvasGradientStop { Position = - fadeWidth, Color = stop1 }, + new CanvasGradientStop { Position = - fadeWidth + progressInRegion, Color = stop1 }, new CanvasGradientStop { Position = progressInRegion + fadeWidth, Color = stop2 }, new CanvasGradientStop { Position = 1 + fadeWidth, Color = stop2 } ])) diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/UnplayingLineRenderer.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/UnplayingLineRenderer.cs index 4363f8d..2bcf0f5 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/UnplayingLineRenderer.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Renderer/UnplayingLineRenderer.cs @@ -15,6 +15,7 @@ namespace BetterLyrics.WinUI3.Renderer LyricsLine line) { var blurAmount = (float)line.BlurAmountTransition.Value; + var opacity = line.OpacityTransition.Value; if (line.PhoneticCanvasTextLayout != null) { @@ -22,7 +23,7 @@ namespace BetterLyrics.WinUI3.Renderer line.PhoneticCanvasTextLayout, line.PhoneticPosition, blurAmount, - (float)line.PhoneticTextOpacityTransition.Value); + (float)opacity * 0.3f); } if (line.OriginalCanvasTextLayout != null) @@ -31,7 +32,7 @@ namespace BetterLyrics.WinUI3.Renderer line.OriginalCanvasTextLayout, line.OriginalPosition, blurAmount, - (float)line.OriginalTextOpacityTransition.Value); + (float)opacity); } if (line.TranslatedCanvasTextLayout != null) @@ -40,7 +41,7 @@ namespace BetterLyrics.WinUI3.Renderer line.TranslatedCanvasTextLayout, line.TranslatedPosition, blurAmount, - (float)line.TranslatedTextOpacityTransition.Value); + (float)opacity * 0.3f); } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs index cd9f17a..7550b60 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LyricsSearchService/LyricsSearchService.cs @@ -562,7 +562,11 @@ namespace BetterLyrics.WinUI3.Services.LyricsSearchService ISearchResult? result; if (searcher == Searchers.Netease && songInfo.SongId != null) { - result = new NeteaseSearchResult(songInfo.Title, songInfo.Artists, songInfo.Album, songInfo.Artists, (int)songInfo.DurationMs, songInfo.SongId); + result = new NeteaseSearchResult("", [], "", [], 0, songInfo.SongId); + } + else if (searcher == Searchers.QQMusic && songInfo.SongId != null) + { + result = new QQMusicSearchResult("", [], "", [], 0, songInfo.SongId, ""); } else { diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.LyricsUpdater.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.LyricsUpdater.cs index bfa1c59..af7dffc 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.LyricsUpdater.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.LyricsUpdater.cs @@ -45,7 +45,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService TranslationSearchProvider = null; _lyricsDataArr.ElementAtOrDefault(0)?.ClearTranslatedText(); - SetCurrentLyricsData(); + App.Current.Resources.DispatcherQueue.TryEnqueue(SetCurrentLyricsData); IsTranslating = true; @@ -55,7 +55,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService IsTranslating = false; - SetCurrentLyricsData(); + App.Current.Resources.DispatcherQueue.TryEnqueue(SetCurrentLyricsData); } @@ -153,7 +153,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService CurrentLyricsSearchResult = null; _lyricsDataArr = [LyricsData.GetLoadingPlaceholder()]; - SetCurrentLyricsData(); + App.Current.Resources.DispatcherQueue.TryEnqueue(SetCurrentLyricsData); if (CurrentSongInfo != null) { @@ -176,10 +176,7 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService // Show original first while loading phonetic and translated ApplyChinesePreference(); - _dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => - { - LyricsChanged?.Invoke(this, new LyricsChangedEventArgs(CurrentLyricsData)); - }); + App.Current.Resources.DispatcherQueue.TryEnqueue(SetCurrentLyricsData); UpdateTranslations(); } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs index 92faee8..dccde11 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs @@ -335,6 +335,12 @@ namespace BetterLyrics.WinUI3.Services.MediaSessionsService .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.NetEaseCloudMusicTrackID))? .Replace(ExtendedGenreFiled.NetEaseCloudMusicTrackID, ""); } + else if (sessionId == PlayerID.QQMusic) + { + songId = mediaProperties?.Genres + .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.QQMusicTrackID))? + .Replace(ExtendedGenreFiled.QQMusicTrackID, ""); + } var linkedFileName = mediaProperties?.Genres .FirstOrDefault(x => x.StartsWith(ExtendedGenreFiled.FileName))? diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw index f0f4a4e..2115721 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/en-US/Resources.resw @@ -130,7 +130,7 @@ Picture-in-picture mode - General + Window When typing multiple artists, please separate them with one of the following delimiters (do not mix them) @@ -607,6 +607,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Album art area style + + Alignment + Base URL @@ -664,12 +667,18 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Borderless lyrics window shortcut + + Bottom gap height factor + Including log files, network lyrics cache Cache + + Center + Chinese pronunciation @@ -859,6 +868,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Fullscreen mode + + General layout factor + Height @@ -871,6 +883,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Hold here and drag to sort + + Horizontal layout factor + Import @@ -925,6 +940,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Username + + Layout + Layout orientation @@ -934,6 +952,12 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Vertical + + Left + + + Left gap area width factor + Server address @@ -982,8 +1006,8 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Bold - - Center + + Lyrics area width factor Lyrics effect @@ -1075,8 +1099,8 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Current line start to current char - - Right + + Lyrics area height factor Enable scaling for syllables with long duration @@ -1165,6 +1189,12 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Mica Alt + + Middle area gap width factor + + + Middle gap area height factor + Play test music @@ -1282,6 +1312,12 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Restart app to apply change + + Right + + + Right gap area width factor + Japanese annotation @@ -1351,6 +1387,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Show in system environment + + Show layout splitter + Show title @@ -1363,18 +1402,6 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Song info - - Alignment - - - Center - - - Left - - - Right - Current song @@ -1435,6 +1462,15 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Switch in and cut out shortcut keys + + Top gap area height factor + + + Track summary area width factor + + + Track summary area height factor + Translated text @@ -1453,6 +1489,9 @@ If you encounter any problems, please go to the Settings page, About tab, and vi Version + + Vertical layout factor + Latin alphabet diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw index 5c441f4..6ce1d88 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ja-JP/Resources.resw @@ -130,7 +130,7 @@ ピクチャーインピクチャーモード - 一般的な + ウィンドウ 複数のアーティストを入力する場合は、次の区切り記号のいずれかで区切ってください(混在しないでください) @@ -607,6 +607,9 @@ アルバムエリアスタイル + + アライメント + ベースURL @@ -664,12 +667,18 @@ ボーダーレス歌詞ウィンドウショートカット + + ボトムギャップハイトファクター + ログファイル、ネットワーク歌詞キャッシュを含む キャッシュ + + 中心 + 中国の発音 @@ -859,6 +868,9 @@ フルスクリーンモード + + 一般的なレイアウトファクター + 高さ @@ -871,6 +883,9 @@ ここを長押ししてドラッグして並べ替えましょう + + 水平レイアウト係数 + インポート @@ -925,6 +940,9 @@ ユーザー名 + + レイアウト + レイアウトの向き @@ -934,6 +952,9 @@ 垂直方向 + + 左ギャップエリア幅係数 + サーバーアドレス @@ -982,8 +1003,8 @@ 大胆な - - 中心 + + 歌詞エリア幅係数 歌詞効果 @@ -1045,9 +1066,6 @@ オリジナルのハイライト範囲 - - - ライト @@ -1075,8 +1093,14 @@ 現在のラインが現在の文字から始まります - - + + 歌詞エリアの高さ係数 + + + 長時間の音節のスケーリングを有効にします + + + スケール効果 ベストマッチ @@ -1159,6 +1183,12 @@ マイカル + + ミドルエリアギャップ幅係数 + + + ミドルギャップエリアハイトファクター + テスト音楽を再生します @@ -1276,6 +1306,9 @@ 変更を適用するためのアプリを再起動します + + 右ギャップエリア幅係数 + 日本の注釈 @@ -1345,6 +1378,9 @@ システム環境に表示します + + レイアウトスプリッターを表示 + タイトルを表示 @@ -1357,16 +1393,10 @@ 曲情報 - - アライメント - - - 中心 - - + - + @@ -1429,6 +1459,15 @@ ショートカットキーを切り込んで切り取ります + + トップギャップエリアの高さ係数 + + + トラックサマリーエリア幅係数 + + + トラックサマリーエリアの高さ係数 + 译文 @@ -1447,6 +1486,9 @@ バージョン + + 垂直レイアウト係数 + 英字 @@ -1513,4 +1555,7 @@ 利用案内 + + + \ 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 4331084..d9f71bd 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/ko-KR/Resources.resw @@ -130,7 +130,7 @@ 사진 인당 모드 - 일반적인 + 윈도우 여러 아티스트를 입력할 때 다음 구분 기호 중 하나로 구분하십시오 (혼합하지 마십시오) @@ -607,6 +607,9 @@ 앨범 영역 스타일 + + 조정 + 기본 URL @@ -664,12 +667,18 @@ 테두리 없는 가사 창 단축키 + + 하단 간격 높이 계수 + 로그 파일, 네트워크 가사 캐시 포함 은닉처 + + 센터 + 화음 @@ -859,6 +868,9 @@ 전체화면 모드 + + 일반 레이아웃 요소 + 신장 @@ -871,6 +883,9 @@ 여기를 누른 상태에서 드래그하여 정렬하세요 + + 수평 레이아웃 요소 + 가져오기 @@ -925,6 +940,9 @@ 사용자 이름 + + 레이아웃 + 레이아웃 방향 @@ -934,6 +952,9 @@ 세로 + + 왼쪽 갭 영역 너비 계수 + 서버 주소 @@ -982,8 +1003,8 @@ 용감한 - - 센터 + + 가사 영역 너비 계수 가사 효과 @@ -1045,9 +1066,6 @@ 원래 하이라이트 범위 - - 왼쪽 - @@ -1075,8 +1093,14 @@ 현재 라인은 현재 숯으로 시작합니다 - - 오른쪽 + + 가사 영역 높이 계수 + + + 장시간 음절 배율을 조정할 수 있습니다 + + + 스케일 효과 최상의 검색 결과 @@ -1159,6 +1183,12 @@ 운모 대체 + + 중간 영역 갭 폭 계수 + + + 중간 간격 영역 높이 계수 + 테스트 음악을 재생하십시오 @@ -1276,6 +1306,9 @@ 변경 사항을 적용하려면 앱을 다시 시작하십시오 + + 오른쪽 간격 영역 너비 계수 + 일본 주석 @@ -1345,6 +1378,9 @@ 시스템 환경에서 보여주세요 + + 레이아웃 스플리터 표시 + 제목 표시 @@ -1357,16 +1393,10 @@ 노래 정보 - - 조정 - - - 센터 - - + 왼쪽 - + 오른쪽 @@ -1429,6 +1459,15 @@ 바로 가기 키를 자르고 잘라냅니다 + + 상단 간격 영역 높이 계수 + + + 트랙 요약 영역 너비 계수 + + + 트랙 요약 영역 높이 계수 + 번역 @@ -1447,6 +1486,9 @@ 버전 + + 수직 레이아웃 요소 + 라틴 알파벳 @@ -1513,4 +1555,7 @@ 사용 안내서 + + 왼쪽 + \ 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 0cee628..c5c38f7 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-CN/Resources.resw @@ -130,7 +130,7 @@ 画中画模式 - 通用 + 窗口 键入多位艺术家时请以下述一种分隔符分隔(不要混用) @@ -607,6 +607,9 @@ 专辑区域样式 + + 对齐方式 + 基本 URL @@ -664,12 +667,18 @@ 无边框歌词窗口快捷方式 + + 底部间隙高度因子 + 包括日志文件,网络歌词缓存 缓存 + + 居中 + 中文注音 @@ -859,6 +868,9 @@ 全屏模式 + + 一般布局系数 + 高度 @@ -871,6 +883,9 @@ 按住此处并拖动以排序 + + 水平布局系数 + 导入 @@ -925,6 +940,9 @@ 用户名 + + 布局 + 布局方向 @@ -934,6 +952,9 @@ 垂直 + + 左间隙区域宽度因子 + 服务器地址 @@ -982,8 +1003,8 @@ 粗体 - - 居中 + + 歌词区域宽度因子 歌词动效 @@ -1045,9 +1066,6 @@ 原文高亮显示范围 - - 靠左 - 细体 @@ -1075,8 +1093,14 @@ 当前歌词开始到当前字符 - - 靠右 + + 歌词区域高度因子 + + + 为持续时间较长的音节启用缩放 + + + 缩放效果 最佳匹配 @@ -1159,6 +1183,12 @@ 云母(替代样式) + + 中间区域间隙宽度系数 + + + 中间间隙区域高度系数 + 播放测试音乐 @@ -1276,6 +1306,9 @@ 重启应用以应用更改 + + 右间隙区域宽度因子 + 日语注音 @@ -1345,6 +1378,9 @@ 在系统环境中显示 + + 显示布局拆分器 + 显示标题 @@ -1357,16 +1393,10 @@ 歌曲信息 - - 对齐方式 - - - 居中 - - + 靠左 - + 靠右 @@ -1429,6 +1459,15 @@ 切入与切出快捷键 + + 顶部间隙区域高度因子 + + + 曲目摘要区域宽度因子 + + + 曲目摘要区域高度系数 + 译文 @@ -1447,6 +1486,9 @@ 版本号 + + 垂直布局系数 + 拉丁字母 @@ -1513,4 +1555,7 @@ 使用指南 + + 靠左 + \ 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 b09f655..41918da 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Strings/zh-TW/Resources.resw @@ -130,7 +130,7 @@ 畫中畫模式 - 一般 + 视窗 鍵入多位藝術家時請以下述一種分隔符號分隔(不要混用) @@ -607,6 +607,9 @@ 專輯區域樣式 + + 對齊方式 + 基本網址 @@ -664,12 +667,18 @@ 無邊框歌詞視窗捷徑 + + 底部間隙高度因子 + 包括日誌文件,網絡歌詞緩存 快取 + + 居中 + 中文注音 @@ -859,6 +868,9 @@ 全螢幕模式 + + 一般布局系數 + 高度 @@ -871,6 +883,9 @@ 按住這裡並拖曳以進行排序 + + 水平布局系數 + 匯入 @@ -925,6 +940,9 @@ 使用者名稱 + + 佈局 + 版面配置方向 @@ -934,6 +952,9 @@ 縱向 + + 左間隙區域寬度因子 + 服務器地址 @@ -982,8 +1003,8 @@ 粗體 - - 居中 + + 歌詞區域寬度因子 歌詞動效 @@ -1045,9 +1066,6 @@ 原文高亮顯示範圍 - - 靠左 - 細體 @@ -1075,8 +1093,14 @@ 當前歌詞開始到當前字符 - - 靠右 + + 歌詞區域高度因子 + + + 啟用長期音節的縮放功能 + + + 縮放效果 最佳匹配 @@ -1159,6 +1183,12 @@ 雲母(替代樣式) + + 中間區域間隙寬度因子 + + + 中間間隙區域高度因子 + 播放測試音樂 @@ -1276,6 +1306,9 @@ 重啟應用程式以應用更改 + + 右間隙區域寬度因子 + 日語注音 @@ -1334,7 +1367,7 @@ 顯示專輯 - 界面設計 + 顯示藝術家 歌詞窗口顯示和隱藏快捷鍵 @@ -1345,6 +1378,9 @@ 在系統環境中顯示 + + 顯示佈局拆分器 + 顯示標題 @@ -1357,16 +1393,10 @@ 歌曲資訊 - - 對齊方式 - - - 居中 - - + 靠左 - + 靠右 @@ -1429,6 +1459,15 @@ 切入與切出快捷鍵 + + 頂部間隙區域高度因子 + + + 曲目摘要區域寬度因子 + + + 曲目摘要區域高度因子 + 譯文 @@ -1447,6 +1486,9 @@ 版本號 + + 垂直布局系數 + 拉丁字母 @@ -1513,4 +1555,7 @@ 使用手冊 + + 靠左 + \ 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 bf97255..3409cd5 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/ViewModels/LyricsPageViewModel.cs @@ -26,35 +26,14 @@ using Windows.Storage.Streams; namespace BetterLyrics.WinUI3.ViewModels { - public partial class LyricsPageViewModel : BaseViewModel, - IRecipient>, - IRecipient>, - IRecipient> + public partial class LyricsPageViewModel : BaseViewModel { public IMediaSessionsService MediaSessionsService { get; private set; } private readonly ILiveStatesService _liveStatesService; - private readonly ThrottleHelper _timelineThrottle = new(TimeSpan.FromSeconds(1)); - - [ObservableProperty] public partial double AlbumArtWithSongInfoStackPanelHeight { get; set; } = 0; - - [ObservableProperty] public partial double LastAlbumArtOpacity { get; set; } = 1; - [ObservableProperty] public partial double AlbumArtOpacity { get; set; } = 1; - [ObservableProperty] public partial BitmapImage? LastAlbumArtBitmapImage { get; set; } - [ObservableProperty] public partial BitmapImage? AlbumArtBitmapImage { get; set; } - - [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsX { get; set; } = 0; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsY { get; set; } = 0; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsWidth { get; set; } = 0; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial double LyricsOpacity { get; set; } = 0; - [ObservableProperty][NotifyPropertyChangedRecipients] public partial Matrix4x4 Lyrics3DMatrix { get; set; } = Matrix4x4.Identity; - [ObservableProperty] public partial LiveStates LiveStates { get; set; } - [ObservableProperty] - public partial double TimelinePositionSeconds { get; set; } - [ObservableProperty] public partial int Volume { get; set; } @@ -73,9 +52,6 @@ namespace BetterLyrics.WinUI3.ViewModels [ObservableProperty] public partial double TimelineSliderThumbSeconds { get; set; } = 0; - [ObservableProperty] - public partial double SongInfoOpacity { get; set; } = 1; - public LyricsPageViewModel(IMediaSessionsService mediaSessionsService, ILiveStatesService liveStatesService) { _liveStatesService = liveStatesService; @@ -127,47 +103,5 @@ namespace BetterLyrics.WinUI3.ViewModels await MediaSessionsService.NextAsync(); } - public async void Receive(PropertyChangedMessage message) - { - if (message.Sender is IMediaSessionsService) - { - if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage)) - { - LastAlbumArtBitmapImage = AlbumArtBitmapImage; - LastAlbumArtOpacity = 1; - await Task.Delay(Constants.Time.AnimationDuration); - - AlbumArtOpacity = 0; - await Task.Delay(Constants.Time.AnimationDuration); - AlbumArtBitmapImage = message.NewValue; - - LastAlbumArtOpacity = 0; - AlbumArtOpacity = 1; - } - } - } - - public void Receive(PropertyChangedMessage message) - { - if (message.Sender is LyricsWindowStatus) - { - if (message.PropertyName == nameof(LyricsWindowStatus.LyricsLayoutOrientation)) - { - //OnLayoutChanged(); - } - } - } - - public void Receive(PropertyChangedMessage message) - { - if (message.Sender is LyricsWindowStatus) - { - if (message.PropertyName == nameof(LyricsWindowStatus.LyricsDisplayType)) - { - //OnLayoutChanged(); - } - } - } - } } diff --git a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml index 25372bd..85826af 100644 --- a/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml +++ b/BetterLyrics.WinUI3/BetterLyrics.WinUI3/Views/LyricsPage.xaml @@ -29,184 +29,263 @@ - - - - - + + + + + + + + + + + + + + + - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + >, IRecipient>, IRecipient>, - IRecipient> + IRecipient>, + IRecipient>, + IRecipient>, + IRecipient>, + IRecipient> { - private readonly ISettingsService _settingsService = Ioc.Default.GetRequiredService(); private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService(); private readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService(); - private double _leftMargin = 36f; - private double _middleMargin = 36f; - private double _rightMargin = 36f; - private double _topMargin = 36f; - private double _bottomMargin = 36f; - - private readonly DispatcherQueueTimer _rootGridSizeChangedTimer; - - public double AlbumArtSize - { - get { return (double)GetValue(AlbumArtSizeProperty); } - set { SetValue(AlbumArtSizeProperty, value); } - } - - public static readonly DependencyProperty AlbumArtSizeProperty = - DependencyProperty.Register(nameof(AlbumArtSize), typeof(double), typeof(NowPlayingCanvas), new PropertyMetadata(0.0)); + private double _startWidth; public CornerRadius AlbumArtCornerRadius { @@ -62,6 +52,16 @@ namespace BetterLyrics.WinUI3.Views public static readonly DependencyProperty AlbumArtCornerRadiusProperty = DependencyProperty.Register(nameof(AlbumArtCornerRadius), typeof(double), typeof(NowPlayingCanvas), new PropertyMetadata(new CornerRadius(0))); + + public double AlbumArtSize + { + get { return (double)GetValue(AlbumArtSizeProperty); } + set { SetValue(AlbumArtSizeProperty, value); } + } + + public static readonly DependencyProperty AlbumArtSizeProperty = + DependencyProperty.Register(nameof(AlbumArtSize), typeof(double), typeof(NowPlayingCanvas), new PropertyMetadata(0.0)); + public LyricsPageViewModel ViewModel => (LyricsPageViewModel)DataContext; public LyricsPage() @@ -74,8 +74,10 @@ namespace BetterLyrics.WinUI3.Views WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); WeakReferenceMessenger.Default.Register>(this); - - _rootGridSizeChangedTimer = App.Current.Resources.DispatcherQueue.CreateTimer(); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); + WeakReferenceMessenger.Default.Register>(this); } private void CompositionTarget_Rendering(object? sender, object e) @@ -84,6 +86,26 @@ namespace BetterLyrics.WinUI3.Views TimelineSlider.Value = currentTime; } + // ==== SongInfo + + private int GetTitleFontSize() + { + var albumArtLayoutSettings = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings; + if (albumArtLayoutSettings.IsAutoSongInfoFontSize) + { + return (int)Math.Clamp(Math.Min(RootGrid.ActualHeight, RootGrid.ActualWidth) / 20, 8, 72); + } + else + { + return albumArtLayoutSettings.SongInfoFontSize; + } + } + + private int GetArtistsAlbumFontSize() + { + return (int)(GetTitleFontSize() * 0.8); + } + private void RenderTextBlock(TextBlock? sender, string? text, int fontSize) { if (sender == null || string.IsNullOrEmpty(text) || fontSize == 0) return; @@ -119,131 +141,105 @@ namespace BetterLyrics.WinUI3.Views RenderTextBlock(AlbumTextBlock, _mediaSessionsService.CurrentSongInfo?.Album, GetArtistsAlbumFontSize()); } - private void UpdateAlbumArtSize() + private void UpdateSongInfoOpacity() { - var lyricsWindowStatus = _liveStatesService.LiveStates.LyricsWindowStatus; - var albumArtLayoutSettings = lyricsWindowStatus.AlbumArtLayoutSettings; - double temp = 0; - switch (lyricsWindowStatus.LyricsLayoutOrientation) + switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) { - case LyricsLayoutOrientation.Horizontal: - if (albumArtLayoutSettings.AutoAlbumArtSize) - { - temp = Math.Min( - (RootGrid.ActualHeight - _topMargin - _bottomMargin) * 8.5 / 16.0, - (RootGrid.ActualWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0); - } - else - { - temp = albumArtLayoutSettings.AlbumArtSize; - } + case LyricsDisplayType.AlbumArtOnly: + SongInfoStackPanel.Opacity = 1; break; - case LyricsLayoutOrientation.Vertical: - if (albumArtLayoutSettings.AutoAlbumArtSize) - { - temp = Math.Min( - (RootGrid.ActualHeight - _topMargin - _bottomMargin) * 3.0 / 16.0, - (RootGrid.ActualWidth - _leftMargin - _middleMargin - _rightMargin) * 4.0 / 16.0); - } - else - { - temp = albumArtLayoutSettings.AlbumArtSize; - } + case LyricsDisplayType.LyricsOnly: + SongInfoStackPanel.Opacity = 0; + break; + case LyricsDisplayType.SplitView: + SongInfoStackPanel.Opacity = 1; + break; + default: break; } - - AlbumArtSize = Math.Max(0, temp); } + private void UpdateSongInfoMargin() + { + switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) + { + case LyricsLayoutOrientation.Horizontal: + SongInfoStackPanel.Margin = new(32, -16, 32, 0); + break; + case LyricsLayoutOrientation.Vertical: + SongInfoStackPanel.Margin = new(-16, 32, 0, 0); + break; + } + } + + private void UpdateTrackSummaryGridMargin() + { + switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) + { + case LyricsLayoutOrientation.Horizontal: + TrackSummaryGrid.Margin = new(-32, -32, -32, 0); + break; + case LyricsLayoutOrientation.Vertical: + TrackSummaryGrid.Margin = new(-32, -32, 0, -32); + break; + } + } + + // ==== AlbumArt + private void UpdateAlbumArtCornerRadius() { var factor = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageRadius / 100.0; - AlbumArtCornerRadius = new((AlbumArtSize / 2) * factor); + AlbumArtCornerRadius = new((AlbumArtImage.ActualHeight / 2) * factor); } - private double GetAlbumArtY() + private void UpdateAlbumArtShadow() { - double temp = 0; - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) + var amount = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageShadowAmount; + ShadowRect.Translation = new(0, 0, amount); + } + + private void UpdateAlbumArtOpacity() + { + switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) { - case LyricsLayoutOrientation.Horizontal: - temp = (RootGrid.ActualHeight - AlbumArtWithSongInfoStackPanel.ActualHeight) / 2.0; + case LyricsDisplayType.AlbumArtOnly: + AlbumArtGrid.Opacity = 1; break; - case LyricsLayoutOrientation.Vertical: - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) - { - case LyricsDisplayType.AlbumArtOnly: - temp = (RootGrid.ActualHeight - AlbumArtSize) / 2.0; - break; - case LyricsDisplayType.SplitView: - temp = _topMargin; - break; - default: - break; - } + case LyricsDisplayType.LyricsOnly: + AlbumArtGrid.Opacity = 0; + break; + case LyricsDisplayType.SplitView: + AlbumArtGrid.Opacity = 1; break; default: break; } - - return (float)temp - 32; } - private double GetAlbumArtX() + // ==== + + private void UpdateTrackSummaryGridSpan() { - double temp = 0; - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + switch (status.LyricsDisplayType) { - case LyricsLayoutOrientation.Horizontal: - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) + case LyricsDisplayType.AlbumArtOnly: + Grid.SetRowSpan(TrackSummaryGrid, 3); + Grid.SetColumnSpan(TrackSummaryGrid, 3); + break; + case LyricsDisplayType.LyricsOnly: + break; + case LyricsDisplayType.SplitView: + switch (status.LyricsLayoutOrientation) { - case LyricsDisplayType.AlbumArtOnly: - temp = RootGrid.ActualWidth / 2.0 - AlbumArtSize / 2.0; + case LyricsLayoutOrientation.Horizontal: + Grid.SetRowSpan(TrackSummaryGrid, 3); + Grid.SetColumnSpan(TrackSummaryGrid, 1); break; - case LyricsDisplayType.SplitView: - temp = _leftMargin + ((RootGrid.ActualWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0 - AlbumArtSize) / 2.0; - break; - default: - break; - } - break; - case LyricsLayoutOrientation.Vertical: - temp = _leftMargin; - break; - default: - break; - } - - return (float)temp - 32; - } - - private void UpdateAlbumArtTranslation() - { - var x = GetAlbumArtX(); - var y = GetAlbumArtY(); - AlbumArtWithSongInfoStackPanel.Translation = new((float)x, (float)y, 0); - } - - private void UpdateMargin() - { - _topMargin = _bottomMargin = _leftMargin = _middleMargin = _rightMargin = Math.Max(RootGrid.ActualWidth, RootGrid.ActualHeight) / 30.0; - } - - private void UpdateLyricsStartY() - { - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) - { - case LyricsLayoutOrientation.Horizontal: - NowPlayingCanvas.LyricsStartY = 0; - break; - case LyricsLayoutOrientation.Vertical: - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) - { - case LyricsDisplayType.LyricsOnly: - NowPlayingCanvas.LyricsStartY = 0; - break; - case LyricsDisplayType.SplitView: - NowPlayingCanvas.LyricsStartY = _topMargin; + case LyricsLayoutOrientation.Vertical: + Grid.SetRowSpan(TrackSummaryGrid, 1); + Grid.SetColumnSpan(TrackSummaryGrid, 3); break; default: break; @@ -254,6 +250,52 @@ namespace BetterLyrics.WinUI3.Views } } + // ==== + + private void UpdateSongInfoStackPanelSpan() + { + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + switch (status.LyricsLayoutOrientation) + { + case LyricsLayoutOrientation.Horizontal: + Grid.SetRow(SongInfoStackPanel, 1); + Grid.SetColumn(SongInfoStackPanel, 0); + Grid.SetRowSpan(SongInfoStackPanel, 1); + Grid.SetColumnSpan(SongInfoStackPanel, 2); + break; + case LyricsLayoutOrientation.Vertical: + Grid.SetRow(SongInfoStackPanel, 0); + Grid.SetColumn(SongInfoStackPanel, 1); + Grid.SetRowSpan(SongInfoStackPanel, 2); + Grid.SetColumnSpan(SongInfoStackPanel, 1); + break; + default: + break; + } + } + + // ==== + + private void UpdateAlbumArtGridSpan() + { + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + switch (status.LyricsLayoutOrientation) + { + case LyricsLayoutOrientation.Horizontal: + Grid.SetRowSpan(AlbumArtGrid, 1); + Grid.SetColumnSpan(AlbumArtGrid, 2); + break; + case LyricsLayoutOrientation.Vertical: + Grid.SetRowSpan(AlbumArtGrid, 2); + Grid.SetColumnSpan(AlbumArtGrid, 1); + break; + default: + break; + } + } + + // ==== Lyrics + private void UpdateLyricsOpacity() { switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) @@ -270,98 +312,208 @@ namespace BetterLyrics.WinUI3.Views } } - private void UpdateLyricsStartX() + private void UpdateLyricsLayout() { - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsLayoutOrientation) + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + switch (status.LyricsDisplayType) { - case LyricsLayoutOrientation.Horizontal: - switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType) + case LyricsDisplayType.AlbumArtOnly: + break; + case LyricsDisplayType.LyricsOnly: + NowPlayingCanvas.LyricsStartX = LeftGapDef.ActualWidth; + NowPlayingCanvas.LyricsStartY = TopGapDef.ActualHeight; + NowPlayingCanvas.LyricsWidth = TrackSummaryColDef.ActualWidth + MiddleGapColDef.ActualWidth + LyricsColDef.ActualWidth; + NowPlayingCanvas.LyricsHeight = TrackSummaryRowDef.ActualHeight + MiddleGapRowDef.ActualHeight + LyricsRowDef.ActualHeight; + break; + case LyricsDisplayType.SplitView: + switch (status.LyricsLayoutOrientation) { - case LyricsDisplayType.LyricsOnly: - NowPlayingCanvas.LyricsStartX = _leftMargin; + case LyricsLayoutOrientation.Horizontal: + NowPlayingCanvas.LyricsStartX = LeftGapDef.ActualWidth + TrackSummaryColDef.ActualWidth + MiddleGapColDef.ActualWidth; + NowPlayingCanvas.LyricsStartY = TopGapDef.ActualHeight; + NowPlayingCanvas.LyricsWidth = LyricsColDef.ActualWidth; + NowPlayingCanvas.LyricsHeight = TrackSummaryRowDef.ActualHeight + MiddleGapRowDef.ActualHeight + LyricsRowDef.ActualHeight; break; - case LyricsDisplayType.SplitView: - NowPlayingCanvas.LyricsStartX = (RootGrid.ActualWidth - _leftMargin - _middleMargin - _rightMargin) / 2.0 + _leftMargin + _middleMargin; + case LyricsLayoutOrientation.Vertical: + NowPlayingCanvas.LyricsStartX = LeftGapDef.ActualWidth; + NowPlayingCanvas.LyricsStartY = TopGapDef.ActualHeight + TrackSummaryRowDef.ActualHeight + MiddleGapRowDef.ActualHeight; + NowPlayingCanvas.LyricsWidth = TrackSummaryColDef.ActualWidth + MiddleGapColDef.ActualWidth + LyricsColDef.ActualWidth; + NowPlayingCanvas.LyricsHeight = LyricsRowDef.ActualHeight; break; default: break; } break; - case LyricsLayoutOrientation.Vertical: - NowPlayingCanvas.LyricsStartX = _leftMargin; - break; default: break; } } - private void UpdateLyricsWidth() - { - NowPlayingCanvas.LyricsWidth = Math.Max(RootGrid.ActualWidth - NowPlayingCanvas.LyricsStartX - _rightMargin, 0); - } + // ==== private void OnLayoutChanged() { - UpdateMargin(); + UpdateSongInfoOpacity(); + UpdateSongInfoMargin(); + + UpdateAlbumArtShadow(); + UpdateAlbumArtOpacity(); + + UpdateTrackSummaryGridMargin(); + UpdateTrackSummaryGridSpan(); + + UpdateAlbumArtGridSpan(); + + UpdateSongInfoStackPanelSpan(); + + UpdateLyricsOpacity(); + UpdateLyricsLayout(); - UpdateAlbumArtSize(); UpdateAlbumArtCornerRadius(); - UpdateAlbumArtTranslation(); - UpdateLyricsStartX(); - UpdateLyricsStartY(); - - UpdateLyricsWidth(); + UpdateLayoutDraggerOpacity(); } - private int GetTitleFontSize() + private void UpdateGapFactor() { - var albumArtLayoutSettings = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings; - if (albumArtLayoutSettings.IsAutoSongInfoFontSize) + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + + status.LeftGapFactor = LeftGapDef.ActualWidth; + status.TopGapFactor = TopGapDef.ActualHeight; + status.RightGapFactor = RightGapDef.ActualWidth; + status.BottomGapFactor = BottomGapDef.ActualHeight; + + status.TrackSummaryColGapFactor = TrackSummaryColDef.ActualWidth; + status.MiddleColGapFactor = MiddleGapColDef.ActualWidth; + status.LyricsColGapFactor = LyricsColDef.ActualWidth; + + status.TrackSummaryRowGapFactor = TrackSummaryRowDef.ActualHeight; + status.MiddleRowGapFactor = MiddleGapRowDef.ActualHeight; + status.LyricsRowGapFactor = LyricsRowDef.ActualHeight; + } + + private void OnRowDraggerDragDelta(RowDefinition sender, DragDeltaEventArgs e) + { + double current = sender.ActualHeight; + current += e.VerticalChange; + + if (current <= 16) return; + + sender.Height = new GridLength(current); + UpdateGapFactor(); + } + + private void OnColDraggerDragDelta(ColumnDefinition sender, DragDeltaEventArgs e) + { + double current = sender.ActualWidth; + current += e.HorizontalChange; + + if (current <= 16) return; + + sender.Width = new GridLength(current); + UpdateGapFactor(); + } + + private void UpdateLayoutDraggerOpacity() + { + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + if (status.ShowLayoutIndicator) { - return (int)Math.Clamp(Math.Min(RootGrid.ActualHeight, RootGrid.ActualWidth) / 20, 8, 72); + switch (status.LyricsDisplayType) + { + case LyricsDisplayType.AlbumArtOnly: + case LyricsDisplayType.LyricsOnly: + + LeftGapDragger.Opacity = 1; + TrackSummaryColDragger.Opacity = 0; + MiddleColDragger.Opacity = 0; + LyricsColDragger.Opacity = 1; + + TopGapDragger.Opacity = 1; + TrackSummaryRowDragger.Opacity = 0; + MiddleRowDragger.Opacity = 0; + LyricsRowDragger.Opacity = 1; + + break; + case LyricsDisplayType.SplitView: + switch (status.LyricsLayoutOrientation) + { + case LyricsLayoutOrientation.Horizontal: + + LeftGapDragger.Opacity = 1; + TrackSummaryColDragger.Opacity = 1; + MiddleColDragger.Opacity = 1; + LyricsColDragger.Opacity = 1; + + TopGapDragger.Opacity = 1; + TrackSummaryRowDragger.Opacity = 0; + MiddleRowDragger.Opacity = 0; + LyricsRowDragger.Opacity = 1; + + break; + case LyricsLayoutOrientation.Vertical: + + LeftGapDragger.Opacity = 1; + TrackSummaryColDragger.Opacity = 0; + MiddleColDragger.Opacity = 0; + LyricsColDragger.Opacity = 1; + + TopGapDragger.Opacity = 1; + TrackSummaryRowDragger.Opacity = 1; + MiddleRowDragger.Opacity = 1; + LyricsRowDragger.Opacity = 1; + + break; + default: + break; + } + break; + default: + break; + } } else { - return albumArtLayoutSettings.SongInfoFontSize; - } - } + LeftGapDragger.Opacity = 0; + TrackSummaryColDragger.Opacity = 0; + MiddleColDragger.Opacity = 0; + LyricsColDragger.Opacity = 0; + + TopGapDragger.Opacity = 0; + TrackSummaryRowDragger.Opacity = 0; + MiddleRowDragger.Opacity = 0; + LyricsRowDragger.Opacity = 0; + } - private int GetArtistsAlbumFontSize() - { - return (int)(GetTitleFontSize() * 0.8); } // ==== private void RootGrid_SizeChanged(object sender, SizeChangedEventArgs e) { - _rootGridSizeChangedTimer.Debounce(() => + RenderSongInfo(); + + OnLayoutChanged(); + + if (e.NewSize.Width < 500 || e.NewSize.Height < 100) { - RenderSongInfo(); - - OnLayoutChanged(); - - if (e.NewSize.Width < 500 || e.NewSize.Height < 100) + if (BottomCommandGrid.Children.Count != 0) { - if (BottomCommandGrid.Children.Count != 0) - { - BottomCommandGrid.Children.Remove(BottomCommandContent); - BottomCommandFlyoutContainer.Children.Add(BottomCommandContent); - } - BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 0, 0); + BottomCommandGrid.Children.Remove(BottomCommandContent); + BottomCommandFlyoutContainer.Children.Add(BottomCommandContent); } - else + BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 0, 0); + } + else + { + if (BottomCommandFlyoutContainer.Children.Count != 0) { - if (BottomCommandFlyoutContainer.Children.Count != 0) - { - BottomCommandFlyout.Hide(); - BottomCommandFlyoutContainer.Children.Remove(BottomCommandContent); - BottomCommandGrid.Children.Add(BottomCommandContent); - } - BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 12, 0); + BottomCommandFlyout.Hide(); + BottomCommandFlyoutContainer.Children.Remove(BottomCommandContent); + BottomCommandGrid.Children.Add(BottomCommandContent); } - }, Constants.Time.DebounceTimeout); + BottomCommandFlyoutTriggerHint.Translation = new Vector3(0, 12, 0); + } } private void BottomCommandGrid_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) @@ -500,11 +652,6 @@ namespace BetterLyrics.WinUI3.Views Shadow.Receivers.Add(ShadowCastGrid); } - private void AlbumArtWithSongInfoStackPanel_SizeChanged(object sender, SizeChangedEventArgs e) - { - ViewModel.AlbumArtWithSongInfoStackPanelHeight = e.NewSize.Height; - } - private void TitleAutoScrollHoverEffectView_PointerCanceled(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e) { TitleAutoScrollHoverEffectView.IsPlaying = false; @@ -560,6 +707,76 @@ namespace BetterLyrics.WinUI3.Views CompositionTarget.Rendering -= CompositionTarget_Rendering; } + private void LyricsPlaceholder_SizeChanged(object sender, SizeChangedEventArgs e) + { + OnLayoutChanged(); + } + + private void TrackSummaryGridContainer_Loaded(object sender, RoutedEventArgs e) + { + var status = _liveStatesService.LiveStates.LyricsWindowStatus; + + LeftGapDef.Width = new(status.LeftGapFactor, GridUnitType.Star); + TopGapDef.Height = new(status.TopGapFactor, GridUnitType.Star); + RightGapDef.Width = new(status.RightGapFactor, GridUnitType.Star); + BottomGapDef.Height = new(status.BottomGapFactor, GridUnitType.Star); + + MiddleGapColDef.Width = new(status.MiddleColGapFactor, GridUnitType.Star); + MiddleGapRowDef.Height = new(status.MiddleRowGapFactor, GridUnitType.Star); + + TrackSummaryColDef.Width = new(status.TrackSummaryColGapFactor, GridUnitType.Star); + TrackSummaryRowDef.Height = new(status.TrackSummaryRowGapFactor, GridUnitType.Star); + + LyricsColDef.Width = new(status.LyricsColGapFactor, GridUnitType.Star); + LyricsRowDef.Height = new(status.LyricsRowGapFactor, GridUnitType.Star); + + OnLayoutChanged(); + } + + private void TrackSummaryGrid_SizeChanged(object sender, SizeChangedEventArgs e) + { + } + + private void LeftGapDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnColDraggerDragDelta(LeftGapDef, e); + } + + private void TrackSummaryColDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnColDraggerDragDelta(TrackSummaryColDef, e); + } + + private void MiddleColDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnColDraggerDragDelta(MiddleGapColDef, e); + } + + private void LyricsColDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnColDraggerDragDelta(LyricsColDef, e); + } + + private void TopGapDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnRowDraggerDragDelta(TopGapDef, e); + } + + private void TrackSummaryRowDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnRowDraggerDragDelta(TrackSummaryRowDef, e); + } + + private void MiddleRowDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnRowDraggerDragDelta(MiddleGapRowDef, e); + } + + private void LyricsRowDragger_DragDelta(object sender, DragDeltaEventArgs e) + { + OnRowDraggerDragDelta(LyricsRowDef, e); + } + // ==== public void Receive(PropertyChangedMessage message) @@ -570,6 +787,14 @@ namespace BetterLyrics.WinUI3.Views { RenderSongInfo(); } + else if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageRadius)) + { + UpdateAlbumArtCornerRadius(); + } + else if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageShadowAmount)) + { + UpdateAlbumArtShadow(); + } } } @@ -582,6 +807,13 @@ namespace BetterLyrics.WinUI3.Views RenderSongInfo(); } } + if (message.Sender is LyricsWindowStatus) + { + if (message.PropertyName == nameof(LyricsWindowStatus.ShowLayoutIndicator)) + { + UpdateLayoutDraggerOpacity(); + } + } } public void Receive(PropertyChangedMessage message) @@ -613,5 +845,109 @@ namespace BetterLyrics.WinUI3.Views } } + public async void Receive(PropertyChangedMessage message) + { + if (message.Sender is IMediaSessionsService) + { + if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage)) + { + LastAlbumArtImage.Source = AlbumArtImage.Source; + LastAlbumArtImage.Opacity = 1; + await Task.Delay(Constants.Time.AnimationDuration); + + AlbumArtImage.Opacity = 0; + await Task.Delay(Constants.Time.AnimationDuration); + AlbumArtImage.Source = message.NewValue; + + LastAlbumArtImage.Opacity = 0; + AlbumArtImage.Opacity = 1; + + UpdateAlbumArtCornerRadius(); + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsWindowStatus) + { + if (message.PropertyName == nameof(LyricsWindowStatus.LyricsLayoutOrientation)) + { + OnLayoutChanged(); + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsWindowStatus) + { + if (message.PropertyName == nameof(LyricsWindowStatus.LyricsDisplayType)) + { + OnLayoutChanged(); + } + } + } + + public void Receive(PropertyChangedMessage message) + { + if (message.Sender is LyricsWindowStatus) + { + + // ==== + + if (message.PropertyName == nameof(LyricsWindowStatus.LeftGapFactor)) + { + LeftGapDef.Width = new(_liveStatesService.LiveStates.LyricsWindowStatus.LeftGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.TopGapFactor)) + { + TopGapDef.Height = new(_liveStatesService.LiveStates.LyricsWindowStatus.TopGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.RightGapFactor)) + { + RightGapDef.Width = new(_liveStatesService.LiveStates.LyricsWindowStatus.RightGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.BottomGapFactor)) + { + BottomGapDef.Height = new(_liveStatesService.LiveStates.LyricsWindowStatus.BottomGapFactor, GridUnitType.Star); + } + + // ==== + + else if (message.PropertyName == nameof(LyricsWindowStatus.MiddleColGapFactor)) + { + MiddleGapColDef.Width = new(_liveStatesService.LiveStates.LyricsWindowStatus.MiddleColGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.MiddleRowGapFactor)) + { + MiddleGapRowDef.Height = new(_liveStatesService.LiveStates.LyricsWindowStatus.MiddleRowGapFactor, GridUnitType.Star); + } + + // ==== + + else if (message.PropertyName == nameof(LyricsWindowStatus.TrackSummaryColGapFactor)) + { + TrackSummaryColDef.Width = new(_liveStatesService.LiveStates.LyricsWindowStatus.TrackSummaryColGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.TrackSummaryRowGapFactor)) + { + TrackSummaryRowDef.Height = new(_liveStatesService.LiveStates.LyricsWindowStatus.TrackSummaryRowGapFactor, GridUnitType.Star); + } + + // ==== + + else if (message.PropertyName == nameof(LyricsWindowStatus.LyricsColGapFactor)) + { + LyricsColDef.Width = new(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsColGapFactor, GridUnitType.Star); + } + else if (message.PropertyName == nameof(LyricsWindowStatus.LyricsRowGapFactor)) + { + LyricsRowDef.Height = new(_liveStatesService.LiveStates.LyricsWindowStatus.LyricsRowGapFactor, GridUnitType.Star); + } + + } + } + } }