fix: album art shadow

This commit is contained in:
Zhe Fang
2025-12-03 14:31:57 -05:00
parent 4d3b982904
commit 53abc4526c
5 changed files with 158 additions and 77 deletions

View File

@@ -334,6 +334,11 @@
<ItemGroup>
<Folder Include="TemplateSelector\" />
</ItemGroup>
<ItemGroup>
<Page Update="Controls\ShadowImage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Controls\PropertyRow.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<UserControl
x:Class="BetterLyrics.WinUI3.Controls.ShadowImage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:const="using:BetterLyrics.WinUI3.Constants"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:BetterLyrics.WinUI3.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.OpacityTransition>
<ScalarTransition />
</UserControl.OpacityTransition>
<Grid Margin="-32" Padding="32">
<Grid
x:Name="ShadowCastGrid"
HorizontalAlignment="Center"
VerticalAlignment="Center"
SizeChanged="ShadowCastGrid_SizeChanged">
<Image Source="{x:Bind ImageSource, Mode=OneWay}" Stretch="Uniform" />
</Grid>
<Border
x:Name="ShadowRect"
Loaded="ShadowRect_Loaded"
SizeChanged="ShadowRect_SizeChanged"
Translation="0,0,0">
<Border.Shadow>
<ThemeShadow x:Name="Shadow" />
</Border.Shadow>
</Border>
</Grid>
</UserControl>

View File

@@ -0,0 +1,103 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace BetterLyrics.WinUI3.Controls
{
public sealed partial class ShadowImage : UserControl
{
public int CornerRadiusAmount
{
get { return (int)GetValue(CornerRadiusAmountProperty); }
set { SetValue(CornerRadiusAmountProperty, value); }
}
public static readonly DependencyProperty CornerRadiusAmountProperty =
DependencyProperty.Register(nameof(CornerRadiusAmount), typeof(int), typeof(ShadowImage), new PropertyMetadata(0, OnDependencyPropertyChanged));
public int ShadowAmount
{
get { return (int)GetValue(ShadowAmountProperty); }
set { SetValue(ShadowAmountProperty, value); }
}
public static readonly DependencyProperty ShadowAmountProperty =
DependencyProperty.Register(nameof(ShadowAmount), typeof(int), typeof(ShadowImage), new PropertyMetadata(0, OnDependencyPropertyChanged));
public ImageSource? ImageSource
{
get { return (ImageSource?)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register(nameof(ImageSource), typeof(ImageSource), typeof(ShadowImage), new PropertyMetadata(null));
public ShadowImage()
{
InitializeComponent();
}
private static void OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ShadowImage shadowImage)
{
if (e.Property == CornerRadiusAmountProperty)
{
shadowImage.UpdateShadowCastGridCornerRadius();
shadowImage.UpdateShadowRectCornerRadius();
}
else if (e.Property == ShadowAmountProperty)
{
shadowImage.UpdateShadowRectShadow();
}
}
}
private void UpdateShadowRectShadow()
{
ShadowRect.Translation = new(0, 0, ShadowAmount);
}
private void UpdateShadowCastGridCornerRadius()
{
var minSize = Math.Min(ShadowCastGrid.ActualHeight, ShadowCastGrid.ActualWidth);
ShadowCastGrid.CornerRadius = new(CornerRadiusAmount / 100.0 * minSize);
}
private void UpdateShadowRectCornerRadius()
{
var minSize = Math.Min(ShadowRect.ActualHeight, ShadowRect.ActualWidth);
ShadowRect.CornerRadius = new(CornerRadiusAmount / 100.0 * minSize);
}
private void ShadowCastGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateShadowCastGridCornerRadius();
}
private void ShadowRect_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateShadowRectCornerRadius();
}
private void ShadowRect_Loaded(object sender, RoutedEventArgs e)
{
Shadow.Receivers.Add(ShadowCastGrid);
}
}
}

View File

@@ -66,38 +66,22 @@
</Grid.OpacityTransition>
<!-- Album art -->
<Grid
x:Name="AlbumArtGrid"
Margin="-32"
Padding="32"
HorizontalAlignment="{Binding ElementName=SongInfoStackPanel, Path=HorizontalAlignment, Mode=OneWay}">
<Grid x:Name="AlbumArtGrid" HorizontalAlignment="{Binding ElementName=SongInfoStackPanel, Path=HorizontalAlignment, Mode=OneWay}">
<Grid.OpacityTransition>
<ScalarTransition Duration="{x:Bind const:Time.AnimationDuration}" />
</Grid.OpacityTransition>
<Grid
x:Name="ShadowCastGrid"
CornerRadius="{x:Bind AlbumArtCornerRadius, Mode=OneWay}"
SizeChanged="ShadowCastGrid_SizeChanged">
<Image x:Name="LastAlbumArtImage" Stretch="Uniform">
<Image.OpacityTransition>
<ScalarTransition Duration="{x:Bind const:Time.AnimationDuration}" />
</Image.OpacityTransition>
</Image>
<Image x:Name="AlbumArtImage" Stretch="Uniform">
<Image.OpacityTransition>
<ScalarTransition Duration="{x:Bind const:Time.AnimationDuration}" />
</Image.OpacityTransition>
</Image>
</Grid>
<Border
x:Name="ShadowRect"
CornerRadius="{x:Bind AlbumArtCornerRadius, Mode=OneWay}"
Loaded="ShadowRect_Loaded"
Translation="0,0,0">
<Border.Shadow>
<ThemeShadow x:Name="Shadow" />
</Border.Shadow>
</Border>
<uc:ShadowImage
x:Name="LastAlbumArtImage"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadiusAmount="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageRadius, Mode=OneWay}"
ShadowAmount="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=OneWay}" />
<uc:ShadowImage
x:Name="AlbumArtImage"
HorizontalAlignment="Center"
VerticalAlignment="Center"
CornerRadiusAmount="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageRadius, Mode=OneWay}"
ShadowAmount="{x:Bind ViewModel.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageShadowAmount, Mode=OneWay}" />
</Grid>
<!-- Song info -->

View File

@@ -42,15 +42,6 @@ namespace BetterLyrics.WinUI3.Views
private readonly DispatcherQueueTimer _layoutChangedTimer = App.Current.Resources.DispatcherQueue.CreateTimer();
private readonly DispatcherQueueTimer _scrollChangedTimer = App.Current.Resources.DispatcherQueue.CreateTimer();
public CornerRadius AlbumArtCornerRadius
{
get { return (CornerRadius)GetValue(AlbumArtCornerRadiusProperty); }
set { SetValue(AlbumArtCornerRadiusProperty, value); }
}
public static readonly DependencyProperty AlbumArtCornerRadiusProperty =
DependencyProperty.Register(nameof(AlbumArtCornerRadius), typeof(double), typeof(LyricsCanvas), new PropertyMetadata(new CornerRadius(0)));
public NowPlayingPageViewModel ViewModel => (NowPlayingPageViewModel)DataContext;
public NowPlayingPage()
@@ -128,19 +119,6 @@ namespace BetterLyrics.WinUI3.Views
}
// ==== AlbumArt
private void UpdateAlbumArtCornerRadius()
{
var factor = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageRadius / 100.0;
AlbumArtCornerRadius = new((AlbumArtImage.ActualHeight / 2) * factor);
}
private void UpdateAlbumArtShadow()
{
var amount = _liveStatesService.LiveStates.LyricsWindowStatus.AlbumArtLayoutSettings.CoverImageShadowAmount;
ShadowRect.Translation = new(0, 0, amount);
}
private void UpdateAlbumArtOpacity()
{
switch (_liveStatesService.LiveStates.LyricsWindowStatus.LyricsDisplayType)
@@ -420,15 +398,11 @@ namespace BetterLyrics.WinUI3.Views
UpdateLyricsOpacity();
UpdateAlbumArtOpacity();
UpdateAlbumArtShadow();
UpdateTrackSummaryGridSpan();
UpdateAlbumArtGridSpan();
UpdateSongInfoStackPanelSpan();
UpdateLyricsPlaceholderSpan();
UpdateAlbumArtCornerRadius();
UpdateLyricsLayout();
}, Constants.Time.DebounceTimeout);
}
@@ -595,11 +569,6 @@ namespace BetterLyrics.WinUI3.Views
SystemVolumeHook.MasterVolume = ViewModel.Volume;
}
private void ShadowRect_Loaded(object sender, RoutedEventArgs e)
{
Shadow.Receivers.Add(ShadowCastGrid);
}
private void TitleAutoScrollHoverEffectView_PointerCanceled(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
TitleAutoScrollHoverEffectView.IsPlaying = false;
@@ -660,11 +629,6 @@ namespace BetterLyrics.WinUI3.Views
OnLayoutChanged();
}
private void ShadowCastGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateAlbumArtCornerRadius();
}
private void LyricsScrollViewer_PointerWheelChanged(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
LyricsCanvas.IsMouseScrolling = true;
@@ -730,14 +694,6 @@ namespace BetterLyrics.WinUI3.Views
{
RenderSongInfo();
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageRadius))
{
UpdateAlbumArtCornerRadius();
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageShadowAmount))
{
UpdateAlbumArtShadow();
}
else if (message.PropertyName == nameof(AlbumArtLayoutSettings.CoverImageHeight))
{
OnLayoutChanged();
@@ -796,18 +752,16 @@ namespace BetterLyrics.WinUI3.Views
{
if (message.PropertyName == nameof(IMediaSessionsService.AlbumArtBitmapImage))
{
LastAlbumArtImage.Source = AlbumArtImage.Source;
LastAlbumArtImage.ImageSource = AlbumArtImage.ImageSource;
LastAlbumArtImage.Opacity = 1;
await Task.Delay(Constants.Time.AnimationDuration);
AlbumArtImage.Opacity = 0;
await Task.Delay(Constants.Time.AnimationDuration);
AlbumArtImage.Source = message.NewValue;
AlbumArtImage.ImageSource = message.NewValue;
LastAlbumArtImage.Opacity = 0;
AlbumArtImage.Opacity = 1;
UpdateAlbumArtCornerRadius();
}
}
}
@@ -856,5 +810,6 @@ namespace BetterLyrics.WinUI3.Views
}
}
}
}
}