Display the loading of the CoinList and History list.
MODIFY
WalletWasabi.Gui/App.xaml
WalletWasabi.Gui/App.xaml
<StyleInclude Source="resm:WalletWasabi.Gui.Icons.Icons.xaml?assembly=WalletWasabi.Gui" />
<StyleInclude Source="resm:WalletWasabi.Gui.Controls.NoparaPasswordBox.xaml?assembly=WalletWasabi.Gui" />
<StyleInclude Source="resm:WalletWasabi.Gui.Controls.MultiTextBox.xaml?assembly=WalletWasabi.Gui" />
+ <StyleInclude Source="resm:WalletWasabi.Gui.Controls.BusyIndicator.xaml?assembly=WalletWasabi.Gui" />
</Application.Styles>
<Application.DataTemplates>
<DataTemplate DataType="Views:MainView">

ADD
WalletWasabi.Gui/Behaviors/CommandOnFirstVisible.cs
+using Avalonia.Input;
+using System;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+
+namespace WalletWasabi.Gui.Behaviors
+{
+ internal class CommandOnFirstVisible : CommandBasedBehavior<InputElement>
+ {
+ private CompositeDisposable Disposables { get; set; }
+
+ protected override void OnAttached()
+ {
+ Disposables = new CompositeDisposable();
+
+ base.OnAttached();
+
+ Observable.FromEventPattern(AssociatedObject, nameof(AssociatedObject.AttachedToVisualTree))
+ .Take(1) // Only on first appearance.
+ .Subscribe(_ =>
+ {
+ ExecuteCommand();
+ }).DisposeWith(Disposables);
+ }
+
+ protected override void OnDetaching()
+ {
+ base.OnDetaching();
+
+ Disposables?.Dispose();
+ }
+ }
+}

ADD
WalletWasabi.Gui/Controls/BusyIndicator.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Styling;
+using System;
+
+namespace WalletWasabi.Gui.Controls
+{
+ public class BusyIndicator : ContentControl, IStyleable
+ {
+ Type IStyleable.StyleKey => typeof(BusyIndicator);
+
+ public static readonly StyledProperty<string> TextProperty =
+ AvaloniaProperty.Register<BusyIndicator, string>(nameof(Text));
+
+ public static readonly StyledProperty<bool> IsBusyProperty =
+ AvaloniaProperty.Register<BusyIndicator, bool>(nameof(IsBusy));
+
+ public string Text
+ {
+ get => GetValue(TextProperty);
+ set => SetValue(TextProperty, value);
+ }
+
+ public bool IsBusy
+ {
+ get => GetValue(IsBusyProperty);
+ set => SetValue(IsBusyProperty, value);
+ }
+ }
+}

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinJoinTabViewModel.cs
@@ -124,8 +124,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
public override void OnOpen()
{
- CoinsList.OnOpen();
-
if (Disposables != null)
{
throw new Exception("CoinJoin tab opened before previous closed.");

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinListView.xaml
WalletWasabi.Gui/Controls/WalletExplorer/CoinListView.xaml
</UserControl.Styles>
<i:Interaction.Behaviors>
<behaviors:ClearPropertyOnLostFocusBehavior TargetProperty="{Binding SelectedCoin}" />
+ <behaviors:CommandOnFirstVisible Command="{Binding InitList}" />
</i:Interaction.Behaviors>
<Grid IsSharedSizeScope="True">
<DockPanel LastChildFill="True">
<TextBlock Text = "BTC" />
</StackPanel>
</StackPanel>
+ <controls:BusyIndicator IsBusy ="{Binding IsCoinListLoading}" Text="Loading...">
<controls:ExtendedListBox Items="{Binding Coins}" VirtualizationMode="None" SelectedItem="{Binding Path=SelectedCoin, Mode=TwoWay}">
<controls:ExtendedListBox.ContextMenu>
<ContextMenu>
</DataTemplate>
</controls:ExtendedListBox.ItemTemplate>
</controls:ExtendedListBox>
+ </controls:BusyIndicator>
</DockPanel>
</Grid>
</UserControl>

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/CoinListViewModel.cs
@@ -11,6 +11,7 @@ using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
+using System.Threading.Tasks;
using WalletWasabi.Gui.Models;
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Models;
@@ -37,6 +38,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
private SortOrder _clustersSortDirection;
private decimal _totalAmount;
private bool _isAnyCoinSelected;
+ private bool _isCoinListLoading;
public Global Global { get; }
public ReactiveCommand<Unit, Unit> EnqueueCoin { get; }
@@ -45,6 +47,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
public ReactiveCommand<Unit, Unit> SelectPrivateCheckBoxCommand { get; }
public ReactiveCommand<Unit, Unit> SelectNonPrivateCheckBoxCommand { get; }
public ReactiveCommand<Unit, Unit> SortCommand { get; }
+ public ReactiveCommand<Unit, Unit> InitList { get; }
public event EventHandler DequeueCoinsPressed;
@@ -82,6 +85,12 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set => this.RaiseAndSetIfChanged(ref _selectPrivateCheckBoxState, value);
}
+ public bool IsCoinListLoading
+ {
+ get => _isCoinListLoading;
+ set => this.RaiseAndSetIfChanged(ref _isCoinListLoading, value);
+ }
+
public SortOrder StatusSortDirection
{
get => _statusSortDirection;
@@ -227,6 +236,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
Global = global;
AmountSortDirection = SortOrder.Decreasing;
+ IsCoinListLoading = true;
RefreshOrdering();
var sortChanged = this.WhenValueChanged(@this => MyComparer)
@@ -367,10 +377,32 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
break;
}
});
+
+ InitList = ReactiveCommand.CreateFromTask(async () =>
+ {
+ try
+ {
+ IsCoinListLoading = true;
+ // We have to wait for the UI to became visible to the user.
+ await Task.Delay(800); // Let other tasks run to display the gui.
+ OnOpen();
+ }
+ finally
+ {
+ IsCoinListLoading = false;
+ }
+ });
+
+ InitList.ThrownExceptions.Subscribe(ex => Logging.Logger.LogError<CoinListViewModel>(ex));
}
- public void OnOpen()
+ private void OnOpen()
{
+ if (Disposables != null)
+ {
+ throw new Exception("CoinList opened before previous closed.");
+ }
+
Disposables = new CompositeDisposable();
foreach (var sc in Global.WalletService.Coins.Where(sc => sc.Unspent))

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabView.xaml
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabView.xaml
<controls:SortingArrow Grid.Column="2" Command="{Binding SortCommand}" Text="Amount (BTC)" SortDirection="{Binding AmountSortDirection}" />
<controls:SortingArrow Grid.Column="3" Command="{Binding SortCommand}" Text="Transaction ID" SortDirection="{Binding TransactionSortDirection}" />
</Grid>
+ <controls:BusyIndicator Text="Loading..." IsBusy="{Binding IsFirstLoading}">
<controls:ExtendedListBox Items="{Binding Transactions}" SelectedItem="{Binding SelectedTransaction, Mode=TwoWay}">
<controls:ExtendedListBox.ItemTemplate>
<DataTemplate>
</DataTemplate>
</controls:ExtendedListBox.ItemTemplate>
</controls:ExtendedListBox>
+ </controls:BusyIndicator>
</DockPanel>
</DockPanel>
</Grid>

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/HistoryTabViewModel.cs
@@ -22,12 +22,21 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
private SortOrder _dateSortDirection;
private SortOrder _amountSortDirection;
private SortOrder _transactionSortDirection;
+ private bool _isFirstLoading;
+
+ public bool IsFirstLoading
+ {
+ get => _isFirstLoading;
+ set => this.RaiseAndSetIfChanged(ref _isFirstLoading, value);
+ }
public ReactiveCommand<Unit, Unit> SortCommand { get; }
public HistoryTabViewModel(WalletViewModel walletViewModel)
: base("History", walletViewModel)
{
+ IsFirstLoading = true;
+
Transactions = new ObservableCollection<TransactionViewModel>();
this.WhenAnyValue(x => x.SelectedTransaction).Subscribe(async transaction =>
@@ -53,7 +62,7 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
if (Disposables != null)
{
- throw new Exception("Histroy Tab was opened before it was closed.");
+ throw new Exception("History Tab was opened before it was closed.");
}
Disposables = new CompositeDisposable();
@@ -119,6 +128,10 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
{
Logger.LogError<HistoryTabViewModel>($"Error while RewriteTable on HistoryTab: {ex}.");
}
+ finally
+ {
+ IsFirstLoading = false;
+ }
}
private List<(DateTimeOffset dateTime, Height height, Money amount, string label, uint256 transactionId)> BuildTxRecordList()

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -1064,8 +1064,6 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
SetFeesAndTexts();
}).DisposeWith(Disposables);
- CoinList.OnOpen();
-
base.OnOpen();
}

Display the loading of the CoinList and History list.