share WalletManagerViewModel with the navbar and the homescreen.
MODIFY
WalletWasabi.Fluent/ViewModels/ClosedWalletViewModel.cs
WalletWasabi.Fluent/ViewModels/ClosedWalletViewModel.cs
@@ -19,7 +19,7 @@ namespace WalletWasabi.Fluent.ViewModels
{
_items = new ObservableCollection<NavBarItemViewModel>
{
- new HomePageViewModel(screen) { Parent = this }
+ new SettingsPageViewModel(screen) { Parent = this }
};
OpenWalletCommand = ReactiveCommand.CreateFromTask(

MODIFY
WalletWasabi.Fluent/ViewModels/Dialogs/IDialogHost.cs
WalletWasabi.Fluent/ViewModels/Dialogs/IDialogHost.cs
@@ -8,6 +8,6 @@ namespace WalletWasabi.Fluent.ViewModels.Dialogs
/// <summary>
/// The currently active dialog. The modal dialog UI should close when this is null.
/// </summary>
- DialogViewModelBase CurrentDialog { get; set; }
+ DialogViewModelBase? CurrentDialog { get; set; }
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/Dialogs/TestDialogViewModel.cs
WalletWasabi.Fluent/ViewModels/Dialogs/TestDialogViewModel.cs
@@ -28,7 +28,7 @@ namespace WalletWasabi.Fluent.ViewModels.Dialogs
protected override void OnDialogClosed()
{
- _screen.Router.NavigateAndReset.Execute(new HomePageViewModel(_screen));
+ _screen.Router.NavigateAndReset.Execute(new AddWalletPageViewModel(_screen));
}
public void Close()

MODIFY
WalletWasabi.Fluent/ViewModels/HomePageViewModel.cs
WalletWasabi.Fluent/ViewModels/HomePageViewModel.cs
using ReactiveUI;
+using System.Collections.ObjectModel;
+using System.Reactive.Linq;
+using DynamicData;
+using DynamicData.Binding;
namespace WalletWasabi.Fluent.ViewModels
{
public class HomePageViewModel : NavBarItemViewModel
{
- public HomePageViewModel(IScreen screen) : base(screen)
+ private readonly ReadOnlyObservableCollection<NavBarItemViewModel> _items;
+
+ public HomePageViewModel(IScreen screen, WalletManagerViewModel walletManager) : base(screen)
{
Title = "Home";
+
+ var list = new SourceList<NavBarItemViewModel>();
+ list.Add(new AddWalletPageViewModel(screen));
+
+ walletManager.Items.ToObservableChangeSet()
+ .Cast(x => x as NavBarItemViewModel)
+ .Sort(SortExpressionComparer<NavBarItemViewModel>.Ascending(i=>i.Title))
+ .Or(list.Connect())
+ .Sort(SortExpressionComparer<NavBarItemViewModel>.Ascending(i => i is AddWalletPageViewModel ? 1 : 0))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Bind(out _items)
+ .AsObservableList();
}
public override string IconName => "home_regular";
+
+ public ReadOnlyObservableCollection<NavBarItemViewModel> Items => _items;
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/MainViewModel.cs
WalletWasabi.Fluent/ViewModels/MainViewModel.cs
@@ -10,33 +10,34 @@ namespace WalletWasabi.Fluent.ViewModels
{
public class MainViewModel : ViewModelBase, IScreen, IDialogHost
{
- private Global _global;
+ private readonly Global _global;
private StatusBarViewModel _statusBar;
private string _title = "Wasabi Wallet";
- private DialogViewModelBase _currentDialog;
+ private DialogViewModelBase? _currentDialog;
private NavBarViewModel _navBar;
+
public MainViewModel(Global global)
{
_global = global;
-
Network = global.Network;
- StatusBar = new StatusBarViewModel(global.DataDir, global.Network, global.Config, global.HostedServices, global.BitcoinStore.SmartHeaderChain, global.Synchronizer, global.LegalDocuments);
+ _currentDialog = null;
- NavBar = new NavBarViewModel(this, Router, global.WalletManager, global.UiConfig);
+ _statusBar = new StatusBarViewModel(global.DataDir, global.Network, global.Config, global.HostedServices, global.BitcoinStore.SmartHeaderChain, global.Synchronizer, global.LegalDocuments);
+
+ var walletManager = new WalletManagerViewModel(this, global.WalletManager, global.UiConfig);
+ _navBar = new NavBarViewModel(this, Router, walletManager);
}
- public static MainViewModel Instance { get; internal set; }
+ public static MainViewModel? Instance { get; internal set; }
public RoutingState Router { get; } = new RoutingState();
- public ReactiveCommand<Unit, IRoutableViewModel> GoNext { get; }
-
public ReactiveCommand<Unit, Unit> GoBack => Router.NavigateBack;
- public Network Network { get; }
+ private Network Network { get; }
- public DialogViewModelBase CurrentDialog
+ public DialogViewModelBase? CurrentDialog
{
get => _currentDialog;
set => this.RaiseAndSetIfChanged(ref _currentDialog, value);
@@ -63,7 +64,7 @@ namespace WalletWasabi.Fluent.ViewModels
public void Initialize()
{
// Temporary to keep things running without VM modifications.
- MainWindowViewModel.Instance = new MainWindowViewModel(_global.Network, _global.UiConfig, _global.WalletManager, null, null, false);
+ MainWindowViewModel.Instance = new MainWindowViewModel(_global.Network, _global.UiConfig, _global.WalletManager, null!, null!, false);
StatusBar.Initialize(_global.Nodes.ConnectedNodes);

MODIFY
WalletWasabi.Fluent/ViewModels/NavBarViewModel.cs
WalletWasabi.Fluent/ViewModels/NavBarViewModel.cs
-using Avalonia.Threading;
using ReactiveUI;
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
-using WalletWasabi.Gui;
-using WalletWasabi.Wallets;
using WalletWasabi.Gui.ViewModels;
+using DynamicData;
+using DynamicData.Binding;
namespace WalletWasabi.Fluent.ViewModels
{
@@ -17,31 +15,25 @@ namespace WalletWasabi.Fluent.ViewModels
/// </summary>
public class NavBarViewModel : ViewModelBase
{
- private ObservableCollection<WalletViewModelBase> _items;
private ObservableCollection<NavBarItemViewModel> _topItems;
private ObservableCollection<NavBarItemViewModel> _bottomItems;
private NavBarItemViewModel _selectedItem;
- private Dictionary<Wallet, WalletViewModelBase> _walletDictionary;
- private bool _anyWalletStarted;
+ private readonly WalletManagerViewModel _walletManager;
private bool _isBackButtonVisible;
- private IScreen _screen;
private bool _isNavigating;
private bool _isOpen;
-
private Action _toggleAction;
private Action _collapseOnClickAction;
- public NavBarViewModel(IScreen screen, RoutingState router, WalletManager walletManager, UiConfig uiConfig)
+
+ public NavBarViewModel(IScreen screen, RoutingState router, WalletManagerViewModel walletManager)
{
- _screen = screen;
Router = router;
+ _walletManager = walletManager;
_topItems = new ObservableCollection<NavBarItemViewModel>();
- _items = new ObservableCollection<WalletViewModelBase>();
_bottomItems = new ObservableCollection<NavBarItemViewModel>();
- _walletDictionary = new Dictionary<Wallet, WalletViewModelBase>();
-
- SelectedItem = new HomePageViewModel(screen);
+ SelectedItem = new HomePageViewModel(screen, walletManager);
_topItems.Add(_selectedItem);
_bottomItems.Add(new AddWalletPageViewModel(screen));
_bottomItems.Add(new SettingsPageViewModel(screen));
@@ -50,7 +42,7 @@ namespace WalletWasabi.Fluent.ViewModels
.OfType<NavBarItemViewModel>()
.Subscribe(x =>
{
- if (_items.Contains(x) || _topItems.Contains(x) || _bottomItems.Contains(x))
+ if (walletManager.Items.Contains(x) || _topItems.Contains(x) || _bottomItems.Contains(x))
{
if (!_isNavigating)
{
@@ -79,69 +71,21 @@ namespace WalletWasabi.Fluent.ViewModels
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(_ => IsBackButtonVisible = Router.NavigationStack.Count > 1);
- Observable
- .FromEventPattern<WalletState>(walletManager, nameof(WalletManager.WalletStateChanged))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(x =>
- {
- var wallet = x.Sender as Wallet;
-
- if (wallet is { } && _walletDictionary.ContainsKey(wallet))
- {
- if (wallet.State == WalletState.Stopping)
- {
- RemoveWallet(_walletDictionary[wallet]);
- }
- else if (_walletDictionary[wallet] is ClosedWalletViewModel cwvm && wallet.State == WalletState.Started)
- {
- OpenClosedWallet(walletManager, uiConfig, cwvm);
- }
- }
-
- AnyWalletStarted = Items.OfType<WalletViewModelBase>().Any(x => x.WalletState == WalletState.Started);
- });
-
- Observable
- .FromEventPattern<Wallet>(walletManager, nameof(WalletManager.WalletAdded))
- .Select(x => x.EventArgs)
- .Where(x => x is { })
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(wallet =>
- {
- WalletViewModelBase vm = (wallet.State <= WalletState.Starting)
- ? ClosedWalletViewModel.Create(screen, walletManager, wallet)
- : WalletViewModel.Create(screen, uiConfig, wallet);
-
- InsertWallet(vm);
- });
-
this.WhenAnyValue(x => x.IsOpen)
.Subscribe(x => SelectedItem.IsExpanded = x);
-
- Dispatcher.UIThread.Post(() => LoadWallets(walletManager));
}
public ReactiveCommand<Unit, IRoutableViewModel> GoNext { get; }
public ReactiveCommand<Unit, Unit> GoBack => Router.NavigateBack;
- public bool AnyWalletStarted
- {
- get => _anyWalletStarted;
- set => this.RaiseAndSetIfChanged(ref _anyWalletStarted, value);
- }
-
public ObservableCollection<NavBarItemViewModel> TopItems
{
get => _topItems;
set => this.RaiseAndSetIfChanged(ref _topItems, value);
}
- public ObservableCollection<WalletViewModelBase> Items
- {
- get => _items;
- set => this.RaiseAndSetIfChanged(ref _items, value);
- }
+ public ObservableCollection<WalletViewModelBase> Items => _walletManager.Items;
public ObservableCollection<NavBarItemViewModel> BottomItems
{
@@ -221,62 +165,5 @@ namespace WalletWasabi.Fluent.ViewModels
{
ToggleAction?.Invoke();
}
-
- private void LoadWallets(WalletManager walletManager)
- {
- foreach (var wallet in walletManager.GetWallets())
- {
- InsertWallet(ClosedWalletViewModel.Create(_screen, walletManager, wallet));
- }
- }
-
- private void OpenClosedWallet(WalletManager walletManager, UiConfig uiConfig, ClosedWalletViewModel closedWalletViewModel)
- {
- var select = SelectedItem == closedWalletViewModel;
-
- RemoveWallet(closedWalletViewModel);
-
- var walletViewModel = OpenWallet(walletManager, uiConfig, closedWalletViewModel.Wallet);
-
- if (select)
- {
- SelectedItem = walletViewModel;
- }
- }
-
- private WalletViewModelBase OpenWallet(WalletManager walletManager, UiConfig uiConfig, Wallet wallet)
- {
- if (_items.OfType<WalletViewModel>().Any(x => x.Title == wallet.WalletName))
- {
- throw new Exception("Wallet already opened.");
- }
-
- var walletViewModel = WalletViewModel.Create(_screen, uiConfig, wallet);
-
- InsertWallet(walletViewModel);
-
- if (!walletManager.AnyWallet(x => x.State >= WalletState.Started && x != walletViewModel.Wallet))
- {
- walletViewModel.OpenWalletTabs();
- }
-
- walletViewModel.IsExpanded = true;
-
- return walletViewModel;
- }
-
- private void InsertWallet(WalletViewModelBase walletVM)
- {
- Items.InsertSorted(walletVM);
- _walletDictionary.Add(walletVM.Wallet, walletVM);
- }
-
- internal void RemoveWallet(WalletViewModelBase walletVM)
- {
- walletVM.Dispose();
-
- _items.Remove(walletVM);
- _walletDictionary.Remove(walletVM.Wallet);
- }
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/SettingsPageViewModel.cs
WalletWasabi.Fluent/ViewModels/SettingsPageViewModel.cs
@@ -19,7 +19,7 @@ namespace WalletWasabi.Fluent.ViewModels
{
Title = "Settings";
- NextCommand = ReactiveCommand.Create(() => screen.Router.Navigate.Execute(new HomePageViewModel(screen)));
+ NextCommand = ReactiveCommand.Create(() => screen.Router.Navigate.Execute(new AddWalletPageViewModel(screen)));
OpenDialogCommand = ReactiveCommand.CreateFromTask(async () => await ConfirmSetting.Handle("Please confirm the setting:").ToTask());

ADD
WalletWasabi.Fluent/ViewModels/WalletManagerViewModel.cs
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive.Linq;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+using DynamicData;
+using ReactiveUI;
+using WalletWasabi.Gui;
+using WalletWasabi.Gui.ViewModels;
+using WalletWasabi.Wallets;
+
+namespace WalletWasabi.Fluent.ViewModels
+{
+ public class WalletManagerViewModel : ViewModelBase
+ {
+ private WalletViewModelBase _selectedItem;
+ private ObservableCollection<WalletViewModelBase> _items;
+ private readonly Dictionary<Wallet, WalletViewModelBase> _walletDictionary;
+ private readonly IScreen _screen;
+ private bool _anyWalletStarted;
+
+ public WalletManagerViewModel(IScreen screen, WalletManager walletManager, UiConfig uiConfig)
+ {
+ _walletDictionary = new Dictionary<Wallet, WalletViewModelBase>();
+ _items = new ObservableCollection<WalletViewModelBase>();
+ _screen = screen;
+
+ Observable
+ .FromEventPattern<WalletState>(walletManager, nameof(WalletManager.WalletStateChanged))
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(x =>
+ {
+ var wallet = x.Sender as Wallet;
+
+ if (wallet is { } && _walletDictionary.ContainsKey(wallet))
+ {
+ if (wallet.State == WalletState.Stopping)
+ {
+ RemoveWallet(_walletDictionary[wallet]);
+ }
+ else if (_walletDictionary[wallet] is ClosedWalletViewModel cwvm && wallet.State == WalletState.Started)
+ {
+ OpenClosedWallet(walletManager, uiConfig, cwvm);
+ }
+ }
+
+ AnyWalletStarted = Items.OfType<WalletViewModelBase>().Any(x => x.WalletState == WalletState.Started);
+ });
+
+ Observable
+ .FromEventPattern<Wallet>(walletManager, nameof(WalletManager.WalletAdded))
+ .Select(x => x.EventArgs)
+ .Where(x => x is { })
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(wallet =>
+ {
+ WalletViewModelBase vm = (wallet.State <= WalletState.Starting)
+ ? ClosedWalletViewModel.Create(screen, walletManager, wallet)
+ : WalletViewModel.Create(screen, uiConfig, wallet);
+
+ InsertWallet(vm);
+ });
+
+ Dispatcher.UIThread.Post(() => LoadWallets(walletManager));
+ }
+
+ public WalletViewModelBase SelectedItem
+ {
+ get => _selectedItem;
+ set => this.RaiseAndSetIfChanged(ref _selectedItem, value);
+ }
+
+ public ObservableCollection<WalletViewModelBase> Items
+ {
+ get => _items;
+ set => this.RaiseAndSetIfChanged(ref _items, value);
+ }
+
+ public bool AnyWalletStarted
+ {
+ get => _anyWalletStarted;
+ set => this.RaiseAndSetIfChanged(ref _anyWalletStarted, value);
+ }
+
+ private void OpenClosedWallet(WalletManager walletManager, UiConfig uiConfig, ClosedWalletViewModel closedWalletViewModel)
+ {
+ var select = SelectedItem == closedWalletViewModel;
+
+ RemoveWallet(closedWalletViewModel);
+
+ var walletViewModel = OpenWallet(walletManager, uiConfig, closedWalletViewModel.Wallet);
+
+ if (select)
+ {
+ SelectedItem = walletViewModel;
+ }
+ }
+
+ private WalletViewModelBase OpenWallet(WalletManager walletManager, UiConfig uiConfig, Wallet wallet)
+ {
+ if (_items.OfType<WalletViewModel>().Any(x => x.Title == wallet.WalletName))
+ {
+ throw new Exception("Wallet already opened.");
+ }
+
+ var walletViewModel = WalletViewModel.Create(_screen, uiConfig, wallet);
+
+ InsertWallet(walletViewModel);
+
+ if (!walletManager.AnyWallet(x => x.State >= WalletState.Started && x != walletViewModel.Wallet))
+ {
+ walletViewModel.OpenWalletTabs();
+ }
+
+ walletViewModel.IsExpanded = true;
+
+ return walletViewModel;
+ }
+
+ private void InsertWallet(WalletViewModelBase walletVM)
+ {
+ Items.InsertSorted(walletVM);
+ _walletDictionary.Add(walletVM.Wallet, walletVM);
+ }
+
+ private void RemoveWallet(WalletViewModelBase walletVM)
+ {
+ walletVM.Dispose();
+
+ _items.Remove(walletVM);
+ _walletDictionary.Remove(walletVM.Wallet);
+ }
+
+ private async Task LoadWallets(WalletManager walletManager)
+ {
+ foreach (var wallet in walletManager.GetWallets())
+ {
+ InsertWallet(ClosedWalletViewModel.Create(_screen, walletManager, wallet));
+
+ await Task.Delay(2500);
+ }
+ }
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/Views/HomePageView.axaml
WalletWasabi.Fluent/Views/HomePageView.axaml
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="clr-namespace:WalletWasabi.Fluent.ViewModels"
xmlns:c="clr-namespace:WalletWasabi.Fluent.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:DataType="vm:HomePageViewModel"
x:Class="WalletWasabi.Fluent.Views.HomePageView">
<c:ContentArea Title="Home" Caption="Select a Wallet below to continue or create a new one:">
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
- <ItemsControl HorizontalAlignment="Center">
+ <ItemsControl HorizontalAlignment="Center" Items="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
CornerRadius="4" Margin="8"
Height="150" Width="150">
<Panel>
- <TextBlock Text="{Binding .}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0 0 0 15" />
+ <TextBlock Text="{Binding Title}" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0 0 0 15" />
<PathIcon Width="28" Height="28" Opacity="0.8" Foreground="#212121" Data="M22.1 3C24.2539 3 26 4.74609 26 6.9V20.7C26 22.8539 24.2539 24.6 22.1 24.6H5.9C3.74609 24.6 2 22.8539 2 20.7V6.9C2 4.74609 3.74609 3 5.9 3H22.1ZM22.1 4.8H5.9C4.7402 4.8 3.8 5.7402 3.8 6.9V20.7C3.8 21.8598 4.7402 22.8 5.9 22.8H22.1C23.2598 22.8 24.2 21.8598 24.2 20.7V6.9C24.2 5.7402 23.2598 4.8 22.1 4.8ZM7.69802 7.2H20.3052C20.8022 7.2 21.2052 7.60294 21.2052 8.1C21.2052 8.55563 20.8666 8.93219 20.4273 8.99178L20.3052 9H7.69802C7.20097 9 6.79803 8.59706 6.79803 8.1C6.79803 7.64437 7.13661 7.26781 7.5759 7.20822L7.69802 7.2H20.3052H7.69802Z" />
</Panel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
- 12345678
</ItemsControl>
</ScrollViewer>
</c:ContentArea>

share WalletManagerViewModel with the navbar and the homescreen.