Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 63 additions & 27 deletions src/UniGetUI.Avalonia/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@
<AvaloniaResource Include="..\UniGetUI\Assets\Images\icon.png" Link="Assets\icon.png" />
<AvaloniaResource Include="..\UniGetUI\Assets\Images\icon_unsquare.png" Link="Assets\icon_unsquare.png" />
<AvaloniaResource Include="..\UniGetUI\Assets\Images\package_color.png" Link="Assets\package_color.png" />
<AvaloniaResource Include="..\UniGetUI\Assets\SplashScreen.png" Link="Assets\SplashScreen.png" />
<AvaloniaResource Include="..\UniGetUI\Assets\SplashScreen.theme-dark.png" Link="Assets\SplashScreen.theme-dark.png" />
<!-- Tray status icon variants -->
<AvaloniaResource Include="..\UniGetUI\Assets\Images\tray_empty_black.ico" Link="Assets\tray_empty_black.ico" />
<AvaloniaResource Include="..\UniGetUI\Assets\Images\tray_empty_white.ico" Link="Assets\tray_empty_white.ico" />
Expand Down Expand Up @@ -177,6 +179,9 @@
<Compile Update="Views\MainWindow.axaml.cs">
<DependentUpon>MainWindow.axaml</DependentUpon>
</Compile>
<Compile Update="Views\SplashWindow.axaml.cs">
<DependentUpon>SplashWindow.axaml</DependentUpon>
</Compile>
<Compile Update="Views\Pages\AbstractPackagesPage.axaml.cs">
<DependentUpon>AbstractPackagesPage.axaml</DependentUpon>
</Compile>
Expand Down
72 changes: 40 additions & 32 deletions src/UniGetUI.Avalonia/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -331,38 +331,46 @@
</StackPanel>

<!-- Centre: search box — vertically centred, no platform-specific margin -->
<StackPanel Grid.Column="1"
VerticalAlignment="Center"
automation:AutomationProperties.AccessibilityView="Control"
Orientation="Horizontal"
Spacing="0"
Opacity="0.6">
<TextBox x:Name="GlobalSearchBox"
Width="300"
MinHeight="20"
Height="30"
FontSize="15"
Margin="0,5,0,0"
CornerRadius="4,0,0,4"
PlaceholderText="{Binding GlobalSearchPlaceholder}"
IsEnabled="{Binding GlobalSearchEnabled}"
automation:AutomationProperties.Name="{Binding GlobalSearchPlaceholder}"
automation:AutomationProperties.AcceleratorKey="Ctrl+F"
Text="{Binding GlobalSearchText}"
KeyDown="SearchBox_KeyDown"/>
<Button Height="30"
Width="30"
Padding="3"
Margin="0,5,0,0"
CornerRadius="0,4,4,0"
IsEnabled="{Binding GlobalSearchEnabled}"
automation:AutomationProperties.Name="{Binding GlobalSearchPlaceholder}"
Command="{Binding SubmitGlobalSearchCommand}">
<controls:SvgIcon Path="avares://UniGetUI.Avalonia/Assets/Symbols/search.svg"
Width="18"
Height="18"/>
</Button>
</StackPanel>
<Border Grid.Column="1"
VerticalAlignment="Center"
Margin="0,5,0,0"
Height="30"
CornerRadius="4"
BorderBrush="{DynamicResource AppBorderBrush}"
BorderThickness="1"
Background="{DynamicResource AppBadgeBackground}"
ClipToBounds="True"
automation:AutomationProperties.AccessibilityView="Control">
<Grid ColumnDefinitions="300,30">
<TextBox x:Name="GlobalSearchBox"
Grid.Column="0"
MinHeight="20"
FontSize="15"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
PlaceholderText="{Binding GlobalSearchPlaceholder}"
IsEnabled="{Binding GlobalSearchEnabled}"
automation:AutomationProperties.Name="{Binding GlobalSearchPlaceholder}"
automation:AutomationProperties.AcceleratorKey="Ctrl+F"
Text="{Binding GlobalSearchText}"
KeyDown="SearchBox_KeyDown"/>
<Button Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Padding="3"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
IsEnabled="{Binding GlobalSearchEnabled}"
automation:AutomationProperties.Name="{Binding GlobalSearchPlaceholder}"
Command="{Binding SubmitGlobalSearchCommand}">
<controls:SvgIcon Path="avares://UniGetUI.Avalonia/Assets/Symbols/search.svg"
Width="18"
Height="18"/>
</Button>
</Grid>
</Border>

<!-- Right column: Linux window buttons on the far right -->
<Panel Grid.Column="2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,14 +605,17 @@
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
automation:AutomationProperties.Name="{Binding Package.AutomationName}"
VerticalAlignment="Top"
HorizontalAlignment="Center"/>
HorizontalAlignment="Center"
Padding="0"/>
<Button Click="CardOverflowButton_Click"
Width="22" Height="22" Padding="0"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
Background="Transparent" BorderThickness="0"
automation:AutomationProperties.Name="{t:Translate More options}">
<TextBlock Text="···" FontSize="16" VerticalAlignment="Center"/>
<TextBlock Text="···" FontSize="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Button>
</Panel>
</Grid>
Expand Down Expand Up @@ -651,7 +654,9 @@
VerticalAlignment="Top"
Background="Transparent" BorderThickness="0"
automation:AutomationProperties.Name="{t:Translate More options}">
<TextBlock Text="···" FontSize="16" VerticalAlignment="Center"/>
<TextBlock Text="···" FontSize="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Button>
<Panel Grid.Row="1" Width="64" Height="64"
Margin="0,-8,0,4"
Expand Down Expand Up @@ -712,28 +717,41 @@
IsVisible="{Binding MegaQueryVisible}"
RowDefinitions="*,64,*"
ColumnDefinitions="*,8*,64,*">
<TextBox x:Name="MegaQueryBlock"
Grid.Row="1"
Grid.Column="1"
Padding="16,0,10,0"
VerticalContentAlignment="Center"
CornerRadius="8,0,0,8"
FontSize="40"
PlaceholderText="{t:Translate Search for packages}"
Background="{DynamicResource AppWindowBackground}"
automation:AutomationProperties.Name="{t:Translate Search for packages}"
Text="{Binding MegaQueryText, Mode=TwoWay}"
KeyDown="MegaQueryBlock_KeyDown"/>
<Button x:Name="MegaFindButton"
Grid.Row="1"
Grid.Column="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="0,8,8,0"
automation:AutomationProperties.Name="{t:Translate Search for packages}"
Command="{Binding SubmitSearch}">
<controls:SvgIcon Path="avares://UniGetUI.Avalonia/Assets/Symbols/search.svg" Width="40" Height="40"/>
</Button>
<!-- Single outer border unifies the search field and search button so the seam between them is invisible. -->
<Border Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"
CornerRadius="8"
BorderBrush="{DynamicResource AppBorderBrush}"
BorderThickness="1"
Background="{DynamicResource AppWindowBackground}"
ClipToBounds="True">
<Grid ColumnDefinitions="*,64">
<TextBox x:Name="MegaQueryBlock"
Grid.Column="0"
Padding="16,0,10,0"
VerticalContentAlignment="Center"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
FontSize="40"
PlaceholderText="{t:Translate Search for packages}"
automation:AutomationProperties.Name="{t:Translate Search for packages}"
Text="{Binding MegaQueryText, Mode=TwoWay}"
KeyDown="MegaQueryBlock_KeyDown"/>
<Button x:Name="MegaFindButton"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
CornerRadius="0"
BorderThickness="0"
Background="Transparent"
automation:AutomationProperties.Name="{t:Translate Search for packages}"
Command="{Binding SubmitSearch}">
<controls:SvgIcon Path="avares://UniGetUI.Avalonia/Assets/Symbols/search.svg" Width="40" Height="40"/>
</Button>
</Grid>
</Border>
</Grid>

</Grid>
Expand Down
24 changes: 24 additions & 0 deletions src/UniGetUI.Avalonia/Views/SplashWindow.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UniGetUI.Avalonia.Views.SplashWindow"
Width="660" Height="340"
WindowStartupLocation="CenterScreen"
WindowDecorations="None"
Background="Transparent"
TransparencyLevelHint="Transparent"
CanResize="False"
ShowInTaskbar="False"
Topmost="True">
<Border CornerRadius="12"
Background="{DynamicResource AppDialogBackground}"
BorderBrush="{DynamicResource AppBorderBrush}"
BorderThickness="1"
BoxShadow="0 8 32 0 #40000000"
Margin="16">
<Image x:Name="SplashImage"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="24"/>
</Border>
</Window>
22 changes: 22 additions & 0 deletions src/UniGetUI.Avalonia/Views/SplashWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -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)));
}
}
Binary file modified src/UniGetUI/Assets/SplashScreen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/UniGetUI/Assets/SplashScreen.theme-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading