自动隐藏播控栏可关闭。加入部分亚克力效果

This commit is contained in:
LanZhan
2026-03-24 00:45:49 +08:00
parent 3185de7023
commit 7acfc4e3f9
16 changed files with 92 additions and 34 deletions

View File

@@ -31,14 +31,14 @@
<DoubleAnimation Storyboard.TargetName="RootPlayBar"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
From="0" To="117"
Duration="0:0:0.3">
Duration="0:0:0.6">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseOut"/>
<CubicEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="RootPlayBar"
Storyboard.TargetProperty="Opacity" From="1"
To="0" Duration="0:0:0.3"/>
To="0" Duration="0:0:0.6"/>
</Storyboard>
<Storyboard x:Name="ShowInfoBarStoryboard">
<DoubleAnimation Storyboard.TargetName="ErrorInfoBar"

View File

@@ -34,6 +34,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
private DateTimeOffset _shellFrameMarginAnimationStart;
private double _shellFrameMarginFrom;
private double _shellFrameMarginTo;
private double _shellFrameMarginAnimationDuration;
// 热键 ID
private const int HOTKEY_ID_VOLUME_UP = 1;
@@ -96,9 +97,10 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
private void OnRootPlayBarChanged(object? sender, PropertyChangedEventArgs e)
{
if (
e.PropertyName
is nameof(RootPlayBarViewModel.IsDetail)
or nameof(RootPlayBarViewModel.IsFullScreen)
Settings.IsAutoHidePlaybackControlBar
&& e.PropertyName
is nameof(RootPlayBarViewModel.IsDetail)
or nameof(RootPlayBarViewModel.IsFullScreen)
)
{
if (Data.RootPlayBarViewModel!.IsDetail && Data.RootPlayBarViewModel.IsFullScreen)
@@ -110,7 +112,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
RootGrid.PointerMoved -= RootGrid_PointerMoved;
if (_isPlayBarHidden)
{
AnimateShellFrameBottomMargin(117);
AnimateShellFrameBottomMargin(117, 300);
ShowPlayBarStoryboard.Begin();
_isPlayBarHidden = false;
StopPlayBarTimer();
@@ -129,7 +131,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
{
if (_isPlayBarHidden)
{
AnimateShellFrameBottomMargin(117);
AnimateShellFrameBottomMargin(117, 300);
ShowPlayBarStoryboard.Begin();
_isPlayBarHidden = false;
}
@@ -154,7 +156,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
&& !_isPlayBarHidden
)
{
AnimateShellFrameBottomMargin(0);
AnimateShellFrameBottomMargin(0, 600);
HidePlayBarStoryboard.Begin();
_isPlayBarHidden = true;
}
@@ -186,7 +188,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
}
}
private void AnimateShellFrameBottomMargin(double targetBottom)
private void AnimateShellFrameBottomMargin(double targetBottom, double durationMs)
{
var currentBottom = ShellFrame.Margin.Bottom;
if (Math.Abs(currentBottom - targetBottom) < 0.1)
@@ -203,6 +205,7 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
_shellFrameMarginFrom = currentBottom;
_shellFrameMarginTo = targetBottom;
_shellFrameMarginAnimationDuration = durationMs;
_shellFrameMarginAnimationStart = DateTimeOffset.Now;
_shellFrameMarginAnimationTimer.Start();
@@ -213,10 +216,15 @@ public sealed partial class MainWindow : WindowEx, IRecipient<LogMessage>
object args
)
{
const double durationMs = 300;
var elapsedMs = (DateTimeOffset.Now - _shellFrameMarginAnimationStart).TotalMilliseconds;
var progress = Math.Clamp(elapsedMs / durationMs, 0d, 1d);
var easedProgress = 1 - Math.Pow(1 - progress, 3);
var progress = Math.Clamp(elapsedMs / _shellFrameMarginAnimationDuration, 0d, 1d);
// 显示 (To > From): EaseOut (1 - (1-x)^3)
// 隐藏 (To < From): EaseIn (x^3)
var easedProgress =
_shellFrameMarginTo > _shellFrameMarginFrom
? 1 - Math.Pow(1 - progress, 3)
: Math.Pow(progress, 3);
var currentBottom =
_shellFrameMarginFrom + ((_shellFrameMarginTo - _shellFrameMarginFrom) * easedProgress);

View File

@@ -204,7 +204,22 @@ public static class Settings
}
}
}
#endregion
/// <summary>
/// 是否在全屏模式下自动隐藏播放控制栏
/// </summary>
public static bool IsAutoHidePlaybackControlBar
{
get;
set
{
if (field != value)
{
field = value;
_localSettingsService.SaveSettingAsync(nameof(IsAutoHidePlaybackControlBar), value);
}
}
}
/// <summary>
/// 是否启用均衡器
@@ -237,6 +252,7 @@ public static class Settings
}
}
}
#endregion
public static async Task InitializeAsync()
{
@@ -266,6 +282,9 @@ public static class Settings
IsWindowBackgroundFollowsCover = await _localSettingsService.ReadSettingAsync<bool>(
nameof(IsWindowBackgroundFollowsCover)
);
IsAutoHidePlaybackControlBar = await _localSettingsService.ReadSettingAsync<bool>(
nameof(IsAutoHidePlaybackControlBar)
);
if (NotFirstUsed)
{
@@ -292,6 +311,7 @@ public static class Settings
var lightColor = Color.FromArgb(255, 252, 252, 252);
TintColor =
App.Current.RequestedTheme == ApplicationTheme.Dark ? darkColor : lightColor;
IsAutoHidePlaybackControlBar = true;
}
InitializedLaterAsync();
}

View File

@@ -213,6 +213,9 @@
<data name="Settings_RefreshLibrary.Header" xml:space="preserve">
<value>Refresh libraries</value>
</data>
<data name="Settings_AutoHidePlaybackControlBar.Header" xml:space="preserve">
<value>Automatically hide the playback control bar in full screen mode</value>
</data>
<data name="Settings_ExclusiveMode.Header" xml:space="preserve">
<value>Exclusive mode (Experimental)</value>
</data>

View File

@@ -213,6 +213,9 @@
<data name="Settings_RefreshLibrary.Header" xml:space="preserve">
<value>刷新库</value>
</data>
<data name="Settings_AutoHidePlaybackControlBar.Header" xml:space="preserve">
<value>在全屏模式下自动隐藏播控栏</value>
</data>
<data name="Settings_ExclusiveMode.Header" xml:space="preserve">
<value>独占模式 (实验性)</value>
</data>

View File

@@ -1,14 +1,12 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="AccentTextFillBrush" Color="{ThemeResource SystemAccentColorDark1}"/>
<SolidColorBrush x:Key="AlternateBackgroundBrush"
Opacity="0.8"
Color="#FDFEFE"/>
<SolidColorBrush x:Key="RequiredBrush" Color="#c50500"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="AccentTextFillBrush" Color="{ThemeResource SystemAccentColorLight1}"/>
<SolidColorBrush x:Key="AlternateBackgroundBrush"
Opacity="0.8"
Color="#323232"/>

View File

@@ -194,6 +194,18 @@ public sealed partial class SettingsViewModel
_dynamicBackgroundService.IsEnabled = value;
}
/// <summary>
/// 是否在全屏模式下自动隐藏播放控制栏
/// </summary>
[ObservableProperty]
public partial bool IsAutoHidePlaybackControlBar { get; set; } =
Settings.IsAutoHidePlaybackControlBar;
partial void OnIsAutoHidePlaybackControlBarChanged(bool value)
{
Settings.IsAutoHidePlaybackControlBar = value;
}
/// <summary>
/// 版本信息
/// </summary>

View File

@@ -158,7 +158,7 @@ public sealed partial class LocalAlbumDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);

View File

@@ -181,7 +181,7 @@ public sealed partial class LocalArtistDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);

View File

@@ -69,14 +69,14 @@
<DoubleAnimation Storyboard.TargetName="AppTitleBar"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
From="0" To="-33"
Duration="0:0:0.3">
Duration="0:0:0.6">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="AppTitleBar"
Storyboard.TargetProperty="Opacity" From="1"
To="0" Duration="0:0:0.3"/>
To="0" Duration="0:0:0.6"/>
</Storyboard>
</Page.Resources>

View File

@@ -32,6 +32,8 @@ public sealed partial class LyricPage : Page, IDisposable
private DateTimeOffset _contentGridMarginAnimationStart;
private double _contentGridMarginFrom;
private double _contentGridMarginTo;
private double _contentGridMarginAnimationDuration;
private CancellationTokenSource? _coverLoadWaitCts;
public LyricPage()
@@ -142,9 +144,10 @@ public sealed partial class LyricPage : Page, IDisposable
private void OnRootPlayBarChanged(object? sender, PropertyChangedEventArgs e)
{
if (
e.PropertyName
is nameof(RootPlayBarViewModel.IsDetail)
or nameof(RootPlayBarViewModel.IsFullScreen)
Settings.IsAutoHidePlaybackControlBar
&& e.PropertyName
is nameof(RootPlayBarViewModel.IsDetail)
or nameof(RootPlayBarViewModel.IsFullScreen)
)
{
if (Data.RootPlayBarViewModel!.IsDetail && Data.RootPlayBarViewModel.IsFullScreen)
@@ -156,7 +159,7 @@ public sealed partial class LyricPage : Page, IDisposable
RootGrid.PointerMoved -= RootGrid_PointerMoved;
if (_isTitleBarHidden)
{
AnimateContentGridTopMargin(0);
AnimateContentGridTopMargin(0, 300);
ShowTitleBarStoryboard.Begin();
_isTitleBarHidden = false;
StopTitleBarTimer();
@@ -174,7 +177,7 @@ public sealed partial class LyricPage : Page, IDisposable
{
if (_isTitleBarHidden)
{
AnimateContentGridTopMargin(0);
AnimateContentGridTopMargin(0, 300);
ShowTitleBarStoryboard.Begin();
_isTitleBarHidden = false;
}
@@ -199,7 +202,7 @@ public sealed partial class LyricPage : Page, IDisposable
&& !_isTitleBarHidden
)
{
AnimateContentGridTopMargin(-33);
AnimateContentGridTopMargin(-33, 600);
HideTitleBarStoryboard.Begin();
_isTitleBarHidden = true;
}
@@ -231,7 +234,7 @@ public sealed partial class LyricPage : Page, IDisposable
}
}
private void AnimateContentGridTopMargin(double targetTop)
private void AnimateContentGridTopMargin(double targetTop, double durationMs)
{
var currentTop = ContentGrid.Margin.Top;
if (Math.Abs(currentTop - targetTop) < 0.1)
@@ -248,6 +251,7 @@ public sealed partial class LyricPage : Page, IDisposable
_contentGridMarginFrom = currentTop;
_contentGridMarginTo = targetTop;
_contentGridMarginAnimationDuration = durationMs;
_contentGridMarginAnimationStart = DateTimeOffset.Now;
_contentGridMarginAnimationTimer.Start();
@@ -255,10 +259,15 @@ public sealed partial class LyricPage : Page, IDisposable
private void ContentGridMarginAnimationTick(DispatcherQueueTimer sender, object args)
{
const double durationMs = 300;
var elapsedMs = (DateTimeOffset.Now - _contentGridMarginAnimationStart).TotalMilliseconds;
var progress = Math.Clamp(elapsedMs / durationMs, 0d, 1d);
var easedProgress = 1 - Math.Pow(1 - progress, 3);
var progress = Math.Clamp(elapsedMs / _contentGridMarginAnimationDuration, 0d, 1d);
// 显示 (To > From): EaseOut
// 隐藏 (To < From): EaseIn
var easedProgress =
_contentGridMarginTo > _contentGridMarginFrom
? 1 - Math.Pow(1 - progress, 3)
: Math.Pow(progress, 3);
var currentTop =
_contentGridMarginFrom
@@ -413,6 +422,7 @@ public sealed partial class LyricPage : Page, IDisposable
visual.Scale = new Vector3(initialScaleX, initialScaleY, 1f);
var compositor = visual.Compositor;
var scaleAnimation = compositor.CreateVector3KeyFrameAnimation();
scaleAnimation.InsertKeyFrame(1f, Vector3.One);
scaleAnimation.Duration = TimeSpan.FromMilliseconds(450);

View File

@@ -157,7 +157,7 @@ public sealed partial class OnlineAlbumDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);

View File

@@ -170,7 +170,7 @@ public sealed partial class OnlineArtistDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);
var contentVisual = ElementCompositionPreview.GetElementVisual(ContentContainer);

View File

@@ -148,7 +148,7 @@ public sealed partial class OnlinePlayListDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);

View File

@@ -148,7 +148,7 @@ public sealed partial class PlayListDetailPage : Page
backgroundScaleFactorNode,
progressNode
);
ExpressionNode backgroundOpacityAnimation = progressNode;
ExpressionNode backgroundOpacityAnimation = progressNode * 0.7f;
backgroundVisual.StartAnimation("Scale.Y", backgroundScaleAnimation);
backgroundVisual.StartAnimation("Opacity", backgroundOpacityAnimation);

View File

@@ -285,6 +285,10 @@
<toolkit:SettingsCard x:Uid="Settings_WindowBackgroundFollowsCover" HeaderIcon="{ui:FontIcon FontFamily={StaticResource UntamedFontFamily}, Glyph=&#xE790;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.IsWindowBackgroundFollowsCover, Mode=TwoWay}"/>
</toolkit:SettingsCard>
<toolkit:SettingsCard x:Uid="Settings_AutoHidePlaybackControlBar" HeaderIcon="{ui:FontIcon FontFamily={StaticResource UntamedFontFamily}, Glyph=&#xE745;}">
<ToggleSwitch IsOn="{x:Bind ViewModel.IsAutoHidePlaybackControlBar, Mode=TwoWay}"/>
</toolkit:SettingsCard>
</StackPanel>
<!-- 开发者选项 -->