Skip to content
Open
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
1 change: 1 addition & 0 deletions src/UniGetUI.Avalonia/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml"/>
<StyleInclude Source="avares://UniGetUI.Avalonia/Assets/Styles/Styles.Common.axaml"/>
</Application.Styles>
</Application>
1 change: 1 addition & 0 deletions src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@

<ItemGroup>
<PackageReference Include="Avalonia" Version="12.0.4" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="12.0.0" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="12.0.0" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.4" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.4" />
Expand Down
2 changes: 1 addition & 1 deletion src/UniGetUI.Avalonia/ViewModels/SidebarViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ partial void OnIsPaneOpenChanged(bool value)
OnPropertyChanged(nameof(BundlesBadgeCompactVisible));
}

public double PaneWidth => IsPaneOpen ? 250 : 72;
public double PaneWidth => IsPaneOpen ? 250 : 64;

public bool UpdatesBadgeExpandedVisible => UpdatesBadgeVisible && IsPaneOpen;
public bool UpdatesBadgeCompactVisible => UpdatesBadgeVisible && !IsPaneOpen;
Expand Down
104 changes: 104 additions & 0 deletions src/UniGetUI.Avalonia/Views/Controls/LogTextEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System.Text;
using Avalonia;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.Document;
using AvaloniaEdit.Rendering;
using UniGetUI.Avalonia.ViewModels.Pages.LogPages;

namespace UniGetUI.Avalonia.Views.Controls;

// Read-only colored log/console viewer shared by every log and command-output view: virtualized
// rendering (smooth scroll), free character-level selection across lines, per-line colors, and a
// theme-aware hyperlink color.
public class LogTextEditor : TextEditor
{
// Per physical line color, indexed by 0-based document line number.
private readonly List<IBrush> _lineColors = [];

// Use AvaloniaEdit's TextEditor theme/template; a subclass key has no matching ControlTheme.
protected override Type StyleKeyOverride => typeof(TextEditor);

public LogTextEditor()
{
IsReadOnly = true;
ShowLineNumbers = false;
WordWrap = true;
Background = Brushes.Transparent;
FontFamily = new FontFamily("Cascadia Mono,Consolas,Menlo,monospace");
FontSize = 12;
Padding = new Thickness(8);
HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;

TextArea.TextView.LineTransformers.Add(new SeverityColorizer(_lineColors));
UpdateLinkColor();
ActualThemeVariantChanged += (_, _) => UpdateLinkColor();
}

public void SetLines(IEnumerable<LogLineItem> lines)
{
_lineColors.Clear();
var sb = new StringBuilder();
bool first = true;

foreach (var item in lines)
{
foreach (string physicalLine in item.Text.Split('\n'))
{
if (!first) sb.Append('\n');
sb.Append(physicalLine);
_lineColors.Add(item.Foreground);
first = false;
}
}

Text = sb.ToString();
TextArea.TextView.Redraw();
}

public void AppendLine(LogLineItem line)
{
var sb = new StringBuilder();
foreach (string physicalLine in line.Text.Split('\n'))
{
if (Document.TextLength > 0 || sb.Length > 0)
sb.Append('\n');
sb.Append(physicalLine);
_lineColors.Add(line.Foreground);
}

Document.Insert(Document.TextLength, sb.ToString());
}

public void ClearLines()
{
_lineColors.Clear();
Text = string.Empty;
}

public void ScrollToBottom() => ScrollToEnd();

// AvaloniaEdit auto-links URLs; its default link brush is too dark to read on the dark theme.
private void UpdateLinkColor()
{
bool isDark = Application.Current?.ActualThemeVariant == ThemeVariant.Dark;
TextArea.TextView.LinkTextForegroundBrush =
new SolidColorBrush(isDark ? Color.FromRgb(100, 170, 255) : Color.FromRgb(0, 0, 205));
}

private sealed class SeverityColorizer(List<IBrush> lineColors) : DocumentColorizingTransformer
{
protected override void ColorizeLine(DocumentLine line)
{
if (line.Length == 0) return;
int index = line.LineNumber - 1;
if (index < 0 || index >= lineColors.Count) return;

IBrush brush = lineColors[index];
ChangeLinePart(line.Offset, line.EndOffset, element => element.TextRunProperties.SetForegroundBrush(brush));
}
}
}
10 changes: 6 additions & 4 deletions src/UniGetUI.Avalonia/Views/Controls/Settings/SettingsCard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using UniGetUI.Avalonia.Views.Controls;
using ICommand = System.Windows.Input.ICommand;

namespace UniGetUI.Avalonia.Views.Controls.Settings;
Expand All @@ -23,7 +24,7 @@ public class SettingsCard : UserControl
private readonly ContentControl _descriptionPresenter;
private readonly ContentControl _contentPresenter;
private readonly StackPanel _descriptionRow;
private readonly TextBlock _chevron;
private readonly SvgIcon _chevron;

// ── Styled properties ──────────────────────────────────────────────────
public static readonly StyledProperty<object?> HeaderProperty =
Expand Down Expand Up @@ -178,10 +179,11 @@ public SettingsCard()
Margin = new Thickness(16, 0, 0, 0),
};

_chevron = new TextBlock
_chevron = new SvgIcon
{
Text = "›",
FontSize = 20,
Path = "avares://UniGetUI.Avalonia/Assets/Symbols/forward.svg",
Width = 16,
Height = 16,
VerticalAlignment = VerticalAlignment.Center,
Opacity = 0.6,
Margin = new Thickness(8, 0, 0, 0),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:automation="clr-namespace:Avalonia.Automation;assembly=Avalonia.Controls"
xmlns:controls="using:UniGetUI.Avalonia.Views.Controls"
x:Class="UniGetUI.Avalonia.Views.DialogPages.OperationFailedDialog"
Width="800" MinWidth="500"
Height="550" MinHeight="300"
Expand All @@ -19,20 +20,14 @@
</Border>

<!-- ── Colored output log ── -->
<ScrollViewer Grid.Row="1"
x:Name="OutputScroll"
Margin="8,0,8,8"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Background="{DynamicResource AppDialogDarkBackground}"
CornerRadius="6">
<SelectableTextBlock x:Name="OutputText"
Padding="8"
FontFamily="Cascadia Mono,Consolas,Menlo,monospace"
FontSize="12"
TextWrapping="Wrap"
automation:AutomationProperties.AccessibilityView="Raw"/>
</ScrollViewer>
<Border Grid.Row="1"
Margin="8,0,8,8"
CornerRadius="6"
ClipToBounds="True"
Background="{DynamicResource AppDialogDarkBackground}">
<controls:LogTextEditor x:Name="OutputText"
automation:AutomationProperties.AccessibilityView="Raw"/>
</Border>

<!-- ── Footer buttons ── -->
<Border Grid.Row="2"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Threading;
using UniGetUI.Avalonia.ViewModels.Pages.LogPages;
using UniGetUI.Core.Tools;
using UniGetUI.PackageEngine.Enums;
using UniGetUI.PackageEngine.Operations;
Expand All @@ -30,8 +30,7 @@ public OperationFailedDialog(AbstractOperation operation)
var normalBrush = Application.Current?.FindResource("SystemControlForegroundBaseHighBrush") as IBrush
?? Brushes.White;

var inlines = OutputText.Inlines ??= new InlineCollection();
bool first = true;
var lines = new List<LogLineItem>();
foreach (var (text, type) in operation.GetOutput())
{
IBrush brush = type switch
Expand All @@ -40,10 +39,9 @@ public OperationFailedDialog(AbstractOperation operation)
AbstractOperation.LineType.VerboseDetails => debugBrush,
_ => normalBrush,
};
if (!first) inlines.Add(new LineBreak());
inlines.Add(new Run(text) { Foreground = brush });
first = false;
lines.Add(new LogLineItem(text, brush));
}
OutputText.SetLines(lines);

var closeButton = new Button
{
Expand All @@ -64,7 +62,7 @@ public OperationFailedDialog(AbstractOperation operation)
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
Dispatcher.UIThread.Post(OutputScroll.ScrollToEnd, DispatcherPriority.Background);
Dispatcher.UIThread.Post(OutputText.ScrollToBottom, DispatcherPriority.Background);
}

private Control BuildRetryButton(AbstractOperation operation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:automation="clr-namespace:Avalonia.Automation;assembly=Avalonia.Controls"
xmlns:vm="using:UniGetUI.Avalonia.ViewModels.DialogPages"
xmlns:controls="using:UniGetUI.Avalonia.Views.Controls"
x:Class="UniGetUI.Avalonia.Views.DialogPages.OperationOutputWindow"
x:DataType="vm:OperationOutputViewModel"
Width="700" MinWidth="400"
Expand All @@ -12,19 +13,13 @@
WindowStartupLocation="CenterOwner"
Title="{Binding Title}">

<ScrollViewer x:Name="OutputScroll"
Margin="8"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Background="{DynamicResource AppDialogDarkBackground}"
CornerRadius="6">
<SelectableTextBlock x:Name="OutputText"
Padding="8"
FontFamily="Cascadia Mono,Consolas,Menlo,monospace"
FontSize="12"
TextWrapping="Wrap"
automation:AutomationProperties.Name="{Binding Title}"
automation:AutomationProperties.AccessibilityView="Raw"/>
</ScrollViewer>
<Border Margin="8"
CornerRadius="6"
ClipToBounds="True"
Background="{DynamicResource AppDialogDarkBackground}">
<controls:LogTextEditor x:Name="OutputText"
automation:AutomationProperties.Name="{Binding Title}"
automation:AutomationProperties.AccessibilityView="Raw"/>
</Border>

</Window>
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Collections.Specialized;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Threading;
using UniGetUI.Avalonia.ViewModels.DialogPages;
using UniGetUI.Avalonia.ViewModels.Pages.LogPages;
Expand All @@ -17,9 +16,7 @@ public OperationOutputWindow(AbstractOperation operation)
InitializeComponent();
UniGetUI.Avalonia.Infrastructure.MicaWindowHelper.Apply(this);

foreach (var line in vm.OutputLines)
AppendLine(line);

OutputText.SetLines(vm.OutputLines);
vm.OutputLines.CollectionChanged += OnOutputLinesChanged;
}

Expand All @@ -29,28 +26,20 @@ private void OnOutputLinesChanged(object? sender, NotifyCollectionChangedEventAr
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
OutputText.Inlines?.Clear();
OutputText.ClearLines();
}
else if (e.NewItems is not null)
{
foreach (LogLineItem item in e.NewItems)
AppendLine(item);
OutputText.AppendLine(item);
}
OutputScroll.ScrollToEnd();
OutputText.ScrollToBottom();
}, DispatcherPriority.Background);
}

private void AppendLine(LogLineItem line)
{
var inlines = OutputText.Inlines ??= new InlineCollection();
if (inlines.Count > 0)
inlines.Add(new LineBreak());
inlines.Add(new Run(line.Text) { Foreground = line.Foreground });
}

protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
OutputScroll.ScrollToEnd();
OutputText.ScrollToBottom();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,11 @@
Spacing="8">
<Border CornerRadius="8" ClipToBounds="True"
x:Name="ScreenshotsBorder"
Background="#000000"
Height="320">
<Panel>
<!-- Black letterbox only behind actual screenshots; the empty-state
banner below composites over the themed window background instead. -->
<Border Background="#000000" IsVisible="{Binding HasScreenshots}"/>
<Carousel x:Name="ScreenshotsCarousel"
IsVisible="{Binding HasScreenshots}"
ItemsSource="{Binding Screenshots}"
Expand Down
2 changes: 1 addition & 1 deletion src/UniGetUI.Avalonia/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@
Grid.Column="0"
MinHeight="20"
FontSize="15"
CornerRadius="0"
CornerRadius="3,0,0,3"
BorderThickness="0"
VerticalContentAlignment="Center"
Padding="8,0,4,0"
Expand Down
Loading
Loading