Implement changes from Roland's branch
MODIFY
WalletWasabi.Fluent/ViewModels/CoinControl/Core/CoinCoinControlItemViewModel.cs
WalletWasabi.Fluent/ViewModels/CoinControl/Core/CoinCoinControlItemViewModel.cs
-using System.Linq;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Fluent.Helpers;
@@ -6,7 +5,7 @@ namespace WalletWasabi.Fluent.ViewModels.CoinControl.Core;
public class CoinCoinControlItemViewModel : CoinControlItemViewModelBase
{
- public CoinCoinControlItemViewModel(SmartCoin smartCoin) : base(Enumerable.Empty<IHierarchicallySelectable>())
+ public CoinCoinControlItemViewModel(SmartCoin smartCoin)
{
SmartCoin = smartCoin;
Amount = smartCoin.Amount;

MODIFY
WalletWasabi.Fluent/ViewModels/CoinControl/Core/CoinControlItemViewModelBase.cs
WalletWasabi.Fluent/ViewModels/CoinControl/Core/CoinControlItemViewModelBase.cs
using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Disposables;
using NBitcoin;
using ReactiveUI;
using WalletWasabi.Blockchain.Analysis.Clustering;
@@ -8,17 +6,13 @@ using WalletWasabi.Fluent.Helpers;
namespace WalletWasabi.Fluent.ViewModels.CoinControl.Core;
-public abstract class CoinControlItemViewModelBase : ViewModelBase, IHierarchicallySelectable, IDisposable
+public abstract class CoinControlItemViewModelBase : ViewModelBase
{
private bool? _isSelected;
- private readonly CompositeDisposable _disposables = new();
- public CoinControlItemViewModelBase(IEnumerable<IHierarchicallySelectable> children)
+ protected CoinControlItemViewModelBase()
{
- Selectables = children.ToList();
- Children = Selectables.Cast<CoinControlItemViewModelBase>().ToList();
- HierarchicalSelectionHandler = new HierarchicalSelectionHandler(this);
- HierarchicalSelectionHandler.DisposeWith(_disposables);
+ CanBeSelected = !IsCoinjoining;
}
public bool IsPrivate => Labels == CoinPocketHelper.PrivateFundsText;
@@ -27,7 +21,7 @@ public abstract class CoinControlItemViewModelBase : ViewModelBase, IHierarchica
public bool IsNonPrivate => !IsSemiPrivate && !IsPrivate;
- public IEnumerable<CoinControlItemViewModelBase> Children { get; }
+ public IReadOnlyCollection<CoinControlItemViewModelBase> Children { get; protected set; } = new List<CoinControlItemViewModelBase>();
public bool IsConfirmed { get; protected set; }
@@ -49,12 +43,8 @@ public abstract class CoinControlItemViewModelBase : ViewModelBase, IHierarchica
public bool IsExpanded { get; set; } = true;
- public HierarchicalSelectionHandler HierarchicalSelectionHandler { get; }
-
public bool CanBeSelected { get; protected set; }
- public IEnumerable<IHierarchicallySelectable> Selectables { get; }
-
public bool? IsSelected
{
get => _isSelected;
@@ -68,13 +58,4 @@ public abstract class CoinControlItemViewModelBase : ViewModelBase, IHierarchica
this.RaiseAndSetIfChanged(ref _isSelected, value);
}
}
-
- public void Dispose()
- {
- _disposables.Dispose();
- foreach (var child in Children)
- {
- child.Dispose();
- }
- }
}

DELETE
WalletWasabi.Fluent/ViewModels/CoinControl/Core/HierarchicalSelectionHandler.cs
-using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Disposables;
-using System.Reactive.Linq;
-using DynamicData;
-using ReactiveUI;
-
-namespace WalletWasabi.Fluent.ViewModels.CoinControl.Core;
-
-public class HierarchicalSelectionHandler : ReactiveObject, IDisposable
-{
- private readonly CompositeDisposable _disposables = new();
-
- private bool _canUpdate = true;
-
- public HierarchicalSelectionHandler(IHierarchicallySelectable model)
- {
- Model = model;
-
- model.Selectables
- .AsObservableChangeSet()
- .AutoRefresh(x => x.IsSelected)
- .Where(_ => _canUpdate)
- .ToCollection()
- .Select(GetSelectionState)
- .BindTo(model, x => x.IsSelected)
- .DisposeWith(_disposables);
-
- this.WhenAnyValue(x => x.Model.IsSelected)
- .WhereNotNull()
- .Do(isSelected => Toggle(isSelected!.Value))
- .Subscribe();
- }
-
- private void Toggle(bool isSelected)
- {
- _canUpdate = false;
-
- foreach (var item in Model.Selectables)
- {
- item.IsSelected = isSelected;
- }
-
- _canUpdate = true;
- }
-
- private IHierarchicallySelectable Model { get; }
-
- private static bool? GetSelectionState(IReadOnlyCollection<IHierarchicallySelectable> children)
- {
- var selectionCount = children.Count(x => x.IsSelected is true or null);
-
- bool? selectionState = selectionCount == 0
- ? false
- : children.Count == selectionCount
- ? true
- : null;
- return selectionState;
- }
-
- public void Dispose()
- {
- _disposables.Dispose();
- }
-}

DELETE
WalletWasabi.Fluent/ViewModels/CoinControl/Core/IHierarchicallySelectable.cs
-using System.Collections.Generic;
-using System.ComponentModel;
-
-namespace WalletWasabi.Fluent.ViewModels.CoinControl.Core;
-
-public interface IHierarchicallySelectable : INotifyPropertyChanged
-{
- IEnumerable<IHierarchicallySelectable> Selectables { get; }
- public bool? IsSelected { get; set; }
-}

MODIFY
WalletWasabi.Fluent/ViewModels/CoinControl/Core/PocketCoinControlItemViewModel.cs
WalletWasabi.Fluent/ViewModels/CoinControl/Core/PocketCoinControlItemViewModel.cs
-using System.Collections.Generic;
using System.Linq;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using DynamicData;
+using ReactiveUI;
using WalletWasabi.Fluent.Models;
namespace WalletWasabi.Fluent.ViewModels.CoinControl.Core;
-public class PocketCoinControlItemViewModel : CoinControlItemViewModelBase
+public class PocketCoinControlItemViewModel : CoinControlItemViewModelBase, IDisposable
{
- public PocketCoinControlItemViewModel(Pocket pocket) : base(GetChildren(pocket))
+ private readonly CompositeDisposable _disposables = new();
+
+ public PocketCoinControlItemViewModel(Pocket pocket)
{
var unconfirmedCount = pocket.Coins.Count(x => !x.Confirmed);
IsConfirmed = unconfirmedCount == 0;
@@ -17,13 +22,42 @@ public class PocketCoinControlItemViewModel : CoinControlItemViewModelBase
IsCoinjoining = pocket.Coins.Any(x => x.CoinJoinInProgress);
AnonymityScore = (int) pocket.Coins.Max(x => x.HdPubKey.AnonymitySet);
Labels = pocket.Labels;
+ Children = pocket.Coins.OrderByDescending(x => x.Amount).Select(coin => new CoinCoinControlItemViewModel(coin)).ToList();
CanBeSelected = true;
+
+ Children
+ .AsObservableChangeSet()
+ .WhenPropertyChanged(x => x.IsSelected)
+ .Select(
+ _ =>
+ {
+ var totalCount = Children.Count;
+ var selectedCount = Children.Count(x => x.IsSelected == true);
+ return (bool?) (selectedCount == totalCount ? true : selectedCount == 0 ? false : null);
+ })
+ .BindTo(this, x => x.IsSelected)
+ .DisposeWith(_disposables);
+
+ this.WhenAnyValue(x => x.IsSelected)
+ .Do(
+ isSelected =>
+ {
+ if (isSelected is null)
+ {
+ return;
+ }
+
+ foreach (var item in Children)
+ {
+ item.IsSelected = isSelected.Value;
+ }
+ })
+ .Subscribe()
+ .DisposeWith(_disposables);
}
- private static IEnumerable<CoinCoinControlItemViewModel> GetChildren(Pocket pocket)
+ public void Dispose()
{
- return pocket.Coins
- .OrderByDescending(x => x.Amount)
- .Select(coin => new CoinCoinControlItemViewModel(coin));
+ _disposables.Dispose();
}
}

MODIFY
WalletWasabi.Fluent/ViewModels/CoinControl/SelectCoinsDialogViewModel.cs
WalletWasabi.Fluent/ViewModels/CoinControl/SelectCoinsDialogViewModel.cs
@@ -197,7 +197,7 @@ public partial class SelectCoinsDialogViewModel : DialogViewModelBase<IEnumerabl
return 0;
}
- private static IReadOnlyCollection<CoinControlItemViewModelBase> CreateItems(IEnumerable<Pocket> pockets)
+ private static IReadOnlyCollection<PocketCoinControlItemViewModel> CreateItems(IEnumerable<Pocket> pockets)
{
return pockets
.Select(pocket => new PocketCoinControlItemViewModel(pocket))

Implement changes from Roland's branch