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
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,16 @@
xmlns:automation="clr-namespace:Avalonia.Automation;assembly=Avalonia.Controls"
xmlns:vm="using:UniGetUI.Avalonia.ViewModels"
xmlns:controls="using:UniGetUI.Avalonia.Views.Controls"
xmlns:chrome="using:Avalonia.Controls.Chrome"
xmlns:t="using:UniGetUI.Avalonia.MarkupExtensions"
x:Class="UniGetUI.Avalonia.Views.ManageIgnoredUpdatesWindow"
x:DataType="vm:ManageIgnoredUpdatesViewModel"
Width="1100" MinWidth="520"
Width="850" MinWidth="520"
Height="500" MinHeight="280"
CanResize="True"
ShowInTaskbar="False"
Background="{DynamicResource IgnoredDialogBackground}"
Background="{DynamicResource AppDialogBackground}"
WindowStartupLocation="CenterOwner"
Title="">

<!-- Solid surfaces defined locally so the app-wide Mica overrides (which make most
dialog brushes translucent) can't bleed the desktop through this window. -->
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="IgnoredDialogBackground" Color="#ECECEC"/>
<SolidColorBrush x:Key="IgnoredListBackground" Color="#F9F9F9"/>
<SolidColorBrush x:Key="IgnoredRowHover" Color="#14000000"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="IgnoredDialogBackground" Color="#2C2C2C"/>
<SolidColorBrush x:Key="IgnoredListBackground" Color="#1F1F1F"/>
<SolidColorBrush x:Key="IgnoredRowHover" Color="#18FFFFFF"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Window.Resources>
Title="{Binding Title}">

<Window.Styles>
<!-- WinUI-style row hover highlight. The base Background must be set via a style
Expand All @@ -41,29 +21,16 @@
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style Selector="Border.row:pointerover">
<Setter Property="Background" Value="{DynamicResource IgnoredRowHover}"/>
</Style>
<!-- Avalonia 12's drawn window decorations add a full-screen caption button; hide it
so only minimize/maximize/close remain. -->
<Style Selector=":is(Control)[(chrome|WindowDecorationProperties.ElementRole)=FullScreenButton]">
<Setter Property="IsVisible" Value="False"/>
<Setter Property="Background" Value="{DynamicResource SubtleFillColorSecondaryBrush}"/>
</Style>
</Window.Styles>

<Grid RowDefinitions="Auto,Auto,*"
Margin="16,36,16,16"
<Grid RowDefinitions="Auto,*"
Margin="16"
RowSpacing="8">

<!-- ── Title ── -->
<TextBlock Grid.Row="0"
Text="{Binding Title}"
FontSize="20"
FontWeight="SemiBold"
Margin="0,0,0,4"
automation:AutomationProperties.HeadingLevel="1"/>

<!-- ── Header: description + Reset list button ── -->
<Grid Grid.Row="1" ColumnDefinitions="*,Auto" ColumnSpacing="8">
<!-- ── Header: description + Reset list button (title is carried by the window caption) ── -->
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" ColumnSpacing="8">

<TextBlock Text="{Binding Description}"
TextWrapping="Wrap"
Expand Down Expand Up @@ -111,8 +78,10 @@
</Grid>

<!-- ── Package list (mirrors the WinUI ItemsView: flat rows, no header) ── -->
<Border Grid.Row="2" Margin="0,4,0,0" CornerRadius="6"
Background="{DynamicResource IgnoredListBackground}">
<Border Grid.Row="1" Margin="0,4,0,0" CornerRadius="8"
BorderThickness="1"
BorderBrush="{DynamicResource AppBorderBrush}"
Background="{DynamicResource AppDialogPanelBackground}">
<Panel>

<!-- Empty state -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,65 @@
using Avalonia.Interactivity;
using Avalonia.Threading;
using UniGetUI.Avalonia.ViewModels;
using UniGetUI.Core.Logging;
using UniGetUI.Core.SettingsEngine;

namespace UniGetUI.Avalonia.Views;

public partial class ManageIgnoredUpdatesWindow : Window
{
public ManageIgnoredUpdatesWindow()
public ManageIgnoredUpdatesWindow(Window? owner = null)
{
var vm = new ManageIgnoredUpdatesViewModel();
DataContext = vm;
InitializeComponent();
UniGetUI.Avalonia.Infrastructure.MicaWindowHelper.Apply(this);

// Drop the OS title-bar strip (its background clashed with the dialog) but keep
// the system min/max/close buttons floating over the extended client area. Default
// WindowDecorations (Full) keeps the system buttons; extending the client area
// merges the title-bar region into the content.
ExtendClientAreaToDecorationsHint = true;
ExtendClientAreaTitleBarHeightHint = -1;
// Set the size before the window opens so CenterOwner positions it correctly.
ApplyInitialSize(owner);

vm.CloseRequested += (_, _) => Close();
}

// Restore the user's last size, falling back to the XAML default, and never open larger
// than the owner window (recovers the adaptive sizing of the pre-Avalonia overlay).
private void ApplyInitialSize(Window? owner)
{
double width = Width;
double height = Height;

string saved = Settings.GetValue(Settings.K.IgnoredUpdatesWindowSize);
if (!string.IsNullOrEmpty(saved))
{
string[] parts = saved.Split(',');
if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h))
{
width = w;
height = h;
}
}

if (owner is not null)
{
width = Math.Min(width, owner.Width - 40);
height = Math.Min(height, owner.Height - 40);
}

Width = Math.Max(MinWidth, width);
Height = Math.Max(MinHeight, height);
}

protected override void OnClosing(WindowClosingEventArgs e)
{
// Persist only the normal (non-maximized) size so the dialog reopens as the user left it.
if (WindowState == WindowState.Normal)
{
try { Settings.SetValue(Settings.K.IgnoredUpdatesWindowSize, $"{(int)Width},{(int)Height}"); }
catch (Exception ex) { Logger.Error(ex); }
}
base.OnClosing(e);
}

protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
Expand Down
17 changes: 16 additions & 1 deletion src/UniGetUI.Avalonia/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,24 @@ private void SetupTitleBarFocusOpacity()

// Match WinUI's inactive Mica appearance without invoking the permanent, global
// NotifyMicaUnavailable() fallback used when composition actually fails (#5111).
InactiveMicaFallback.Opacity = MicaWindowHelper.IsMicaEnabled() && !active ? 1.0 : 0.0;
// A partial (not full) overlay so the inactive window still keeps some of the Mica
// tint instead of flattening to solid grey. Skip it while a modal dialog is open: the
// window deactivates but shouldn't grey out behind its own dialog. Modeless owned
// windows (operation output/failure) don't count — the main window should still grey
// when the user switches to another application.
InactiveMicaFallback.Opacity =
MicaWindowHelper.IsMicaEnabled() && !active && !HasOpenModalDialog() ? 0.4 : 0.0;
});

// True when a window opened modally (ShowDialog) over this one is currently open.
private bool HasOpenModalDialog()
{
foreach (var owned in OwnedWindows)
if (owned.IsDialog)
return true;
return false;
}

private void SetupTitleBar()
{
if (OperatingSystem.IsMacOS())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
ViewModel.ManageIgnoredRequested += async () =>
{
if (GetMainWindow() is { } win)
await new ManageIgnoredUpdatesWindow().ShowDialog(win);
await new ManageIgnoredUpdatesWindow(win).ShowDialog(win);
};

// "New version" sort option is only relevant on the updates page
Expand Down Expand Up @@ -644,7 +644,7 @@

// Guard against spreadsheet formula injection (CWE-1236): package metadata is
// external, and a value starting with one of these executes as a formula in Excel/Sheets.
if (field.Length > 0 && "=+-@\t\r".IndexOf(field[0]) >= 0)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / Linux (Avalonia)

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / Linux (NativeAOT)

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / Windows (Avalonia)

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / Windows (NativeAOT)

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)

Check warning on line 647 in src/UniGetUI.Avalonia/Views/SoftwarePages/AbstractPackagesPage.axaml.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Use 'string.Contains' instead of 'string.IndexOf' to improve readability (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2249)
field = "'" + field;

if (field.IndexOfAny(['"', ',', '\n', '\r']) >= 0)
Expand Down
2 changes: 2 additions & 0 deletions src/UniGetUI.Core.Settings/SettingsEngine_Names.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public enum K
OperationHistory,
StartupPage,
WindowGeometry,
IgnoredUpdatesWindowSize,
ChangeBackupFileName,
CurrentSessionToken,
IgnoredPackageUpdates,
Expand Down Expand Up @@ -178,6 +179,7 @@ public static string ResolveKey(K key)
K.OperationHistory => "OperationHistory",
K.StartupPage => "StartupPage",
K.WindowGeometry => "WindowGeometry",
K.IgnoredUpdatesWindowSize => "IgnoredUpdatesWindowSize",
K.ChangeBackupFileName => "ChangeBackupFileName",
K.CurrentSessionToken => "CurrentSessionToken",
K.IgnoredPackageUpdates => "IgnoredPackageUpdates",
Expand Down
Loading