remove musthave logic, handle private funds silently
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/LabelSelectionViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/LabelSelectionViewModel.cs
@@ -4,14 +4,20 @@ using NBitcoin;
using ReactiveUI;
using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Blockchain.TransactionOutputs;
+using WalletWasabi.Fluent.Helpers;
using WalletWasabi.Fluent.Models;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send;
-public class LabelSelectionViewModel : ViewModelBase
+public partial class LabelSelectionViewModel : ViewModelBase
{
private readonly Money _targetAmount;
+ [AutoNotify] private bool _enoughSelected;
+
+ private Pocket? _privatePocket;
+ private bool _includePrivatePocket;
+
public LabelSelectionViewModel(Money targetAmount)
{
_targetAmount = targetAmount;
@@ -25,12 +31,35 @@ public class LabelSelectionViewModel : ViewModelBase
public IEnumerable<LabelViewModel> LabelsBlackList => AllLabelViewModel.Where(x => x.IsBlackListed);
- public Pocket[] GetUsedPockets() =>
- AllPocket.Where(x => x.Labels.All(label => LabelsWhiteList.Any(labelViewModel => labelViewModel.Value == label))).ToArray();
+ public Pocket[] GetAllPockets()
+ {
+ var pockets = AllPocket.ToList();
+
+ if (_privatePocket is { } privatePocket)
+ {
+ pockets.Add(privatePocket);
+ }
+
+ return pockets.ToArray();
+ }
+
+ public Pocket[] GetUsedPockets()
+ {
+ var pocketsToReturn = AllPocket.Where(x => x.Labels.All(label => LabelsWhiteList.Any(labelViewModel => labelViewModel.Value == label))).ToList();
+
+ if (_includePrivatePocket && _privatePocket is { } privatePocket)
+ {
+ pocketsToReturn.Add(privatePocket);
+ }
+
+ return pocketsToReturn.ToArray();
+ }
public void Reset(Pocket[] pockets)
{
- AllPocket = pockets;
+ _privatePocket = pockets.FirstOrDefault(x => x.Labels == CoinPocketHelper.PrivateFundsText);
+
+ AllPocket = pockets.Where(x => x != _privatePocket).ToArray();
var allLabels = SmartLabel.Merge(AllPocket.Select(x => x.Labels));
AllLabelViewModel = allLabels.Select(x => new LabelViewModel(this, x)).ToArray();
@@ -78,13 +107,27 @@ public class LabelSelectionViewModel : ViewModelBase
private void OnSelectionChanged()
{
- var sumOfWhiteList = AllPocket.Where(x => LabelsWhiteList.Any(y => x.Labels.Contains(y.Value))).Sum(x => x.Amount);
+ Money sumOfWhiteList = AllPocket.Where(x => LabelsWhiteList.Any(y => x.Labels.Contains(y.Value))).Sum(x => x.Amount);
- foreach (var labelViewModel in LabelsWhiteList)
+ if (sumOfWhiteList >= _targetAmount)
{
- var sumOfLabelsPockets = AllPocket.Where(x => x.Labels.Contains(labelViewModel.Value)).Sum(x => x.Amount);
-
- labelViewModel.MustHave = sumOfWhiteList - sumOfLabelsPockets < _targetAmount;
+ EnoughSelected = true;
+ _includePrivatePocket = false;
+ }
+ else if (!LabelsBlackList.Any() && _privatePocket is { } && sumOfWhiteList + _privatePocket.Amount >= _targetAmount)
+ {
+ EnoughSelected = true;
+ _includePrivatePocket = true;
+ }
+ else if (!LabelsWhiteList.Any() && _privatePocket is { } && _privatePocket.Amount >= _targetAmount)
+ {
+ EnoughSelected = true;
+ _includePrivatePocket = true;
+ }
+ else
+ {
+ EnoughSelected = false;
+ _includePrivatePocket = false;
}
this.RaisePropertyChanged(nameof(LabelsWhiteList));

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/LabelViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/LabelViewModel.cs
@@ -13,7 +13,6 @@ public partial class LabelViewModel : ViewModelBase
private bool _isHighlighted;
[AutoNotify] private bool _isPointerOver;
- [AutoNotify] private bool _mustHave;
public LabelViewModel(LabelSelectionViewModel owner, string label)
{
@@ -24,8 +23,7 @@ public partial class LabelViewModel : ViewModelBase
.Where(value => value == true)
.Subscribe(_ => owner.OnPointerOver(this));
- ClickedCommand = ReactiveCommand.Create(() => owner.SwapLabel(this),
- this.WhenAnyValue(x => x.MustHave, x => x.IsBlackListed).Select(x => x.Item2 || !x.Item1 && !x.Item2));
+ ClickedCommand = ReactiveCommand.Create(() => owner.SwapLabel(this));
}
public string Value { get; }

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacyControlViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacyControlViewModel.cs
@@ -31,7 +31,7 @@ public partial class PrivacyControlViewModel : DialogViewModelBase<IEnumerable<S
SetupCancel(enableCancel: false, enableCancelOnEscape: true, enableCancelOnPressed: false);
EnableBack = true;
- NextCommand = ReactiveCommand.Create(() => Complete(LabelSelection.GetUsedPockets()));
+ NextCommand = ReactiveCommand.Create(() => Complete(LabelSelection.GetUsedPockets()), LabelSelection.WhenAnyValue(x => x.EnoughSelected));
}
public LabelSelectionViewModel LabelSelection { get; }
@@ -66,7 +66,7 @@ public partial class PrivacyControlViewModel : DialogViewModelBase<IEnumerable<S
if (_isSilent)
{
- var usedPockets = LabelSelection.GetUsedPockets();
+ var usedPockets = LabelSelection.GetAllPockets();
if (usedPockets.FirstOrDefault(x => x.Labels == CoinPocketHelper.PrivateFundsText) is { } privatePocket &&
privatePocket.Amount >= _transactionInfo.Amount)

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionsFlyoutViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionsFlyoutViewModel.cs
@@ -41,10 +41,7 @@ public partial class PrivacySuggestionsFlyoutViewModel : ViewModelBase
Suggestions.Clear();
SelectedSuggestion = null;
- if (!info.IsPrivate)
- {
Suggestions.Add(new PocketSuggestionViewModel(SmartLabel.Merge(transaction.SpentCoins.Select(x => CoinHelpers.GetLabels(x)))));
- }
var suggestions =
await ChangeAvoidanceSuggestionViewModel.GenerateSuggestionsAsync(info, destination, wallet, transaction);

MODIFY
WalletWasabi.Tests/UnitTests/UserInterfaceTest/PocketSelectionTests.cs
WalletWasabi.Tests/UnitTests/UserInterfaceTest/PocketSelectionTests.cs
@@ -366,71 +366,6 @@ public class PocketSelectionTests
Assert.Contains(selection.GetLabel("Lucas"), selection.LabelsWhiteList);
Assert.Contains(selection.GetLabel("Jumar"), selection.LabelsWhiteList);
}
-
- [Fact]
- public void SingeLabelMarkedAndUnmarkedAsMustHave()
- {
- var selection = new LabelSelectionViewModel(Money.Parse("1.0"));
-
- var pockets = new List<Pocket>();
- pockets.AddPocket(2.0M, out var pocket1, "Roland");
- pockets.AddPocket(1.0M, out var pocket2, "Dan");
-
- selection.Reset(pockets.ToArray());
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.True(selection.GetLabel("Dan").MustHave);
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.False(selection.GetLabel("Dan").MustHave);
- }
-
- [Fact]
- public void MultipleLabelMarkedAndUnmarkedAsMustHave()
- {
- var selection = new LabelSelectionViewModel(Money.Parse("1.0"));
-
- var pockets = new List<Pocket>();
- pockets.AddPocket(2.0M, out var pocket1, "Roland");
- pockets.AddPocket(1.0M, out var pocket2, "Dan", "Jumar");
-
- selection.Reset(pockets.ToArray());
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.True(selection.GetLabel("Dan").MustHave);
- Assert.True(selection.GetLabel("Jumar").MustHave);
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.False(selection.GetLabel("Dan").MustHave);
- Assert.False(selection.GetLabel("Jumar").MustHave);
- }
-
- [Fact]
- public void MultiplePocketLabelMarkedAndUnmarkedAsMustHave()
- {
- var selection = new LabelSelectionViewModel(Money.Parse("1.0"));
-
- var pockets = new List<Pocket>();
- pockets.AddPocket(2.0M, out var pocket1, "Roland");
- pockets.AddPocket(0.5M, out var pocket2, "Dan");
- pockets.AddPocket(0.5M, out var pocket3, "Jumar");
-
- selection.Reset(pockets.ToArray());
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.True(selection.GetLabel("Dan").MustHave);
- Assert.True(selection.GetLabel("Jumar").MustHave);
-
- selection.SwapLabel(selection.GetLabel("Roland"));
-
- Assert.False(selection.GetLabel("Dan").MustHave);
- Assert.False(selection.GetLabel("Jumar").MustHave);
- }
}
internal static class LabelTestExtensions

remove musthave logic, handle private funds silently