This commit is contained in:
GukSang.Jin
2026-03-16 19:10:33 +08:00
parent 34083df6de
commit 88a65233a7
26 changed files with 839 additions and 235 deletions

View File

@@ -0,0 +1,133 @@
using System;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Threading;
namespace
{
public partial class LoadingOverlayWindow : Window
{
private static readonly TimeSpan MinimumDisplayDuration = TimeSpan.FromMilliseconds(700);
private static readonly TimeSpan DismissAnimationDuration = TimeSpan.FromMilliseconds(240);
private readonly DateTime _shownAtUtc;
private bool _closeRequested;
public LoadingOverlayWindow()
{
InitializeComponent();
_shownAtUtc = DateTime.UtcNow;
}
public void AlignTo(Window referenceWindow)
{
if (referenceWindow == null)
{
return;
}
WindowState = WindowState.Normal;
double width = referenceWindow.ActualWidth > 0 ? referenceWindow.ActualWidth : referenceWindow.Width;
double height = referenceWindow.ActualHeight > 0 ? referenceWindow.ActualHeight : referenceWindow.Height;
if (width <= 0 || height <= 0)
{
Rect restoreBounds = referenceWindow.RestoreBounds;
width = restoreBounds.Width > 0 ? restoreBounds.Width : width;
height = restoreBounds.Height > 0 ? restoreBounds.Height : height;
}
Left = referenceWindow.Left;
Top = referenceWindow.Top;
Width = width;
Height = height;
}
public void MatchTopmost(Window referenceWindow)
{
if (referenceWindow == null)
{
return;
}
Topmost = referenceWindow.Topmost;
}
public void SetMessage(string title, string subtitle)
{
if (!string.IsNullOrWhiteSpace(title))
{
TitleText.Text = title;
}
if (!string.IsNullOrWhiteSpace(subtitle))
{
SubtitleText.Text = subtitle;
}
}
public void CloseWhenReady()
{
if (_closeRequested)
{
return;
}
_closeRequested = true;
TimeSpan remaining = MinimumDisplayDuration - (DateTime.UtcNow - _shownAtUtc);
if (remaining <= TimeSpan.Zero)
{
CloseOverlay();
return;
}
DispatcherTimer timer = new DispatcherTimer(
remaining,
DispatcherPriority.Background,
OnCloseTimerTick,
Dispatcher);
timer.Start();
}
private void OnCloseTimerTick(object sender, EventArgs e)
{
DispatcherTimer timer = sender as DispatcherTimer;
if (timer != null)
{
timer.Stop();
timer.Tick -= OnCloseTimerTick;
}
CloseOverlay();
}
private void CloseOverlay()
{
if (Dispatcher.HasShutdownStarted || Dispatcher.HasShutdownFinished || !IsLoaded)
{
return;
}
DoubleAnimation fadeOutAnimation = new DoubleAnimation
{
From = Opacity,
To = 0,
Duration = new Duration(DismissAnimationDuration),
FillBehavior = FillBehavior.Stop
};
fadeOutAnimation.Completed += (sender, args) =>
{
if (Dispatcher.HasShutdownStarted || Dispatcher.HasShutdownFinished || !IsLoaded)
{
return;
}
Close();
};
BeginAnimation(OpacityProperty, fadeOutAnimation);
}
}
}