mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-24 18:44:38 +08:00
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:
@@ -143,8 +143,7 @@ public partial class App : Application
|
|||||||
|
|
||||||
private static SplashWindow CreateSplashWindow()
|
private static SplashWindow CreateSplashWindow()
|
||||||
{
|
{
|
||||||
var preferences = StartupVisualPreferencesResolver.Resolve();
|
var window = new SplashWindow();
|
||||||
var window = new SplashWindow(preferences.Mode);
|
|
||||||
TrySetSplashVersionInfo(window, LauncherRuntimeContext.Current);
|
TrySetSplashVersionInfo(window, LauncherRuntimeContext.Current);
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,37 +22,15 @@
|
|||||||
|
|
||||||
<Grid RowDefinitions="*,Auto"
|
<Grid RowDefinitions="*,Auto"
|
||||||
Background="#0B0B0B">
|
Background="#0B0B0B">
|
||||||
<Grid Grid.Row="0">
|
<Grid Grid.Row="0"
|
||||||
<Grid x:Name="CompactHero"
|
Margin="24">
|
||||||
Margin="24">
|
<TextBlock x:Name="AppNameText"
|
||||||
<TextBlock x:Name="AppNameText"
|
Text="LanMountain Desktop"
|
||||||
Text="LanMountain Desktop"
|
FontSize="24"
|
||||||
FontSize="24"
|
FontWeight="SemiBold"
|
||||||
FontWeight="SemiBold"
|
VerticalAlignment="Top"
|
||||||
VerticalAlignment="Top"
|
HorizontalAlignment="Left"
|
||||||
HorizontalAlignment="Left"
|
Foreground="#F6F7FB" />
|
||||||
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>
|
||||||
|
|
||||||
<Border Grid.Row="1"
|
<Border Grid.Row="1"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Avalonia.Markup.Xaml;
|
|||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LanMountainDesktop.Launcher.Services;
|
using LanMountainDesktop.Launcher.Services;
|
||||||
using LanMountainDesktop.Shared.Contracts.Launcher;
|
|
||||||
|
|
||||||
namespace LanMountainDesktop.Launcher.Views;
|
namespace LanMountainDesktop.Launcher.Views;
|
||||||
|
|
||||||
@@ -15,25 +14,14 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
{
|
{
|
||||||
private const int DebugModeClickThreshold = 5;
|
private const int DebugModeClickThreshold = 5;
|
||||||
private static readonly TimeSpan FadeAnimationDuration = TimeSpan.FromMilliseconds(160);
|
private static readonly TimeSpan FadeAnimationDuration = TimeSpan.FromMilliseconds(160);
|
||||||
private static readonly TimeSpan SlideAnimationDuration = TimeSpan.FromMilliseconds(260);
|
|
||||||
|
|
||||||
private readonly StartupVisualMode _mode;
|
|
||||||
private int _versionTextClickCount;
|
private int _versionTextClickCount;
|
||||||
private bool _isDebugModeOpened;
|
private bool _isDebugModeOpened;
|
||||||
private bool _isOpened;
|
private bool _isOpened;
|
||||||
private bool _layoutConfigured;
|
|
||||||
private bool _dismissed;
|
private bool _dismissed;
|
||||||
private PixelPoint _targetPosition;
|
|
||||||
private PixelPoint _slideHiddenPosition;
|
|
||||||
|
|
||||||
public SplashWindow()
|
public SplashWindow()
|
||||||
: this(StartupVisualMode.Fade)
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
public SplashWindow(StartupVisualMode mode)
|
|
||||||
{
|
|
||||||
_mode = mode;
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
Loaded += OnWindowLoaded;
|
Loaded += OnWindowLoaded;
|
||||||
Opened += OnWindowOpened;
|
Opened += OnWindowOpened;
|
||||||
@@ -55,20 +43,9 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
}
|
}
|
||||||
|
|
||||||
_isOpened = true;
|
_isOpened = true;
|
||||||
ConfigureForVisualMode();
|
|
||||||
|
|
||||||
if (_mode == StartupVisualMode.Fade)
|
Opacity = 0d;
|
||||||
{
|
await AnimateOpacityAsync(0d, 1d, FadeAnimationDuration).ConfigureAwait(false);
|
||||||
Opacity = 0d;
|
|
||||||
await AnimateOpacityAsync(0d, 1d, FadeAnimationDuration).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Opacity = 1d;
|
|
||||||
if (_mode == StartupVisualMode.SlideSplash)
|
|
||||||
{
|
|
||||||
await AnimateWindowPositionAsync(_slideHiddenPosition, _targetPosition, SlideAnimationDuration, EaseOutCubic).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DismissAsync()
|
public async Task DismissAsync()
|
||||||
@@ -80,25 +57,13 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
|
|
||||||
_dismissed = true;
|
_dismissed = true;
|
||||||
|
|
||||||
// 确保在UI线程上执行
|
|
||||||
if (!Dispatcher.UIThread.CheckAccess())
|
if (!Dispatcher.UIThread.CheckAccess())
|
||||||
{
|
{
|
||||||
await Dispatcher.UIThread.InvokeAsync(async () => await DismissAsync());
|
await Dispatcher.UIThread.InvokeAsync(async () => await DismissAsync());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureForVisualMode();
|
await AnimateOpacityAsync(Opacity, 0d, FadeAnimationDuration).ConfigureAwait(false);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,46 +159,6 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
UpdateStatus("[Debug Mode] Splash Preview");
|
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)
|
private void OnVersionTextClick(object? sender, PointerPressedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_isDebugModeOpened)
|
if (_isDebugModeOpened)
|
||||||
@@ -292,20 +217,6 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
}, duration, EaseOutCubic).ConfigureAwait(false);
|
}, 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)
|
private async Task AnimateAsync(Action<double> update, TimeSpan duration, Func<double, double> easing)
|
||||||
{
|
{
|
||||||
if (duration <= TimeSpan.Zero)
|
if (duration <= TimeSpan.Zero)
|
||||||
@@ -347,6 +258,4 @@ public partial class SplashWindow : Window, ISplashStageReporter
|
|||||||
var inverse = 1d - value;
|
var inverse = 1d - value;
|
||||||
return 1d - (inverse * inverse * inverse);
|
return 1d - (inverse * inverse * inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double EaseInCubic(double value) => value * value * value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 999 KiB |
BIN
LanMountainDesktop/Assets/about_banner_dark.png
Normal file
BIN
LanMountainDesktop/Assets/about_banner_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 682 KiB |
BIN
LanMountainDesktop/Assets/about_banner_light.png
Normal file
BIN
LanMountainDesktop/Assets/about_banner_light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@@ -6,6 +6,19 @@
|
|||||||
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
|
xmlns:fi="using:FluentIcons.Avalonia.Fluent"
|
||||||
x:Class="LanMountainDesktop.Views.SettingsPages.AboutSettingsPage"
|
x:Class="LanMountainDesktop.Views.SettingsPages.AboutSettingsPage"
|
||||||
x:DataType="vm:AboutSettingsPageViewModel">
|
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>
|
<UserControl.Styles>
|
||||||
<Style Selector="StackPanel.about-page-container">
|
<Style Selector="StackPanel.about-page-container">
|
||||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
@@ -38,10 +51,7 @@
|
|||||||
Classes="about-hero-card"
|
Classes="about-hero-card"
|
||||||
Height="240"
|
Height="240"
|
||||||
PointerPressed="OnAboutHeroCardPointerPressed">
|
PointerPressed="OnAboutHeroCardPointerPressed">
|
||||||
<Image Source="/Assets/about_banner.png"
|
<Panel Background="{DynamicResource AboutBannerBrush}" />
|
||||||
Stretch="Uniform"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center" />
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock Classes="settings-subsection-title"
|
<TextBlock Classes="settings-subsection-title"
|
||||||
|
|||||||
Reference in New Issue
Block a user