add placeholder tiles for round status and btc price.
ADD
WalletWasabi.Fluent/ViewModels/Wallets/Home/Tiles/BtcPriceTileViewModel.cs
+using System;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using ReactiveUI;
+using WalletWasabi.Fluent.Helpers;
+using WalletWasabi.Wallets;
+
+namespace WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles
+{
+ public partial class BtcPriceTileViewModel : TileViewModel
+ {
+ [AutoNotify] private string _btcPrice;
+
+ private readonly Wallet _wallet;
+
+ public BtcPriceTileViewModel(Wallet wallet)
+ {
+ _wallet = wallet;
+
+ _wallet.Synchronizer.WhenAnyValue(x => x.UsdExchangeRate)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(usd => BtcPrice = usd.FormattedFiat());
+ //.DisposeWith(Disposables);
+ }
+ }
+}
\ No newline at end of file

ADD
WalletWasabi.Fluent/ViewModels/Wallets/Home/Tiles/RoundStatusTileViewModel.cs
+using System;
+using System.Reactive.Linq;
+using NBitcoin;
+using ReactiveUI;
+using WalletWasabi.CoinJoin.Client.Rounds;
+using WalletWasabi.CoinJoin.Common.Models;
+using WalletWasabi.Gui.Models;
+using WalletWasabi.Wallets;
+
+namespace WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles
+{
+ public partial class RoundStatusTileViewModel : TileViewModel
+ {
+ private readonly Wallet _wallet;
+ [AutoNotify] private long _roundId;
+ [AutoNotify] private RoundPhaseState _roundPhaseState;
+ [AutoNotify] private DateTimeOffset _roundTimesout;
+ [AutoNotify] private TimeSpan _timeLeftTillRoundTimeout;
+ private Money _requiredBTC;
+ private string _coordinatorFeePercent;
+ [AutoNotify] private int _peersRegistered;
+ [AutoNotify] private int _peersNeeded;
+
+ public RoundStatusTileViewModel(Wallet wallet)
+ {
+ _wallet = wallet;
+
+ Observable.FromEventPattern(_wallet.ChaumianClient, nameof(Wallet.ChaumianClient.CoinQueued))
+ .Merge(Observable.FromEventPattern(_wallet.ChaumianClient, nameof(Wallet.ChaumianClient.OnDequeue)))
+ .Merge(Observable.FromEventPattern(_wallet.ChaumianClient, nameof(Wallet.ChaumianClient.StateUpdated)))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(_ => UpdateStates());
+ //.DisposeWith(disposables);
+
+ ClientRound mostAdvancedRound = _wallet.ChaumianClient?.State?.GetMostAdvancedRoundOrDefault();
+
+ if (mostAdvancedRound is { })
+ {
+ RoundId = mostAdvancedRound.State.RoundId;
+ RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase,
+ _wallet.ChaumianClient?.State.IsInErrorState ?? false);
+ RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration
+ ? mostAdvancedRound.State.InputRegistrationTimesout
+ : DateTimeOffset.UtcNow;
+ PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount;
+ PeersNeeded = mostAdvancedRound.State.RequiredPeerCount;
+ }
+ else
+ {
+ RoundId = -1;
+ RoundPhaseState = new RoundPhaseState(RoundPhase.InputRegistration, false);
+ RoundTimesout = DateTimeOffset.UtcNow;
+ PeersRegistered = 0;
+ PeersNeeded = 100;
+ }
+
+ Observable.Interval(TimeSpan.FromSeconds(1))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(_ =>
+ {
+ TimeSpan left = RoundTimesout - DateTimeOffset.UtcNow;
+ TimeLeftTillRoundTimeout =
+ left > TimeSpan.Zero ? left : TimeSpan.Zero; // Make sure cannot be less than zero.
+ }); //.DisposeWith(disposables);
+ }
+
+ private void UpdateStates()
+ {
+ var chaumianClient = _wallet?.ChaumianClient;
+ if (chaumianClient is null)
+ {
+ return;
+ }
+
+ //AmountQueued = chaumianClient.State.SumAllQueuedCoinAmounts();
+
+ var registrableRound = chaumianClient.State.GetRegistrableRoundOrDefault();
+ if (registrableRound is { })
+ {
+ //CoordinatorFeePercent = registrableRound.State.CoordinatorFeePercent.ToString();
+ //UpdateRequiredBtcLabel(registrableRound);
+ }
+
+ var mostAdvancedRound = chaumianClient.State.GetMostAdvancedRoundOrDefault();
+ if (mostAdvancedRound is { })
+ {
+ RoundId = mostAdvancedRound.State.RoundId;
+ if (!chaumianClient.State.IsInErrorState)
+ {
+ RoundPhaseState = new RoundPhaseState(mostAdvancedRound.State.Phase, false);
+ RoundTimesout = mostAdvancedRound.State.Phase == RoundPhase.InputRegistration
+ ? mostAdvancedRound.State.InputRegistrationTimesout
+ : DateTimeOffset.UtcNow;
+ }
+ else
+ {
+ RoundPhaseState = new RoundPhaseState(RoundPhaseState.Phase, true);
+ }
+
+ this.RaisePropertyChanged(nameof(RoundPhaseState));
+ this.RaisePropertyChanged(nameof(RoundTimesout));
+ PeersRegistered = mostAdvancedRound.State.RegisteredPeerCount;
+ PeersNeeded = mostAdvancedRound.State.RequiredPeerCount;
+ }
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/WalletViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/WalletViewModel.cs
@@ -32,6 +32,8 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets
BalanceTile = new WalletBalanceTileViewModel(wallet, balanceChanged);
BalanceChartTile = new WalletBalanceChartTileViewModel(History.UnfilteredTransactions);
WalletPieChart = new WalletPieChartTileViewModel(wallet, balanceChanged);
+ RoundStatusTile = new RoundStatusTileViewModel(wallet);
+ BtcPriceTile= new BtcPriceTileViewModel(wallet);
}
private CompositeDisposable Disposables { get; set; }
@@ -46,6 +48,10 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets
public WalletPieChartTileViewModel WalletPieChart { get; }
+ public RoundStatusTileViewModel RoundStatusTile { get; }
+
+ public BtcPriceTileViewModel BtcPriceTile { get; }
+
public static WalletViewModel Create(UiConfig uiConfig, Wallet wallet)
{
return wallet.KeyManager.IsHardwareWallet

ADD
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/BtcPriceTileView.axaml
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:vm="using:WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:CompileBindings="True" x:DataType="vm:BtcPriceTileViewModel"
+ x:Class="WalletWasabi.Fluent.Views.Wallets.Home.Tiles.BtcPriceTileView">
+ <Border ClipToBounds="False" CornerRadius="5" Background="{DynamicResource TileRegionColor}" Margin="6" Padding="16" BoxShadow="{DynamicResource InfoBoxShadow}">
+ <DockPanel>
+ <TextBlock Text="BTC Price" DockPanel.Dock="Top" />
+ <TextBlock Text="{Binding BtcPrice}" />
+ </DockPanel>
+ </Border>
+</UserControl>

ADD
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/BtcPriceTileView.axaml.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WalletWasabi.Fluent.Views.Wallets.Home.Tiles
+{
+ public class BtcPriceTileView : UserControl
+ {
+ public BtcPriceTileView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
\ No newline at end of file

ADD
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/RoundStatusTileView.axaml
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:vm="using:WalletWasabi.Fluent.ViewModels.Wallets.Home.Tiles"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:CompileBindings="True" x:DataType="vm:RoundStatusTileViewModel"
+ x:Class="WalletWasabi.Fluent.Views.Wallets.Home.Tiles.RoundStatusTileView">
+ <Border ClipToBounds="False" CornerRadius="5" Background="{DynamicResource TileRegionColor}" Margin="6" Padding="16" BoxShadow="{DynamicResource InfoBoxShadow}">
+ <StackPanel>
+ <StackPanel Orientation="Horizontal">
+ <TextBlock Text="{Binding PeersRegistered}" />
+ <TextBlock Text="/" />
+ <TextBlock Text="{Binding PeersNeeded}" />
+ </StackPanel>
+ <TextBlock Text="Peers Registered" />
+
+ <TextBlock Text="{Binding TimeLeftTillRoundTimeout}" />
+
+ <TextBlock Text="{Binding RoundPhaseState}" />
+ </StackPanel>
+ </Border>
+</UserControl>

ADD
WalletWasabi.Fluent/Views/Wallets/Home/Tiles/RoundStatusTileView.axaml.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WalletWasabi.Fluent.Views.Wallets.Home.Tiles
+{
+ public class RoundStatusTileView : UserControl
+ {
+ public RoundStatusTileView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Views/Wallets/WalletView.axaml
WalletWasabi.Fluent/Views/Wallets/WalletView.axaml
UseLayoutRounding="False">
<tiles:WalletBalanceTileView DataContext="{Binding BalanceTile}"
c:ResponsivePanel.ColumnSpan="1, 1, 1" c:ResponsivePanel.RowSpan="1, 1, 1" />
- <Border CornerRadius="4" Margin="4" Background="{DynamicResource TileRegionColor}" BoxShadow="{DynamicResource InfoBoxShadow}"
+
+ <tiles:RoundStatusTileView DataContext="{Binding RoundStatusTile}"
c:ResponsivePanel.ColumnSpan="1, 1, 1" c:ResponsivePanel.RowSpan="1, 1, 1" />
- <Border CornerRadius="4" Margin="4" Background="{DynamicResource TileRegionColor}" BoxShadow="{DynamicResource InfoBoxShadow}"
+
+ <tiles:BtcPriceTileView DataContext="{Binding BtcPriceTile}"
c:ResponsivePanel.ColumnSpan="1, 1, 1" c:ResponsivePanel.RowSpan="1, 1, 1" />
<tiles:WalletPieChartTileView DataContext="{Binding WalletPieChart}" c:ResponsivePanel.ColumnSpan="1, 1, 1" c:ResponsivePanel.RowSpan="1, 1, 2" />

add placeholder tiles for round status and btc price.