Simplify splash to fade; add themed about banners

Simplify splash startup visuals by removing the multi-mode/slide behavior and always using a fade animation. Update App to create SplashWindow without a StartupVisualMode parameter and remove related fields, layout configuration, slide animation, and easing helpers from SplashWindow. Clean up unused using. Replace the single about_banner asset with theme-aware variants (about_banner_dark.png and about_banner_light.png), delete the old about_banner.png, and update AboutSettingsPage to use a DynamicResource ImageBrush (AboutBannerBrush) that selects the appropriate banner per theme.
This commit is contained in:
lincube
2026-04-24 18:22:14 +08:00
parent 403cf280bb
commit 43c0ee6c06
7 changed files with 27 additions and 131 deletions

View File

@@ -143,8 +143,7 @@ public partial class App : Application
private static SplashWindow CreateSplashWindow()
{
var preferences = StartupVisualPreferencesResolver.Resolve();
var window = new SplashWindow(preferences.Mode);
var window = new SplashWindow();
TrySetSplashVersionInfo(window, LauncherRuntimeContext.Current);
return window;
}

View File

@@ -22,37 +22,15 @@
<Grid RowDefinitions="*,Auto"
Background="#0B0B0B">
<Grid Grid.Row="0">
<Grid x:Name="CompactHero"
Margin="24">
<TextBlock x:Name="AppNameText"
Text="LanMountain Desktop"
FontSize="24"
FontWeight="SemiBold"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Foreground="#F6F7FB" />
</Grid>
<Grid x:Name="FullscreenHero"
IsVisible="False">
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="24">
<Border Width="240"
Height="240"
Background="Transparent">
<Image Source="/Assets/logo_nightly.png"
Stretch="Uniform" />
</Border>
<TextBlock Text="LanMountain Desktop"
HorizontalAlignment="Center"
FontSize="26"
FontWeight="SemiBold"
Foreground="#F6F7FB" />
</StackPanel>
</Grid>
<Grid Grid.Row="0"
Margin="24">
<TextBlock x:Name="AppNameText"
Text="LanMountain Desktop"
FontSize="24"
FontWeight="SemiBold"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Foreground="#F6F7FB" />
</Grid>
<Border Grid.Row="1"

View File

@@ -7,7 +7,6 @@ using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Threading;
using LanMountainDesktop.Launcher.Services;
using LanMountainDesktop.Shared.Contracts.Launcher;
namespace LanMountainDesktop.Launcher.Views;
@@ -15,25 +14,14 @@ public partial class SplashWindow : Window, ISplashStageReporter
{
private const int DebugModeClickThreshold = 5;
private static readonly TimeSpan FadeAnimationDuration = TimeSpan.FromMilliseconds(160);
private static readonly TimeSpan SlideAnimationDuration = TimeSpan.FromMilliseconds(260);
private readonly StartupVisualMode _mode;
private int _versionTextClickCount;
private bool _isDebugModeOpened;
private bool _isOpened;
private bool _layoutConfigured;
private bool _dismissed;
private PixelPoint _targetPosition;
private PixelPoint _slideHiddenPosition;
public SplashWindow()
: this(StartupVisualMode.Fade)
{
}
public SplashWindow(StartupVisualMode mode)
{
_mode = mode;
AvaloniaXamlLoader.Load(this);
Loaded += OnWindowLoaded;
Opened += OnWindowOpened;
@@ -55,20 +43,9 @@ public partial class SplashWindow : Window, ISplashStageReporter
}
_isOpened = true;
ConfigureForVisualMode();
if (_mode == StartupVisualMode.Fade)
{
Opacity = 0d;
await AnimateOpacityAsync(0d, 1d, FadeAnimationDuration).ConfigureAwait(false);
return;
}
Opacity = 1d;
if (_mode == StartupVisualMode.SlideSplash)
{
await AnimateWindowPositionAsync(_slideHiddenPosition, _targetPosition, SlideAnimationDuration, EaseOutCubic).ConfigureAwait(false);
}
Opacity = 0d;
await AnimateOpacityAsync(0d, 1d, FadeAnimationDuration).ConfigureAwait(false);
}
public async Task DismissAsync()
@@ -80,25 +57,13 @@ public partial class SplashWindow : Window, ISplashStageReporter
_dismissed = true;
// 确保在UI线程上执行
if (!Dispatcher.UIThread.CheckAccess())
{
await Dispatcher.UIThread.InvokeAsync(async () => await DismissAsync());
return;
}
ConfigureForVisualMode();
if (_mode == StartupVisualMode.SlideSplash)
{
var from = Position;
await AnimateWindowPositionAsync(from, _slideHiddenPosition, SlideAnimationDuration, EaseInCubic).ConfigureAwait(false);
}
else if (_mode == StartupVisualMode.Fade)
{
await AnimateOpacityAsync(Opacity, 0d, FadeAnimationDuration).ConfigureAwait(false);
}
await AnimateOpacityAsync(Opacity, 0d, FadeAnimationDuration).ConfigureAwait(false);
Close();
}
@@ -194,46 +159,6 @@ public partial class SplashWindow : Window, ISplashStageReporter
UpdateStatus("[Debug Mode] Splash Preview");
}
private void ConfigureForVisualMode()
{
if (_layoutConfigured)
{
return;
}
_layoutConfigured = true;
var compactHero = this.FindControl<Grid>("CompactHero");
var fullscreenHero = this.FindControl<Grid>("FullscreenHero");
if (_mode == StartupVisualMode.Fade)
{
compactHero?.SetCurrentValue(IsVisibleProperty, true);
fullscreenHero?.SetCurrentValue(IsVisibleProperty, false);
Background = new SolidColorBrush(Color.Parse("#0B0B0B"));
Width = 480;
Height = 320;
WindowStartupLocation = WindowStartupLocation.CenterScreen;
return;
}
compactHero?.SetCurrentValue(IsVisibleProperty, false);
fullscreenHero?.SetCurrentValue(IsVisibleProperty, true);
Background = Brushes.Black;
WindowStartupLocation = WindowStartupLocation.Manual;
var screen = Screens?.Primary ?? Screens?.All.FirstOrDefault();
var workingArea = screen?.WorkingArea ?? new PixelRect(0, 0, 1920, 1080);
var scale = Math.Max(screen?.Scaling ?? 1d, 0.01d);
Width = workingArea.Width / scale;
Height = workingArea.Height / scale;
_targetPosition = new PixelPoint(workingArea.X, workingArea.Y);
_slideHiddenPosition = new PixelPoint(workingArea.X + workingArea.Width, workingArea.Y);
Position = _mode == StartupVisualMode.SlideSplash
? _slideHiddenPosition
: _targetPosition;
}
private void OnVersionTextClick(object? sender, PointerPressedEventArgs e)
{
if (_isDebugModeOpened)
@@ -292,20 +217,6 @@ public partial class SplashWindow : Window, ISplashStageReporter
}, duration, EaseOutCubic).ConfigureAwait(false);
}
private async Task AnimateWindowPositionAsync(
PixelPoint from,
PixelPoint to,
TimeSpan duration,
Func<double, double> easing)
{
await AnimateAsync(progress =>
{
var currentX = (int)Math.Round(from.X + ((to.X - from.X) * progress));
var currentY = (int)Math.Round(from.Y + ((to.Y - from.Y) * progress));
Position = new PixelPoint(currentX, currentY);
}, duration, easing).ConfigureAwait(false);
}
private async Task AnimateAsync(Action<double> update, TimeSpan duration, Func<double, double> easing)
{
if (duration <= TimeSpan.Zero)
@@ -347,6 +258,4 @@ public partial class SplashWindow : Window, ISplashStageReporter
var inverse = 1d - value;
return 1d - (inverse * inverse * inverse);
}
private static double EaseInCubic(double value) => value * value * value;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 999 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@@ -6,6 +6,19 @@
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
x:Class="LanMountainDesktop.Views.SettingsPages.AboutSettingsPage"
x:DataType="vm:AboutSettingsPageViewModel">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<ImageBrush x:Key="AboutBannerBrush" Source="/Assets/about_banner_light.png" Stretch="Uniform" AlignmentX="Center" AlignmentY="Center" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<ImageBrush x:Key="AboutBannerBrush" Source="/Assets/about_banner_dark.png" Stretch="Uniform" AlignmentX="Center" AlignmentY="Center" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="StackPanel.about-page-container">
<Setter Property="HorizontalAlignment" Value="Stretch" />
@@ -38,10 +51,7 @@
Classes="about-hero-card"
Height="240"
PointerPressed="OnAboutHeroCardPointerPressed">
<Image Source="/Assets/about_banner.png"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Panel Background="{DynamicResource AboutBannerBrush}" />
</Border>
<TextBlock Classes="settings-subsection-title"