diff --git a/src/UniGetUI.Avalonia/App.axaml.cs b/src/UniGetUI.Avalonia/App.axaml.cs
index 6abd79e4ee..67ec82f6f1 100644
--- a/src/UniGetUI.Avalonia/App.axaml.cs
+++ b/src/UniGetUI.Avalonia/App.axaml.cs
@@ -54,42 +54,78 @@ public override void OnFrameworkInitializationCompleted()
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
- if (OperatingSystem.IsMacOS())
+ // Apply the saved theme before any window is shown so the splash
+ // appears in the user's preferred light/dark variant from the start.
+ ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme));
+
+ // Show the splash before any heavy initialization. Skipped in daemon
+ // mode since the app isn't supposed to be visible at all.
+ SplashWindow? splash = null;
+ if (!CoreData.WasDaemon)
{
- ProcessEnvironmentConfigurator.PrepareForCurrentPlatform();
- using var stream = AssetLoader.Open(new Uri("avares://UniGetUI.Avalonia/Assets/icon.png"));
- using var ms = new MemoryStream();
- stream.CopyTo(ms);
- MacOsNotificationBridge.SetDockIcon(ms.ToArray());
+ splash = new SplashWindow();
+ splash.Show();
}
- else
+
+ // Defer the rest of startup so the splash gets a chance to paint
+ // before we block the UI thread loading package managers and the
+ // main window XAML. Without this the splash window appears empty
+ // until init completes, defeating its purpose.
+ Dispatcher.UIThread.Post(() => StartMainWindow(desktop, splash), DispatcherPriority.Background);
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+
+ private static void StartMainWindow(IClassicDesktopStyleApplicationLifetime desktop, SplashWindow? splash)
+ {
+ if (OperatingSystem.IsMacOS())
+ {
+ ProcessEnvironmentConfigurator.PrepareForCurrentPlatform();
+ using var stream = AssetLoader.Open(new Uri("avares://UniGetUI.Avalonia/Assets/icon.png"));
+ using var ms = new MemoryStream();
+ stream.CopyTo(ms);
+ MacOsNotificationBridge.SetDockIcon(ms.ToArray());
+ }
+ else
+ {
+ ProcessEnvironmentConfigurator.ApplyProxySettingsToProcess();
+ }
+ PEInterface.LoadLoaders();
+ var mainWindow = new MainWindow();
+ desktop.MainWindow = mainWindow;
+ AvaloniaAppHost.SecondaryInstanceArgsReceived += args =>
+ HandleSecondaryInstanceArgs(mainWindow, args);
+
+ if (CoreData.WasDaemon)
+ {
+ // Start silently: hide the window on first open only.
+ // Opened fires on every Show() in Avalonia, so we must unsubscribe
+ // immediately or every ShowFromTray() call would hide the window again.
+ void HideOnce(object? s, EventArgs e)
{
- ProcessEnvironmentConfigurator.ApplyProxySettingsToProcess();
+ mainWindow.Opened -= HideOnce;
+ mainWindow.Hide();
}
- PEInterface.LoadLoaders();
- ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme));
- var mainWindow = new MainWindow();
- desktop.MainWindow = mainWindow;
- AvaloniaAppHost.SecondaryInstanceArgsReceived += args =>
- HandleSecondaryInstanceArgs(mainWindow, args);
+ mainWindow.Opened += HideOnce;
+ }
- if (CoreData.WasDaemon)
+ if (splash is not null)
+ {
+ var splashRef = splash;
+ void CloseSplashOnce(object? s, EventArgs e)
{
- // Start silently: hide the window on first open only.
- // Opened fires on every Show() in Avalonia, so we must unsubscribe
- // immediately or every ShowFromTray() call would hide the window again.
- void HideOnce(object? s, EventArgs e)
- {
- mainWindow.Opened -= HideOnce;
- mainWindow.Hide();
- }
- mainWindow.Opened += HideOnce;
+ mainWindow.Opened -= CloseSplashOnce;
+ splashRef.Close();
}
-
- _ = StartupAsync(mainWindow);
+ mainWindow.Opened += CloseSplashOnce;
}
- base.OnFrameworkInitializationCompleted();
+ // Framework auto-show already passed (we deferred via Dispatcher.Post),
+ // so we have to open the window ourselves.
+ mainWindow.Show();
+
+ _ = StartupAsync(mainWindow);
}
private static async Task StartupAsync(MainWindow mainWindow)
diff --git a/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
index 2514a337f6..d4a084aa27 100644
--- a/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
+++ b/src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
@@ -122,6 +122,8 @@
+
+
@@ -177,6 +179,9 @@
MainWindow.axaml
+
+ SplashWindow.axaml
+
AbstractPackagesPage.axaml
diff --git a/src/UniGetUI.Avalonia/Views/MainWindow.axaml b/src/UniGetUI.Avalonia/Views/MainWindow.axaml
index 4044c15d89..1c30bde762 100644
--- a/src/UniGetUI.Avalonia/Views/MainWindow.axaml
+++ b/src/UniGetUI.Avalonia/Views/MainWindow.axaml
@@ -331,38 +331,46 @@
-
-
-
-
+
+
+
+
+
+
diff --git a/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml
index a5ac09b29a..da41f7a75f 100644
--- a/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml
+++ b/src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml
@@ -605,14 +605,17 @@
+ HorizontalAlignment="Center"
+ Padding="0"/>
@@ -651,7 +654,9 @@
VerticalAlignment="Top"
Background="Transparent" BorderThickness="0"
automation:AutomationProperties.Name="{t:Translate More options}">
-
+
-
-
+
+
+
+
+
+
+
diff --git a/src/UniGetUI.Avalonia/Views/SplashWindow.axaml b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml
new file mode 100644
index 0000000000..067b760a61
--- /dev/null
+++ b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs
new file mode 100644
index 0000000000..7afc9dabbb
--- /dev/null
+++ b/src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs
@@ -0,0 +1,22 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media.Imaging;
+using Avalonia.Platform;
+using Avalonia.Styling;
+
+namespace UniGetUI.Avalonia.Views;
+
+public partial class SplashWindow : Window
+{
+ public SplashWindow()
+ {
+ InitializeComponent();
+
+ bool isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark;
+ string uri = isDark
+ ? "avares://UniGetUI.Avalonia/Assets/SplashScreen.theme-dark.png"
+ : "avares://UniGetUI.Avalonia/Assets/SplashScreen.png";
+ SplashImage.Source = new Bitmap(AssetLoader.Open(new Uri(uri)));
+ }
+}
diff --git a/src/UniGetUI/Assets/SplashScreen.png b/src/UniGetUI/Assets/SplashScreen.png
index cc079c3c6f..d4626ddd0e 100644
Binary files a/src/UniGetUI/Assets/SplashScreen.png and b/src/UniGetUI/Assets/SplashScreen.png differ
diff --git a/src/UniGetUI/Assets/SplashScreen.theme-dark.png b/src/UniGetUI/Assets/SplashScreen.theme-dark.png
new file mode 100644
index 0000000000..1509b3bfec
Binary files /dev/null and b/src/UniGetUI/Assets/SplashScreen.theme-dark.png differ