Skip to content

Commit

Permalink
Merge pull request #7039 from wieslawsoltes/vdg/LabelsColumnImprovements
Browse files Browse the repository at this point in the history
[VDG] [Fluent] Improve Labels column in transaction history table
  • Loading branch information
Dan Walmsley committed Apr 6, 2022
2 parents 63c63e8 + 8131977 commit ad5c1ac
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 111 deletions.
2 changes: 2 additions & 0 deletions WalletWasabi.Fluent/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/TileControl.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/StatusItem.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/PrivacyContentControl.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/LabelsListBox.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/LabelControl.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/SuggestionItem.axaml" />
<StyleInclude Source="avares://WalletWasabi.Fluent/Controls/ClipboardCopyButton.axaml" />
</Application.Styles>
Expand Down
38 changes: 38 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelControl.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:WalletWasabi.Fluent.Controls">

<Design.PreviewWith>
<c:LabelControl DataContext="Label 1" />
</Design.PreviewWith>

<Style Selector="c|LabelControl">
<Setter Property="Margin" Value="0 0 4 0" />
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="PART_Border">
<TextBlock Text="{Binding}"
TextTrimming="CharacterEllipsis"
MaxWidth="120" />
</Border>
</ControlTemplate>
</Setter>
</Style>

<Style Selector="c|LabelControl /template/ Border#PART_Border">
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="12,5,12,5" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="MinWidth" Value="38" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="{DynamicResource TagsBoxBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource InvisibleButtonBackgroundColor}" />
<Setter Property="CornerRadius" Value="2" />
</Style>

</Styles>

7 changes: 7 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelControl.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Avalonia.Controls.Primitives;

namespace WalletWasabi.Fluent.Controls;

public class LabelControl : TemplatedControl
{
}
34 changes: 34 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelsItemsPresenter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Styling;
using ReactiveUI;

namespace WalletWasabi.Fluent.Controls;

public class LabelsItemsPresenter : ItemsPresenter, IStyleable
{
Type IStyleable.StyleKey => typeof(ItemsPresenter);

protected override void PanelCreated(IPanel panel)
{
base.PanelCreated(panel);

if (panel is LabelsPanel labelsPanel)
{
labelsPanel.WhenAnyValue(x => x.VisibleItemsCount)
.Subscribe(x =>
{
if (Items is List<string> items)
{
labelsPanel.FilteredItems = items.Skip(x).ToList();
}
else
{
labelsPanel.FilteredItems = new List<string>();
}
});
}
}
}
64 changes: 64 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelsListBox.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:g="clr-namespace:System.Collections.Generic;assembly=System.Collections"
xmlns:c="clr-namespace:WalletWasabi.Fluent.Controls">

<Design.PreviewWith>
<Border BorderBrush="Black" BorderThickness="1" Width="250" Height="50">
<c:LabelsListBox HorizontalAlignment="Left" VerticalAlignment="Center">
<c:LabelsListBox.Items>
<g:List x:TypeArguments="x:String">
<x:String>Label 1</x:String>
<x:String>Label 2</x:String>
<x:String>Label 3</x:String>
<x:String>Label 4</x:String>
</g:List>
</c:LabelsListBox.Items>
</c:LabelsListBox>
</Border>
</Design.PreviewWith>

<Style Selector="c|LabelsListBox">
<Setter Property="Template">
<ControlTemplate>
<ScrollViewer Name="PART_ScrollViewer"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Disabled"
AllowAutoHide="False">
<c:LabelsItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
Margin="0"
VirtualizationMode="Simple">
<ItemsPresenter.ItemsPanel>
<ItemsPanelTemplate>
<c:LabelsPanel Orientation="Horizontal" Spacing="2" HorizontalAlignment="Left">
<c:LabelsPanel.EllipsisControl>
<Button Classes="labelFlyout"
Content="..."
Margin="0 0 0 0">
<Button.Flyout>
<Flyout Placement="BottomEdgeAlignedLeft" ShowMode="TransientWithDismissOnPointerMoveAway">
<c:TagsBox IsReadOnly="True"
Items="{Binding $parent[c:LabelsPanel].FilteredItems}" />
</Flyout>
</Button.Flyout>
<ToolTip.Tip>
<Panel>
<c:TagsBox IsReadOnly="True"
Margin="4,6,0,0"
Items="{Binding $parent[c:LabelsPanel].FilteredItems}" />
</Panel>
</ToolTip.Tip>
</Button>
</c:LabelsPanel.EllipsisControl>
</c:LabelsPanel>
</ItemsPanelTemplate>
</ItemsPresenter.ItemsPanel>
</c:LabelsItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</Setter>
</Style>

</Styles>

18 changes: 18 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelsListBox.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Controls.Generators;
using Avalonia.Styling;

namespace WalletWasabi.Fluent.Controls;

public class LabelsListBox : ListBox, IStyleable
{
Type IStyleable.StyleKey => typeof(LabelsListBox);

protected override IItemContainerGenerator CreateItemContainerGenerator()
{
return new ItemContainerGenerator<LabelControl>(
this,
ContentControl.ContentProperty,
ContentControl.ContentTemplateProperty);
}
}
162 changes: 162 additions & 0 deletions WalletWasabi.Fluent/Controls/LabelsPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls;

namespace WalletWasabi.Fluent.Controls;

public class LabelsPanel : VirtualizingStackPanel
{
public static readonly StyledProperty<Control?> EllipsisControlProperty =
AvaloniaProperty.Register<LabelsPanel, Control?>(nameof(EllipsisControl));

public static readonly DirectProperty<LabelsPanel, int> VisibleItemsCountProperty =
AvaloniaProperty.RegisterDirect<LabelsPanel, int>(
nameof(VisibleItemsCount),
o => o.VisibleItemsCount);

private int _visibleItemsCount;

public Control? EllipsisControl
{
get => GetValue(EllipsisControlProperty);
set => SetValue(EllipsisControlProperty, value);
}

public int VisibleItemsCount
{
get => _visibleItemsCount;
private set => SetAndRaise(VisibleItemsCountProperty, ref _visibleItemsCount, value);
}

public List<string>? FilteredItems { get; set; }

protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
if (EllipsisControl is { } ellipsisControl)
{
((ISetLogicalParent)ellipsisControl).SetParent(this);
VisualChildren.Add(ellipsisControl);
LogicalChildren.Add(ellipsisControl);
}

base.OnAttachedToVisualTree(e);
}

protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
if (EllipsisControl is { } ellipsisControl)
{
((ISetLogicalParent)ellipsisControl).SetParent(null);
LogicalChildren.Remove(ellipsisControl);
VisualChildren.Remove(ellipsisControl);
}

base.OnDetachedFromVisualTree(e);
}

protected override Size MeasureOverride(Size availableSize)
{
var ellipsis = 0.0;
if (EllipsisControl is { })
{
EllipsisControl.Measure(availableSize);
ellipsis = EllipsisControl.DesiredSize.Width;
}

return base.MeasureOverride(availableSize.WithWidth(availableSize.Width + ellipsis));
}

protected override Size ArrangeOverride(Size finalSize)
{
var spacing = Spacing;
var ellipsisWidth = 0.0;
var width = 0.0;
var height = 0.0;
var finalWidth = finalSize.Width;
var showEllipsis = false;
var totalChildren = Children.Count;
var count = 0;

if (EllipsisControl is { })
{
ellipsisWidth = EllipsisControl.DesiredSize.Width;
}

for (var i = 0; i < totalChildren; i++)
{
var child = Children[i];
var childWidth = child.DesiredSize.Width;

if (width + childWidth > finalWidth)
{
while (true)
{
if (width + ellipsisWidth > finalWidth)
{
var previous = i - 1;
if (previous >= 0)
{
var previousChild = Children[previous];
count--;
width -= previousChild.DesiredSize.Width + spacing;
}
else
{
break;
}
}
else
{
break;
}
}

showEllipsis = true;
if (EllipsisControl is { })
{
width += EllipsisControl.DesiredSize.Width;
}

break;
}

width += child.DesiredSize.Width + spacing;
height = Math.Max(height, child.DesiredSize.Height);
count++;
}

var offset = 0.0;

for (var i = 0; i < totalChildren; i++)
{
var child = Children[i];
if (i < count)
{
var rect = new Rect(offset, 0.0, child.DesiredSize.Width, height);
child.Arrange(rect);
offset += child.DesiredSize.Width + spacing;
}
else
{
child.Arrange(new Rect(-10000, -10000, 0, 0));
}
}

if (EllipsisControl is { })
{
if (showEllipsis)
{
var rect = new Rect(offset, 0.0, EllipsisControl.DesiredSize.Width, height);
EllipsisControl.Arrange(rect);
}
else
{
EllipsisControl.Arrange(new Rect(-10000, -10000, 0, 0));
}
}

VisibleItemsCount = count;

return new Size(width, height);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ public class CoinJoinHistoryItemViewModel : HistoryItemViewModelBase
IObservable<Unit> updateTrigger)
: base(orderIndex, transactionSummary)
{
Label = transactionSummary.Label.Take(1).FirstOrDefault();
FilteredLabel = transactionSummary.Label.Skip(1).ToList();
Label = transactionSummary.Label.ToList();
IsConfirmed = transactionSummary.IsConfirmed();
Date = transactionSummary.DateTime.ToLocalTime();
Balance = balance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ public class CoinJoinsHistoryItemViewModel : HistoryItemViewModelBase
_updateTrigger = updateTrigger;

CoinJoinTransactions = new List<TransactionSummary>();
Label = "Coinjoins";
FilteredLabel = new List<string>();
Label = new [] {"Coinjoins"}.ToList();
IsCoinJoin = true;

ShowDetailsCommand = ReactiveCommand.Create(() => RoutableViewModel.Navigate(NavigationTarget.DialogScreen).To(new CoinJoinDetailsViewModel(this)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ protected HistoryItemViewModelBase(int orderIndex, TransactionSummary transactio

public uint256 Id { get; }

public List<string>? FilteredLabel { get; protected set; }

public string? Label { get; protected set; }
public List<string>? Label { get; protected set; }

public bool IsCoinJoin { get; protected set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public class TransactionHistoryItemViewModel : HistoryItemViewModelBase
IObservable<Unit> updateTrigger)
: base(orderIndex, transactionSummary)
{
Label = transactionSummary.Label.Take(1).FirstOrDefault();
FilteredLabel = transactionSummary.Label.Skip(1).ToList();
Label = transactionSummary.Label.ToList();
IsConfirmed = transactionSummary.IsConfirmed();
Date = transactionSummary.DateTime.ToLocalTime();
Balance = balance;
Expand Down

0 comments on commit ad5c1ac

Please sign in to comment.