Skip to content

Commit dd5fb91

Browse files
committed
chores: add delay when automatically show and hide window
1 parent 041459e commit dd5fb91

File tree

15 files changed

+110
-125
lines changed

15 files changed

+110
-125
lines changed
6.84 KB
Loading
-83.9 KB
Binary file not shown.

BetterLyrics.WinUI3/BetterLyrics.WinUI3/BetterLyrics.WinUI3.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@
117117
<Content Update="Assets\AIMP.png">
118118
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
119119
</Content>
120+
<Content Update="Assets\AlbumArtPlaceholder.png">
121+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
122+
</Content>
120123
<Content Update="Assets\AMLLPlayer.png">
121124
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
122125
</Content>

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/ImageHelper.cs

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Runtime.InteropServices.WindowsRuntime;
1919
using System.Threading.Tasks;
2020
using Windows.Graphics.Imaging;
21+
using Windows.Storage;
2122
using Windows.Storage.Streams;
2223
using Windows.UI;
2324
using static Vanara.PInvoke.Ole32;
@@ -46,43 +47,14 @@ public static RandomAccessStreamReference ByteArrayToRandomAccessStreamReference
4647
return RandomAccessStreamReference.CreateFromStream(stream);
4748
}
4849

49-
public static async Task<IRandomAccessStream> CreateTextPlaceholderBytesAsync(int width, int height)
50+
public static async Task<IRandomAccessStream> GetAlbumArtPlaceholderAsync()
5051
{
51-
using var device = CanvasDevice.GetSharedDevice();
52-
using var renderTarget = new CanvasRenderTarget(device, width, height, 96);
53-
54-
// 随机生成渐变色
55-
Windows.UI.Color RandomColor()
56-
{
57-
var rand = new Random(Guid.NewGuid().GetHashCode());
58-
double h = rand.NextDouble() * 360;
59-
double s = 0.35 + rand.NextDouble() * 0.3; // 0.35~0.65,适中饱和度
60-
double l = 0.5 + rand.NextDouble() * 0.3; // 0.5~0.8,明亮
61-
return CommunityToolkit.WinUI.Helpers.ColorHelper.FromHsl(h, s, l);
62-
}
63-
64-
Windows.UI.Color color1 = RandomColor();
65-
Windows.UI.Color color2 = RandomColor();
66-
67-
using (var ds = renderTarget.CreateDrawingSession())
68-
{
69-
// 绘制线性渐变背景
70-
using var gradientBrush = new Microsoft.Graphics.Canvas.Brushes.CanvasLinearGradientBrush(ds, color1, color2)
71-
{
72-
StartPoint = new Vector2(0, 0),
73-
EndPoint = new Vector2(width, height)
74-
};
75-
ds.FillRectangle(0, 0, width, height, gradientBrush);
76-
}
77-
78-
// 保存为 PNG 并转为 byte[]
79-
var stream = new InMemoryRandomAccessStream();
80-
await renderTarget.SaveAsync(stream, CanvasBitmapFileFormat.Png);
81-
stream.Seek(0);
52+
Uri uri = new Uri($"ms-appx:///Assets/AlbumArtPlaceholder.png");
53+
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(uri);
54+
IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
8255
return stream;
8356
}
8457

85-
8658
public static Task<ThemeColorResult> GetAccentColorAsync(BitmapDecoder decoder, PaletteGeneratorType generatorType)
8759
{
8860
return generatorType switch

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Helper/WindowHelper.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using BetterLyrics.WinUI3.Views;
77
using CommunityToolkit.Mvvm.DependencyInjection;
88
using CommunityToolkit.WinUI;
9+
using Microsoft.UI.Dispatching;
910
using Microsoft.UI.Windowing;
1011
using Microsoft.UI.Xaml;
1112
using System;
@@ -31,6 +32,8 @@ public static class WindowHelper
3132
private static readonly ILiveStatesService _liveStatesService = Ioc.Default.GetRequiredService<ILiveStatesService>();
3233
private static readonly IMediaSessionsService _mediaSessionsService = Ioc.Default.GetRequiredService<IMediaSessionsService>();
3334

35+
private static DispatcherQueueTimer? _setLyricsWindowVisibilityByPlayingStatusTimer;
36+
3437
public static void HideWindow<T>()
3538
{
3639
var window = _activeWindows.Find(w => w is T);
@@ -346,27 +349,36 @@ public static void UpdateWorkArea<T>()
346349
Shell32.SHAppBarMessage(Shell32.ABM.ABM_SETPOS, ref abd);
347350
}
348351

349-
public static void SetLyricsWindowVisibilityByPlayingStatus()
352+
/// <summary>
353+
///
354+
/// </summary>
355+
/// <param name="dispatcherQueue">请确保此参数指向同一个对象,建议传值 BaseViewModel._dispatcherQueue</param>
356+
public static void SetLyricsWindowVisibilityByPlayingStatus(DispatcherQueue dispatcherQueue)
350357
{
351-
var window = GetWindowByWindowType<LyricsWindow>();
352-
if (window == null) return;
358+
_setLyricsWindowVisibilityByPlayingStatusTimer ??= dispatcherQueue.CreateTimer();
353359

354-
if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && !_mediaSessionsService.IsPlaying)
360+
_setLyricsWindowVisibilityByPlayingStatusTimer.Debounce(() =>
355361
{
356-
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
362+
var window = GetWindowByWindowType<LyricsWindow>();
363+
if (window == null) return;
364+
365+
if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && !_mediaSessionsService.IsPlaying)
357366
{
358-
SetIsWorkArea<LyricsWindow>(false);
367+
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
368+
{
369+
SetIsWorkArea<LyricsWindow>(false);
370+
}
371+
HideWindow<LyricsWindow>();
359372
}
360-
HideWindow<LyricsWindow>();
361-
}
362-
else if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && _mediaSessionsService.IsPlaying)
363-
{
364-
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
373+
else if (_liveStatesService.LiveStates.LyricsWindowStatus.AutoShowOrHideWindow && _mediaSessionsService.IsPlaying)
365374
{
366-
SetIsWorkArea<LyricsWindow>(true);
375+
if (_liveStatesService.LiveStates.LyricsWindowStatus.IsWorkArea)
376+
{
377+
SetIsWorkArea<LyricsWindow>(true);
378+
}
379+
OpenOrShowWindow<LyricsWindow>();
367380
}
368-
OpenOrShowWindow<LyricsWindow>();
369-
}
381+
}, Constants.Time.DebounceTimeout);
370382
}
371383

372384
}

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/LyricsWindowStatus.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,6 @@ private void OldAlbumArtLayoutSettings_PropertyChanged(object? sender, System.Co
9191
this.OnPropertyChanged(nameof(AlbumArtLayoutSettings));
9292
}
9393

94-
partial void OnAutoShowOrHideWindowChanged(bool value)
95-
{
96-
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus();
97-
}
98-
9994
public void UpdateMonitorNameAndBounds()
10095
{
10196
var lyricsWindow = WindowHelper.GetWindowByWindowType<LyricsWindow>();

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Models/SongInfo.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// 2025/6/23 by Zhe Fang
22

33
using CommunityToolkit.Mvvm.ComponentModel;
4+
using System;
45
using Windows.Graphics.Imaging;
56
using Windows.UI;
67

@@ -31,4 +32,14 @@ public partial class SongInfo : ObservableObject
3132

3233
public SongInfo() { }
3334
}
35+
36+
public static class SongInfoExtensions
37+
{
38+
public static SongInfo Placeholder => new()
39+
{
40+
Title = "N/A",
41+
Album = "N/A",
42+
Artist = "N/A",
43+
};
44+
}
3445
}

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/LiveStatesService/LiveStatesService.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ private async void LyricsWindowStatus_PropertyChanged(object? sender, System.Com
9393
case nameof(LyricsWindowStatus.TitleBarArea):
9494
WindowHelper.SetTitleBarArea<LyricsWindow>(LiveStates.LyricsWindowStatus.TitleBarArea);
9595
break;
96+
case nameof(LyricsWindowStatus.AutoShowOrHideWindow):
97+
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus(_dispatcherQueue);
98+
break;
9699
default:
97100
break;
98101
}
@@ -134,7 +137,7 @@ public async void RefreshLyricsWindowStatus()
134137
WindowHelper.SetIsAlwaysOnTop<LyricsWindow>(LiveStates.LyricsWindowStatus.IsAlwaysOnTop);
135138
WindowHelper.SetIsClickThrough<LyricsWindow>(LiveStates.LyricsWindowStatus.IsClickThrough);
136139
WindowHelper.SetIsBorderless<LyricsWindow>(LiveStates.LyricsWindowStatus.IsBorderless);
137-
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus();
140+
WindowHelper.SetLyricsWindowVisibilityByPlayingStatus(_dispatcherQueue);
138141
WindowHelper.SetTitleBarArea<LyricsWindow>(LiveStates.LyricsWindowStatus.TitleBarArea);
139142

140143
if (LiveStates.LyricsWindowStatus.IsWorkArea)

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.AlbumArtUpdater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ private async Task RefreshArtAlbum(CancellationToken token)
4646

4747
if (buffer == null)
4848
{
49-
using var placeHolderStream = await ImageHelper.CreateTextPlaceholderBytesAsync(500, 500);
49+
using var placeHolderStream = await ImageHelper.GetAlbumArtPlaceholderAsync();
5050
var tempBuffer = new Windows.Storage.Streams.Buffer((uint)placeHolderStream.Size);
5151
await placeHolderStream.ReadAsync(tempBuffer, (uint)placeHolderStream.Size, InputStreamOptions.None);
5252
buffer = tempBuffer;

BetterLyrics.WinUI3/BetterLyrics.WinUI3/Services/MediaSessionsService/MediaSessionsService.cs

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,14 @@ private void InitMediaManager()
213213
_mediaManager.CurrentMediaSessions.ToList().ForEach(x => RecordMediaSourceProviderInfo(x.Value));
214214
}
215215

216-
private void MediaManager_OnFocusedSessionChanged(MediaManager.MediaSession? mediaSession)
216+
private async void MediaManager_OnFocusedSessionChanged(MediaManager.MediaSession? mediaSession)
217217
{
218218
if (!_mediaManager.IsStarted) return;
219219

220-
SendFocusedMessagesAsync();
220+
await SendFocusedMessagesAsync();
221221
}
222222

223-
private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties timelineProperties)
223+
private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionTimelineProperties? timelineProperties)
224224
{
225225
if (!_mediaManager.IsStarted) return;
226226
if (mediaSession == null) return;
@@ -241,16 +241,16 @@ private void MediaManager_OnAnyTimelinePropertyChanged(MediaManager.MediaSession
241241
{
242242
if (IsMediaSourceTimelineSyncEnabled(mediaSession.Id))
243243
{
244-
_cachedPosition = timelineProperties.Position;
244+
_cachedPosition = timelineProperties?.Position ?? TimeSpan.Zero;
245245
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
246246
{
247-
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(_cachedPosition, timelineProperties.EndTime));
247+
TimelineChanged?.Invoke(this, new TimelineChangedEventArgs(_cachedPosition, timelineProperties?.EndTime ?? TimeSpan.Zero));
248248
});
249249
}
250250
}
251251
}
252252

253-
private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo playbackInfo)
253+
private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionPlaybackInfo? playbackInfo)
254254
{
255255
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
256256
{
@@ -268,7 +268,7 @@ private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession me
268268
}
269269
else
270270
{
271-
_cachedIsPlaying = playbackInfo.PlaybackStatus switch
271+
_cachedIsPlaying = playbackInfo?.PlaybackStatus switch
272272
{
273273
GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing => true,
274274
_ => false,
@@ -279,26 +279,28 @@ private void MediaManager_OnAnyPlaybackStateChanged(MediaManager.MediaSession me
279279
});
280280
}
281281

282-
private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties mediaProperties)
282+
private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession? mediaSession, GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProperties)
283283
{
284284
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () =>
285285
{
286286
if (!_mediaManager.IsStarted) return;
287-
if (mediaSession == null) return;
287+
if (mediaSession == null)
288+
{
289+
_cachedSongInfo = SongInfoExtensions.Placeholder;
290+
}
288291

289-
string sessionId = mediaSession.Id;
292+
string? sessionId = mediaSession?.Id;
290293

291294
var desiredSession = GetCurrentSession();
292295

293-
//RecordMediaSourceProviderInfo(mediaSession);
294296
if (mediaSession != desiredSession) return;
295297

296-
if (!IsMediaSourceEnabled(sessionId))
298+
if (sessionId != null && !IsMediaSourceEnabled(sessionId))
297299
{
298-
_cachedSongInfo = null;
300+
_cachedSongInfo = SongInfoExtensions.Placeholder;
299301

300302
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
301-
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
303+
mediaProperties?.Title, mediaProperties?.Artist, mediaProperties?.AlbumTitle);
302304

303305
if (sessionId == Constants.PlayerID.LXMusic)
304306
{
@@ -315,33 +317,33 @@ private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession me
315317
currentMediaSourceProviderInfo?.PositionOffset = 0;
316318
}
317319

318-
string fixedArtist = mediaProperties.Artist;
319-
string fixedAlbum = mediaProperties.AlbumTitle;
320+
string fixedArtist = mediaProperties?.Artist ?? "N/A";
321+
string fixedAlbum = mediaProperties?.AlbumTitle ?? "N/A";
320322
string? songId = null;
321323

322324
if (sessionId == Constants.PlayerID.AppleMusic || sessionId == Constants.PlayerID.AppleMusicAlternative)
323325
{
324-
fixedArtist = mediaProperties.Artist.Split(" — ").FirstOrDefault() ?? mediaProperties.Artist;
325-
fixedAlbum = mediaProperties.Artist.Split(" — ").LastOrDefault() ?? mediaProperties.AlbumTitle;
326+
fixedArtist = mediaProperties?.Artist.Split(" — ").FirstOrDefault() ?? (mediaProperties?.Artist ?? "N/A");
327+
fixedAlbum = mediaProperties?.Artist.Split(" — ").LastOrDefault() ?? (mediaProperties?.AlbumTitle ?? "N/A");
326328
}
327-
else if (PlayerIdMatcher.IsNeteaseFamily(sessionId))
329+
else if (PlayerIdMatcher.IsNeteaseFamily(sessionId ?? ""))
328330
{
329-
songId = mediaProperties.Genres.FirstOrDefault()?.Replace("NCM-", "");
331+
songId = mediaProperties?.Genres.FirstOrDefault()?.Replace("NCM-", "");
330332
}
331333

332334
_cachedSongInfo = new SongInfo
333335
{
334-
Title = mediaProperties.Title,
336+
Title = mediaProperties?.Title ?? "N/A",
335337
Artist = fixedArtist,
336338
Album = fixedAlbum,
337-
DurationMs = mediaSession.ControlSession.GetTimelineProperties().EndTime.TotalMilliseconds,
339+
DurationMs = mediaSession?.ControlSession?.GetTimelineProperties().EndTime.TotalMilliseconds,
338340
PlayerId = sessionId,
339341
SongId = songId
340342
};
341-
_cachedSongInfo.Duration = (int)(_cachedSongInfo.DurationMs / 1000f);
343+
_cachedSongInfo.Duration = (int)((_cachedSongInfo.DurationMs ?? 0) / 1000f);
342344

343345
_logger.LogInformation("Media properties changed: Title: {Title}, Artist: {Artist}, Album: {Album}",
344-
mediaProperties.Title, mediaProperties.Artist, mediaProperties.AlbumTitle);
346+
mediaProperties?.Title, mediaProperties?.Artist, mediaProperties?.AlbumTitle);
345347

346348
if (sessionId == Constants.PlayerID.LXMusic)
347349
{
@@ -356,7 +358,7 @@ private void MediaManager_OnAnyMediaPropertyChanged(MediaManager.MediaSession me
356358
{
357359
_SMTCAlbumArtBuffer = _lxMusicAlbumArtBytes.AsBuffer();
358360
}
359-
else if (mediaProperties.Thumbnail is IRandomAccessStreamReference streamReference)
361+
else if (mediaProperties?.Thumbnail is IRandomAccessStreamReference streamReference)
360362
{
361363
_SMTCAlbumArtBuffer = await ImageHelper.ToBufferAsync(streamReference);
362364
}
@@ -438,7 +440,7 @@ private void SendNullMessages()
438440
{
439441
_dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
440442
{
441-
_cachedSongInfo = null;
443+
_cachedSongInfo = SongInfoExtensions.Placeholder;
442444
_cachedIsPlaying = false;
443445
SongInfoChanged?.Invoke(this, new SongInfoChangedEventArgs(_cachedSongInfo));
444446
IsPlayingChanged?.Invoke(this, new IsPlayingChangedEventArgs(_cachedIsPlaying));
@@ -448,14 +450,21 @@ private void SendNullMessages()
448450

449451
private async Task SendFocusedMessagesAsync()
450452
{
453+
GlobalSystemMediaTransportControlsSessionMediaProperties? mediaProps = null;
454+
451455
var desiredSession = GetCurrentSession();
452-
if (desiredSession == null || desiredSession.ControlSession == null) return;
456+
//if (desiredSession == null || desiredSession.ControlSession == null) return;
457+
458+
try
459+
{
460+
mediaProps = await desiredSession?.ControlSession?.TryGetMediaPropertiesAsync();
461+
}
462+
catch (Exception) { }
463+
//if (desiredSession == null || desiredSession.ControlSession == null) return;
453464

454-
var mediaProps = await desiredSession.ControlSession.TryGetMediaPropertiesAsync();
455-
if (desiredSession == null || desiredSession.ControlSession == null) return;
456-
MediaManager_OnAnyTimelinePropertyChanged(desiredSession, desiredSession.ControlSession.GetTimelineProperties());
465+
MediaManager_OnAnyTimelinePropertyChanged(desiredSession, desiredSession?.ControlSession?.GetTimelineProperties());
457466
MediaManager_OnAnyMediaPropertyChanged(desiredSession, mediaProps);
458-
MediaManager_OnAnyPlaybackStateChanged(desiredSession, desiredSession.ControlSession.GetPlaybackInfo());
467+
MediaManager_OnAnyPlaybackStateChanged(desiredSession, desiredSession?.ControlSession?.GetPlaybackInfo());
459468
}
460469

461470
private void StartSSE()

0 commit comments

Comments
 (0)