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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,6 @@ UniGetUI Installer_winget-fix-test.exe
InstallerExtras/uninst-*.e32
src/.idea/
src/UniGetUI.v3.ncrunchsolution

# macOS Finder metadata
.DS_Store
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"version": "10.0.103",
"rollForward": "latestPatch"
}
}
}
103 changes: 99 additions & 4 deletions src/UniGetUI.Avalonia/App.axaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,103 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="UniGetUI.Avalonia.App"
xmlns:avaloniaApplication1="clr-namespace:UniGetUI.Avalonia"
xmlns:controls="using:UniGetUI.Avalonia.Views.Controls"
RequestedThemeVariant="Default">
<Application.Styles>
<StyleInclude Source="avares://UniGetUI.Avalonia/Styles/AppStyles.axaml" />
</Application.Styles>
</Application>

<Application.DataTemplates>
<avaloniaApplication1:ViewLocator/>
</Application.DataTemplates>

<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<!-- Settings cards -->
<SolidColorBrush x:Key="SettingsCardBackground" Color="#262B3C"/>
<SolidColorBrush x:Key="SettingsCardBorderBrush" Color="#3a3a3a"/>
<SolidColorBrush x:Key="SettingsCardHoverBackground" Color="#2e3448"/>
<!-- Window structure -->
<SolidColorBrush x:Key="AppWindowBackground" Color="#1e2025"/>
<SolidColorBrush x:Key="AppTitleBarBackground" Color="#313131"/>
<SolidColorBrush x:Key="AppSplitterBackground" Color="#14161a"/>
<SolidColorBrush x:Key="AppOperationsPanelBackground" Color="#16181c"/>
<SolidColorBrush x:Key="AppBorderBrush" Color="#323439"/>
<SolidColorBrush x:Key="AppBadgeBackground" Color="#3c3e44"/>
<!-- Dialogs -->
<SolidColorBrush x:Key="AppDialogBackground" Color="#1e2025"/>
<SolidColorBrush x:Key="AppDialogPanelBackground" Color="#2a2d34"/>
<SolidColorBrush x:Key="AppDialogSubtleBackground" Color="#3a3d44"/>
<SolidColorBrush x:Key="AppDialogDarkBackground" Color="#12141a"/>
<!-- Warning banner -->
<SolidColorBrush x:Key="WarningBannerBackground" Color="#3d2800"/>
<SolidColorBrush x:Key="WarningBannerBorderBrush" Color="#7a5200"/>
<SolidColorBrush x:Key="WarningBannerIconBackground" Color="#f0a500"/>
<SolidColorBrush x:Key="WarningBannerIconForeground" Color="#1a1000"/>
<SolidColorBrush x:Key="WarningBannerSubtext" Color="#ffe082"/>
<!-- Setting warning subtext (WarningText on cards) -->
<SolidColorBrush x:Key="SettingWarningTextForeground" Color="#ffc107"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<!-- Settings cards -->
<SolidColorBrush x:Key="SettingsCardBackground" Color="#f3f3f3"/>
<SolidColorBrush x:Key="SettingsCardBorderBrush" Color="#d0d0d0"/>
<SolidColorBrush x:Key="SettingsCardHoverBackground" Color="#e8e8e8"/>
<!-- Window structure -->
<SolidColorBrush x:Key="AppWindowBackground" Color="#f0f0f0"/>
<SolidColorBrush x:Key="AppTitleBarBackground" Color="#e0e0e0"/>
<SolidColorBrush x:Key="AppSplitterBackground" Color="#d8d8d8"/>
<SolidColorBrush x:Key="AppOperationsPanelBackground" Color="#f8f8f8"/>
<SolidColorBrush x:Key="AppBorderBrush" Color="#cccccc"/>
<SolidColorBrush x:Key="AppBadgeBackground" Color="#e0e0e0"/>
<!-- Dialogs -->
<SolidColorBrush x:Key="AppDialogBackground" Color="#ffffff"/>
<SolidColorBrush x:Key="AppDialogPanelBackground" Color="#f5f5f5"/>
<SolidColorBrush x:Key="AppDialogSubtleBackground" Color="#ebebeb"/>
<SolidColorBrush x:Key="AppDialogDarkBackground" Color="#e8e8e8"/>
<!-- Warning banner -->
<SolidColorBrush x:Key="WarningBannerBackground" Color="#fff8e1"/>
<SolidColorBrush x:Key="WarningBannerBorderBrush" Color="#d4a700"/>
<SolidColorBrush x:Key="WarningBannerIconBackground" Color="#f0a500"/>
<SolidColorBrush x:Key="WarningBannerIconForeground" Color="#1a1000"/>
<SolidColorBrush x:Key="WarningBannerSubtext" Color="#7a4f00"/>
<!-- Setting warning subtext (WarningText on cards) -->
<SolidColorBrush x:Key="SettingWarningTextForeground" Color="#a05c00"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>

<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>

<!-- SettingsCard appearance -->
<Style Selector="Border.settings-card">
<Setter Property="Background" Value="{DynamicResource SettingsCardBackground}"/>
<Setter Property="BorderBrush" Value="{DynamicResource SettingsCardBorderBrush}"/>
<Setter Property="Margin" Value="40,0"/>
</Style>
<Style Selector="Border.settings-card-clickable:pointerover">
<Setter Property="Background" Value="{DynamicResource SettingsCardHoverBackground}"/>
</Style>

<!-- Setting warning subtext (amber, both themes) -->
<Style Selector="TextBlock.setting-warning-text">
<Setter Property="Foreground" Value="{DynamicResource SettingWarningTextForeground}"/>
</Style>

<!-- Warning banner (InfoBar-style amber/golden) -->
<Style Selector="Border.warning-banner">
<Setter Property="Background" Value="{DynamicResource WarningBannerBackground}"/>
<Setter Property="BorderBrush" Value="{DynamicResource WarningBannerBorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Margin" Value="40,4,40,0"/>
</Style>

<!-- SvgIcon: inherit the Fluent foreground so icons match text colour in both themes -->
<Style Selector="controls|SvgIcon">
<Setter Property="Foreground" Value="{DynamicResource SystemControlForegroundBaseHighBrush}"/>
</Style>
</Application.Styles>
</Application>
89 changes: 64 additions & 25 deletions src/UniGetUI.Avalonia/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System.ComponentModel;
using System.Diagnostics;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
using Avalonia.Themes.Fluent;
using Devolutions.AvaloniaTheme.DevExpress;
using Devolutions.AvaloniaTheme.Linux;
using Devolutions.AvaloniaTheme.MacOS;
using UniGetUI.Avalonia.Views;
using UniGetUI.PackageEngine;
using CoreSettings = global::UniGetUI.Core.SettingsEngine.Settings;

namespace UniGetUI.Avalonia;

Expand All @@ -15,38 +15,77 @@ public partial class App : Application
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

Styles.Insert(0, CreatePlatformTheme());
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
if (OperatingSystem.IsMacOS())
ExpandMacOSPath();
PEInterface.LoadLoaders();
ApplyTheme(CoreSettings.GetValue(CoreSettings.K.PreferredTheme));
var mainWindow = new MainWindow();
#if DEBUG
mainWindow.AttachDevTools();
#endif
desktop.MainWindow = mainWindow;
_ = Task.Run(PEInterface.LoadManagers);
}

Name = "UniGetUI.Avalonia";
base.OnFrameworkInitializationCompleted();
}

private static Styles CreatePlatformTheme()
/// <summary>
/// macOS GUI apps start with a minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin).
/// Ask the user's login shell for its full PATH so package managers (npm, pip,
/// cargo, brew-installed tools, …) can be found.
/// </summary>
private static void ExpandMacOSPath()
{
Styles styles = OperatingSystem.IsWindows()
? new DevolutionsDevExpressTheme()
: OperatingSystem.IsMacOS()
? new DevolutionsMacOsTheme()
: OperatingSystem.IsLinux()
? new DevolutionsLinuxYaruTheme()
: new FluentTheme();

if (styles is ISupportInitialize initializable)
try
{
initializable.BeginInit();
initializable.EndInit();
using var process = new Process
{
StartInfo = new ProcessStartInfo("zsh", ["-l", "-c", "printenv PATH"])
{
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
},
};
process.Start();
string shellPath = process.StandardOutput.ReadToEnd().Trim();
process.WaitForExit(5000);
if (!string.IsNullOrEmpty(shellPath))
Environment.SetEnvironmentVariable("PATH", shellPath);
}
catch { /* keep the existing PATH if the shell can't be launched */ }
}

return styles;
public static void ApplyTheme(string value)
{
Current!.RequestedThemeVariant = value switch
{
"light" => ThemeVariant.Light,
"dark" => ThemeVariant.Dark,
_ => ThemeVariant.Default,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is default valid ? In the styles we only seem to have dark and light 🤔

};
}

public override void OnFrameworkInitializationCompleted()
private static void DisableAvaloniaDataAnnotationValidation()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();

// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
desktop.MainWindow = new MainWindow();
BindingPlugins.DataValidators.Remove(plugin);
}

base.OnFrameworkInitializationCompleted();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using Microsoft.Win32;
using UniGetUI.Avalonia.Views;
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.Core.SettingsEngine;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Avalonia.Threading;
using UniGetUI.Avalonia.Models;
using UniGetUI.Avalonia.Views;
using UniGetUI.Core.Data;
using UniGetUI.Core.IconEngine;
using UniGetUI.Core.Logging;
Expand Down
Loading