mirror of
https://github.com/jayfunc/BetterLyrics.git
synced 2026-01-12 19:24:55 +08:00
chores: fix floating animation; improve layout
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using Microsoft.UI.Xaml;
|
||||
using System;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Helper
|
||||
{
|
||||
public static class LyricsLayoutHelper
|
||||
{
|
||||
// 硬性限制
|
||||
private const float BaseMinFontSize = 14f;
|
||||
private const float BaseMaxFontSize = 80f;
|
||||
private const float TargetMinVisibleLines = 5f;
|
||||
private const float WidthPaddingRatio = 0.85f;
|
||||
|
||||
// 比例配置
|
||||
private const float RatioSongTitle = 1f;
|
||||
private const float RatioArtist = 0.85f;
|
||||
private const float RatioAlbum = 0.75f;
|
||||
private const float RatioTranslation = 0.7f;
|
||||
private const float RatioTransliteration = 0.55f;
|
||||
private const float AbsoluteMinReadableSize = 10f;
|
||||
|
||||
public static LyricsLayoutMetrics CalculateLayout(double width, double height)
|
||||
{
|
||||
float baseSize = CalculateBaseFontSize(width, height);
|
||||
|
||||
return new LyricsLayoutMetrics
|
||||
{
|
||||
MainLyricsSize = baseSize,
|
||||
TranslationSize = ApplyRatio(baseSize, RatioTranslation),
|
||||
TransliterationSize = ApplyRatio(baseSize, RatioTransliteration),
|
||||
SongTitleSize = ApplyRatio(baseSize, RatioSongTitle),
|
||||
ArtistNameSize = ApplyRatio(baseSize, RatioArtist),
|
||||
AlbumNameSize = ApplyRatio(baseSize, RatioAlbum)
|
||||
};
|
||||
}
|
||||
|
||||
private static float CalculateBaseFontSize(double width, double height)
|
||||
{
|
||||
float usableWidth = (float)width * WidthPaddingRatio;
|
||||
|
||||
// 宽度 300~500px 时,除以 14 (字大)
|
||||
// 宽度 >1000px 时,除以 30 (字适中,展示更多内容)
|
||||
float targetCharsPerLine;
|
||||
if (width < 500)
|
||||
{
|
||||
targetCharsPerLine = 14f;
|
||||
}
|
||||
else if (width > 1000)
|
||||
{
|
||||
targetCharsPerLine = 30f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 平滑过渡
|
||||
float t = (float)(width - 500) / 500f;
|
||||
targetCharsPerLine = 14f + 16f * t;
|
||||
}
|
||||
|
||||
float sizeByWidth = usableWidth / targetCharsPerLine;
|
||||
float sizeByHeight = (float)height / TargetMinVisibleLines;
|
||||
|
||||
float targetSize = Math.Min(sizeByWidth, sizeByHeight);
|
||||
|
||||
// 窄屏时底线设高一点 (16px),宽屏如果高度不够可能允许更小
|
||||
float currentMinLimit = (width < 400) ? 16f : BaseMinFontSize;
|
||||
|
||||
return Math.Clamp(targetSize, currentMinLimit, BaseMaxFontSize);
|
||||
}
|
||||
|
||||
private static float ApplyRatio(float baseSize, float ratio)
|
||||
{
|
||||
return Math.Max(baseSize * ratio, AbsoluteMinReadableSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ namespace BetterLyrics.WinUI3.Helper
|
||||
public T StartValue => _startValue;
|
||||
public T TargetValue => _targetValue;
|
||||
public EasingType? EasingType => _easingType;
|
||||
public double Progress => _progress;
|
||||
|
||||
public ValueTransition(T initialValue, double durationSeconds, Func<T, T, double, T>? interpolator = null, EasingType? easingType = null, double delaySeconds = 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Helper;
|
||||
using BetterLyrics.WinUI3.Models;
|
||||
using BetterLyrics.WinUI3.Models.Settings;
|
||||
using Microsoft.Graphics.Canvas;
|
||||
using Microsoft.Graphics.Canvas.UI.Xaml;
|
||||
@@ -41,13 +42,16 @@ namespace BetterLyrics.WinUI3.Logic
|
||||
|
||||
if (style.IsDynamicLyricsFontSize)
|
||||
{
|
||||
originalFontSize = (int)Math.Clamp(Math.Min(canvasHeight, canvasWidth) / 15, 18, 96);
|
||||
translatedFontSize = phoneticFontSize = (int)(originalFontSize * 2.0 / 3.0);
|
||||
var lyricsLayoutMetrics = LyricsLayoutHelper.CalculateLayout(canvasWidth, canvasHeight);
|
||||
|
||||
phoneticFontSize = (int)lyricsLayoutMetrics.TransliterationSize;
|
||||
originalFontSize = (int)lyricsLayoutMetrics.MainLyricsSize;
|
||||
translatedFontSize = (int)lyricsLayoutMetrics.TranslationSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
originalFontSize = style.OriginalLyricsFontSize;
|
||||
phoneticFontSize = style.PhoneticLyricsFontSize;
|
||||
originalFontSize = style.OriginalLyricsFontSize;
|
||||
translatedFontSize = style.TranslatedLyricsFontSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Models
|
||||
{
|
||||
public struct LyricsLayoutMetrics
|
||||
{
|
||||
public float MainLyricsSize;
|
||||
public float TranslationSize;
|
||||
public float TransliterationSize;
|
||||
|
||||
public float SongTitleSize;
|
||||
public float ArtistNameSize;
|
||||
public float AlbumNameSize;
|
||||
|
||||
public Thickness AlbumArtPadding;
|
||||
}
|
||||
}
|
||||
@@ -229,14 +229,19 @@ namespace BetterLyrics.WinUI3.Renderer
|
||||
|
||||
if (settings.IsLyricsFloatAnimationEnabled)
|
||||
{
|
||||
double targetFloatOffset = sourceCharRect.Height * 0.05;
|
||||
double targetFloatOffset = sourceCharRect.Height * 0.1;
|
||||
if (charIndex < curCharIndexInt) floatOffset = 0;
|
||||
else if (charIndex == curCharIndexInt)
|
||||
{
|
||||
var p = exactProgressIndex - curCharIndexInt;
|
||||
floatOffset = -targetFloatOffset + p * targetFloatOffset;
|
||||
}
|
||||
else floatOffset = -targetFloatOffset;
|
||||
else
|
||||
{
|
||||
floatOffset = -targetFloatOffset;
|
||||
}
|
||||
// 制造句间上浮过度动画,这里用任何一个 Transition 都行,主要是获取当前行的进入视野的 Progress
|
||||
floatOffset *= line.YOffsetTransition.Progress;
|
||||
}
|
||||
|
||||
var parentSyllable = line.LyricsSyllables.FirstOrDefault(x => x.StartIndex <= charIndex && charIndex < x.StartIndex + x.Text.Length);
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
|
||||
<Grid x:Name="TrackSummaryGridContainer" Loaded="TrackSummaryGridContainer_Loaded">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition x:Name="TrackSummaryRowDef" Height="*" />
|
||||
<RowDefinition x:Name="TrackSummaryRowDef" Height="0" />
|
||||
<RowDefinition x:Name="MiddleGapRowDef" Height="0" />
|
||||
<RowDefinition x:Name="LyricsRowDef" Height="2*" />
|
||||
<RowDefinition x:Name="LyricsRowDef" Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftGapDef" Width="0" />
|
||||
@@ -184,11 +184,14 @@
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
x:Name="LyricsPlaceholder"
|
||||
Grid.Row="2"
|
||||
Grid.Column="3"
|
||||
SizeChanged="LyricsPlaceholder_SizeChanged" />
|
||||
<Grid x:Name="LyricsPlaceholder" SizeChanged="LyricsPlaceholder_SizeChanged">
|
||||
<ScrollViewer
|
||||
x:Name="LyricsScrollViewer"
|
||||
PointerWheelChanged="LyricsScrollViewer_PointerWheelChanged"
|
||||
Visibility="Collapsed">
|
||||
<Grid />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ using BetterLyrics.WinUI3.ViewModels;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using CommunityToolkit.Mvvm.Messaging.Messages;
|
||||
using DevWinUI;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Documents;
|
||||
@@ -21,7 +22,6 @@ using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Media3D;
|
||||
|
||||
namespace BetterLyrics.WinUI3.Views
|
||||
{
|
||||
@@ -39,6 +39,8 @@ namespace BetterLyrics.WinUI3.Views
|
||||
private readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
|
||||
private readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService<ILiveStatesService>();
|
||||
|
||||
private readonly DispatcherQueueTimer _timer = App.Current.Resources.DispatcherQueue.CreateTimer();
|
||||
|
||||
public CornerRadius AlbumArtCornerRadius
|
||||
{
|
||||
get { return (CornerRadius)GetValue(AlbumArtCornerRadiusProperty); }
|
||||
@@ -48,16 +50,6 @@ 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()
|
||||
@@ -85,25 +77,7 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
// ==== 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)
|
||||
private void RenderTextBlock(TextBlock? sender, string? text, double fontSize)
|
||||
{
|
||||
if (sender == null || string.IsNullOrEmpty(text) || fontSize == 0) return;
|
||||
|
||||
@@ -115,28 +89,23 @@ namespace BetterLyrics.WinUI3.Views
|
||||
var fontFamilyName = LanguageHelper.IsCJK(ch) ? lyricsStyleSettings.LyricsCJKFontFamily : lyricsStyleSettings.LyricsWesternFontFamily;
|
||||
sender.Inlines.Add(new Run { Text = $"{ch}", FontFamily = new FontFamily(fontFamilyName) });
|
||||
}
|
||||
sender.FontSize = fontSize;
|
||||
sender.FontSize = (int)fontSize;
|
||||
sender.Foreground = new SolidColorBrush(_mediaSessionsService.AlbumArtThemeColors.BgFontColor);
|
||||
}
|
||||
|
||||
private void RenderTextBlock(AnimatedTextBlock? sender, string? text, int fontSize)
|
||||
{
|
||||
if (sender == null || string.IsNullOrEmpty(text) || fontSize == 0) return;
|
||||
|
||||
var lyricsStyleSettings = _liveStatesService.LiveStates.LyricsWindowStatus.LyricsStyleSettings;
|
||||
var fontFamilyName = LanguageHelper.IsCJK(text) ? lyricsStyleSettings.LyricsCJKFontFamily : lyricsStyleSettings.LyricsWesternFontFamily;
|
||||
|
||||
sender.FontFamily = new Microsoft.UI.Xaml.Media.FontFamily(fontFamilyName);
|
||||
sender.FontSize = fontSize;
|
||||
|
||||
sender.Text = text;
|
||||
}
|
||||
|
||||
private void RenderSongInfo()
|
||||
{
|
||||
RenderTextBlock(TitleTextBlock, _mediaSessionsService.CurrentSongInfo?.Title, GetTitleFontSize());
|
||||
RenderTextBlock(ArtistsTextBlock, _mediaSessionsService.CurrentSongInfo?.DisplayArtists, GetArtistsAlbumFontSize());
|
||||
RenderTextBlock(AlbumTextBlock, _mediaSessionsService.CurrentSongInfo?.Album, GetArtistsAlbumFontSize());
|
||||
var lyricsLayoutMetrics = LyricsLayoutHelper.CalculateLayout(RootGrid.ActualWidth, RootGrid.ActualHeight);
|
||||
|
||||
var albumArtLayoutSettings = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings;
|
||||
|
||||
var titleFontSize = albumArtLayoutSettings.IsAutoSongInfoFontSize ? lyricsLayoutMetrics.SongTitleSize : albumArtLayoutSettings.SongInfoFontSize;
|
||||
var artistsFontSize = albumArtLayoutSettings.IsAutoSongInfoFontSize ? lyricsLayoutMetrics.ArtistNameSize : albumArtLayoutSettings.SongInfoFontSize * 0.8;
|
||||
var albumFontSize = albumArtLayoutSettings.IsAutoSongInfoFontSize ? lyricsLayoutMetrics.AlbumNameSize : albumArtLayoutSettings.SongInfoFontSize * 0.8;
|
||||
|
||||
RenderTextBlock(TitleTextBlock, _mediaSessionsService.CurrentSongInfo?.Title, titleFontSize);
|
||||
RenderTextBlock(ArtistsTextBlock, _mediaSessionsService.CurrentSongInfo?.DisplayArtists, artistsFontSize);
|
||||
RenderTextBlock(AlbumTextBlock, _mediaSessionsService.CurrentSongInfo?.Album, albumFontSize);
|
||||
}
|
||||
|
||||
private void UpdateSongInfoOpacity()
|
||||
@@ -246,6 +215,43 @@ namespace BetterLyrics.WinUI3.Views
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLyricsPlaceholderSpan()
|
||||
{
|
||||
var status = _liveStatesService.LiveStates.LyricsWindowStatus;
|
||||
switch (status.LyricsDisplayType)
|
||||
{
|
||||
case LyricsDisplayType.AlbumArtOnly:
|
||||
break;
|
||||
case LyricsDisplayType.LyricsOnly:
|
||||
Grid.SetRow(LyricsPlaceholder, 0);
|
||||
Grid.SetRowSpan(LyricsPlaceholder, 3);
|
||||
Grid.SetColumn(LyricsPlaceholder, 1);
|
||||
Grid.SetColumnSpan(LyricsPlaceholder, 3);
|
||||
break;
|
||||
case LyricsDisplayType.SplitView:
|
||||
switch (status.LyricsLayoutOrientation)
|
||||
{
|
||||
case LyricsLayoutOrientation.Horizontal:
|
||||
Grid.SetRow(LyricsPlaceholder, 0);
|
||||
Grid.SetRowSpan(LyricsPlaceholder, 3);
|
||||
Grid.SetColumn(LyricsPlaceholder, 3);
|
||||
Grid.SetColumnSpan(LyricsPlaceholder, 1);
|
||||
break;
|
||||
case LyricsLayoutOrientation.Vertical:
|
||||
Grid.SetRow(LyricsPlaceholder, 2);
|
||||
Grid.SetRowSpan(LyricsPlaceholder, 1);
|
||||
Grid.SetColumn(LyricsPlaceholder, 1);
|
||||
Grid.SetColumnSpan(LyricsPlaceholder, 3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
|
||||
private void UpdateAlbumArtGridSpan()
|
||||
@@ -329,15 +335,19 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
private void UpdateGap()
|
||||
{
|
||||
var lyricsLayoutMetrics = LyricsLayoutHelper.CalculateLayout(RootGrid.ActualWidth, RootGrid.ActualHeight);
|
||||
|
||||
var status = _liveStatesService.LiveStates.LyricsWindowStatus;
|
||||
|
||||
double height = RootGrid.ActualHeight;
|
||||
double width = RootGrid.ActualWidth;
|
||||
|
||||
double xMargin = 0;
|
||||
double yMargin = 0;
|
||||
double middleGapCol = 0;
|
||||
double gapBetweenAlbumArtAndSongInfo = 0;
|
||||
double trackSummaryRowHeight = 0;
|
||||
|
||||
double xMargin = 0;
|
||||
double yMargin = 0;
|
||||
|
||||
if (height < 400)
|
||||
{
|
||||
@@ -354,18 +364,19 @@ namespace BetterLyrics.WinUI3.Views
|
||||
}
|
||||
else
|
||||
{
|
||||
gapBetweenAlbumArtAndSongInfo = GetTitleFontSize() / 2;
|
||||
gapBetweenAlbumArtAndSongInfo = lyricsLayoutMetrics.SongTitleSize / 2;
|
||||
}
|
||||
|
||||
switch (status.LyricsLayoutOrientation)
|
||||
{
|
||||
case LyricsLayoutOrientation.Horizontal:
|
||||
xMargin = Math.Max(16, Math.Min(width, height) * 0.25);
|
||||
yMargin = Math.Max(16, Math.Min(width, height) * 0.15);
|
||||
xMargin = Math.Clamp(Math.Min(width, height) * 0.25, 16, 128);
|
||||
yMargin = Math.Max(32, Math.Min(width, height) * 0.15);
|
||||
break;
|
||||
case LyricsLayoutOrientation.Vertical:
|
||||
xMargin = Math.Max(16, Math.Min(width, height) * 0.15);
|
||||
yMargin = Math.Max(16, Math.Min(width, height) * 0.10);
|
||||
xMargin = Math.Max(16, Math.Min(width, height) * 0.05);
|
||||
yMargin = Math.Max(16, Math.Min(width, height) * 0.05);
|
||||
trackSummaryRowHeight = Math.Max(64, Math.Min(width, height) * 0.25);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -373,30 +384,36 @@ namespace BetterLyrics.WinUI3.Views
|
||||
|
||||
MiddleGapColDef.Width = new(middleGapCol);
|
||||
|
||||
TrackSummaryGridRow0.Height = TrackSummaryGridRow4.Height = new(yMargin);
|
||||
TrackSummaryGridRow0.Height = new(yMargin);
|
||||
TrackSummaryGridRow4.Height = new(yMargin);
|
||||
LeftGapDef.Width = RightGapDef.Width = new(xMargin);
|
||||
|
||||
TrackSummaryRowDef.Height = new(trackSummaryRowHeight);
|
||||
|
||||
TrackSummaryGridCol1.Width = TrackSummaryGridRow2.Height = new(gapBetweenAlbumArtAndSongInfo);
|
||||
}
|
||||
|
||||
private void OnLayoutChanged()
|
||||
{
|
||||
UpdateSongInfoOpacity();
|
||||
_timer.Debounce(() =>
|
||||
{
|
||||
UpdateGap();
|
||||
|
||||
UpdateAlbumArtShadow();
|
||||
UpdateAlbumArtOpacity();
|
||||
UpdateSongInfoOpacity();
|
||||
UpdateLyricsOpacity();
|
||||
UpdateAlbumArtOpacity();
|
||||
|
||||
UpdateTrackSummaryGridSpan();
|
||||
UpdateAlbumArtShadow();
|
||||
|
||||
UpdateAlbumArtGridSpan();
|
||||
UpdateTrackSummaryGridSpan();
|
||||
UpdateAlbumArtGridSpan();
|
||||
UpdateSongInfoStackPanelSpan();
|
||||
UpdateLyricsPlaceholderSpan();
|
||||
|
||||
UpdateSongInfoStackPanelSpan();
|
||||
UpdateAlbumArtCornerRadius();
|
||||
|
||||
UpdateLyricsOpacity();
|
||||
UpdateLyricsLayout();
|
||||
|
||||
UpdateAlbumArtCornerRadius();
|
||||
|
||||
UpdateGap();
|
||||
UpdateLyricsLayout();
|
||||
}, Constants.Time.DebounceTimeout);
|
||||
}
|
||||
|
||||
// ====
|
||||
@@ -763,5 +780,11 @@ namespace BetterLyrics.WinUI3.Views
|
||||
}
|
||||
}
|
||||
|
||||
private void LyricsScrollViewer_PointerWheelChanged(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
|
||||
{
|
||||
var pointerPoint = e.GetCurrentPoint(LyricsScrollViewer);
|
||||
int mouseWheelDelta = pointerPoint.Properties.MouseWheelDelta;
|
||||
NowPlayingCanvas.LyricsStartY += mouseWheelDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user