initial work to show pocket selection in the privacy shield.
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/ChangeAvoidanceSuggestionViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/ChangeAvoidanceSuggestionViewModel.cs
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using JetBrains.Annotations;
using NBitcoin;
using WalletWasabi.Blockchain.TransactionBuilding;
using WalletWasabi.Fluent.Helpers;

ADD
WalletWasabi.Fluent/ViewModels/Wallets/Send/PocketSuggestionViewModel.cs
+using System.Collections.Generic;
+using System.Linq;
+using WalletWasabi.Blockchain.Analysis.Clustering;
+
+namespace WalletWasabi.Fluent.ViewModels.Wallets.Send;
+
+public partial class PocketSuggestionViewModel : SuggestionViewModel
+{
+ [AutoNotify] private List<string> _labels;
+ [AutoNotify] private List<string> _filteredLabels;
+
+ public PocketSuggestionViewModel(SmartLabel currentLabels) : base(null)
+ {
+ Labels = currentLabels.Take(1).ToList();
+ FilteredLabels = currentLabels.Skip(1).ToList();
+ }
+}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionsFlyoutViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/PrivacySuggestionsFlyoutViewModel.cs
@@ -2,7 +2,9 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using ReactiveUI;
+using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Blockchain.TransactionBuilding;
+using WalletWasabi.Fluent.Helpers;
using WalletWasabi.Wallets;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send;
@@ -40,6 +42,11 @@ 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)))));
+ }
+
foreach (var suggestion in suggestions)
{
Suggestions.Add(suggestion);

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/SuggestionViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/SuggestionViewModel.cs
+using System.Windows.Input;
using WalletWasabi.Blockchain.TransactionBuilding;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Send;
public class SuggestionViewModel : ViewModelBase
{
- public SuggestionViewModel(BuildTransactionResult transactionResult, bool isOriginal = false)
+ public SuggestionViewModel(BuildTransactionResult? transactionResult, bool isOriginal = false)
{
IsOriginal = isOriginal;
TransactionResult = transactionResult;
@@ -12,5 +13,5 @@ public class SuggestionViewModel : ViewModelBase
public bool IsOriginal { get; protected set; }
- public BuildTransactionResult TransactionResult { get; protected set; }
+ public BuildTransactionResult? TransactionResult { get; protected set; }
}
\ No newline at end of file

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionInfo.cs
@@ -42,7 +42,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
public bool IsOptimized => ChangelessCoins.Any();
- public bool IsPrivatePocketUsed => Coins.All(x => x.HdPubKey.AnonymitySet >= _privateCoinThreshold);
+ public bool IsPrivate => Coins.All(x => x.HdPubKey.AnonymitySet >= _privateCoinThreshold);
public bool IsCustomFeeUsed { get; set; }

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionPreviewViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionPreviewViewModel.cs
@@ -61,15 +61,22 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
});
PrivacySuggestions.WhenAnyValue(x => x.SelectedSuggestion)
- .Subscribe(x =>
+ .Subscribe(async x =>
{
PrivacySuggestions.IsOpen = false;
PrivacySuggestions.SelectedSuggestion = null;
- if (x is { })
+ if (x is ChangeAvoidanceSuggestionViewModel changeAvoidance)
+ {
+ if (x.TransactionResult is { })
{
UpdateTransaction(CurrentTransactionSummary, x.TransactionResult);
}
+ }
+ else if (x is PocketSuggestionViewModel)
+ {
+ await OnChangePocketsAsync();
+ }
});
PrivacySuggestions.WhenAnyValue(x => x.IsOpen)
@@ -114,8 +121,6 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
await OnAdjustFeeAsync();
}
});
-
- ChangePocketsCommand = ReactiveCommand.CreateFromTask(OnChangePocketsAsync);
}
public TransactionSummaryViewModel CurrentTransactionSummary { get; }
@@ -130,8 +135,6 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
public ICommand AdjustFeeCommand { get; }
- public ICommand ChangePocketsCommand { get; }
-
private async Task ShowAdvancedDialogAsync()
{
var result = await NavigateDialogAsync(new AdvancedSendOptionsViewModel(_info), NavigationTarget.CompactDialogScreen);
@@ -312,7 +315,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
private async Task<BuildTransactionResult?> HandleInsufficientBalanceWhenNormalAsync(Wallet wallet, TransactionInfo transactionInfo)
{
- var dialog = new InsufficientBalanceDialogViewModel(transactionInfo.IsPrivatePocketUsed
+ var dialog = new InsufficientBalanceDialogViewModel(transactionInfo.IsPrivate
? BalanceType.Private
: BalanceType.Pocket);
@@ -349,7 +352,7 @@ namespace WalletWasabi.Fluent.ViewModels.Wallets.Send
if (wallet.Coins.TotalAmount() > transactionInfo.Amount)
{
await ShowErrorAsync("Transaction Building",
- $"There are not enough {(transactionInfo.IsPrivatePocketUsed ? "private funds" : "funds selected")} to cover the transaction fee",
+ $"There are not enough {(transactionInfo.IsPrivate ? "private funds" : "funds selected")} to cover the transaction fee",
"Wasabi was unable to create your transaction.");
var feeDialogResult = await NavigateDialogAsync(new SendFeeViewModel(wallet, transactionInfo, false),

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionSummaryViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Send/TransactionSummaryViewModel.cs
@@ -13,7 +13,6 @@ public partial class TransactionSummaryViewModel : ViewModelBase
private readonly Wallet _wallet;
private readonly TransactionInfo _info;
private BuildTransactionResult? _transaction;
- [AutoNotify] private SmartLabel _labels;
[AutoNotify] private string _amountText = "";
[AutoNotify] private bool _transactionHasChange;
[AutoNotify] private bool _transactionHasPockets;
@@ -29,8 +28,6 @@ public partial class TransactionSummaryViewModel : ViewModelBase
_info = info;
IsPreview = isPreview;
- _labels = SmartLabel.Empty;
-
this.WhenAnyValue(x => x.TransactionHasChange, x => x.TransactionHasPockets)
.Subscribe(_ => { MaxPrivacy = !TransactionHasPockets && !TransactionHasChange; });
@@ -66,15 +63,12 @@ public partial class TransactionSummaryViewModel : ViewModelBase
var fiatFeeText = fee.ToDecimal(MoneyUnit.BTC)
.GenerateFiatText(_wallet.Synchronizer.UsdExchangeRate, "USD");
- Labels = SmartLabel.Merge(_info.UserLabels,
- SmartLabel.Merge(transactionResult.SpentCoins.Select(x => CoinHelpers.GetLabels(x))));
-
FeeText = $"{btcFeeText}{fiatFeeText}";
TransactionHasChange =
_transaction.InnerWalletOutputs.Any(x => x.ScriptPubKey != _info.Address.ScriptPubKey);
- TransactionHasPockets = !_info.IsPrivatePocketUsed;
+ TransactionHasPockets = !_info.IsPrivate;
IsCustomFeeUsed = _info.IsCustomFeeUsed;
}

RENAME
WalletWasabi.Fluent/Views/Wallets/Send/PrivacySuggestionControl.axaml
WalletWasabi.Fluent/Views/Wallets/Send/ChangeAvoidanceSuggestionControl.axaml
x:DataType="vm:ChangeAvoidanceSuggestionViewModel"
x:CompileBindings="True"
ClipToBounds="False"
- x:Class="WalletWasabi.Fluent.Views.Wallets.Send.PrivacySuggestionControl">
+ x:Class="WalletWasabi.Fluent.Views.Wallets.Send.ChangeAvoidanceSuggestionControl">
<Panel>
<Border Name="PART_DecorationBorder" />
<Border Name="PART_MainContentBorder">

RENAME
WalletWasabi.Fluent/Views/Wallets/Send/PrivacySuggestionControl.axaml.cs
WalletWasabi.Fluent/Views/Wallets/Send/ChangeAvoidanceSuggestionControl.axaml.cs
@@ -3,9 +3,9 @@ using Avalonia.Markup.Xaml;
namespace WalletWasabi.Fluent.Views.Wallets.Send
{
- public class PrivacySuggestionControl : UserControl
+ public class ChangeAvoidanceSuggestionControl : UserControl
{
- public PrivacySuggestionControl()
+ public ChangeAvoidanceSuggestionControl()
{
InitializeComponent();
}

ADD
WalletWasabi.Fluent/Views/Wallets/Send/PocketSuggestionControl.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:c="clr-namespace:WalletWasabi.Fluent.Controls"
+ xmlns:send="clr-namespace:WalletWasabi.Fluent.ViewModels.Wallets.Send"
+ mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="450"
+ x:CompileBindings="True"
+ x:DataType="send:PocketSuggestionViewModel"
+ x:Class="WalletWasabi.Fluent.Views.Wallets.Send.PocketSuggestionControl">
+ <Panel>
+ <Border Name="PART_DecorationBorder" />
+ <Border Name="PART_MainContentBorder">
+ <StackPanel Spacing="20">
+ <PathIcon DockPanel.Dock="Top" Data="{StaticResource incognito_filled}" Height="25" Width="25"
+ Foreground="{DynamicResource TextForegroundColor}" />
+
+ <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="Various people or companies could become aware of this transaction including..." />
+
+ <DockPanel LastChildFill="False" HorizontalAlignment="Center">
+ <c:TagsBox Padding="0"
+ Margin="0"
+ MinWidth="0"
+ BorderThickness="0"
+ DockPanel.Dock="Left"
+ IsReadOnly="True"
+ Items="{Binding Labels}"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Center" />
+ <Button Classes="labelFlyout"
+ DockPanel.Dock="Left"
+ IsVisible="{Binding !!FilteredLabels.Count}"
+ Content="..."
+ Margin="0 4 0 0">
+ <Button.Flyout>
+ <Flyout Placement="BottomEdgeAlignedLeft" ShowMode="TransientWithDismissOnPointerMoveAway">
+ <c:TagsBox IsReadOnly="True"
+ Items="{Binding FilteredLabels}" />
+ </Flyout>
+ </Button.Flyout>
+ <ToolTip.Tip>
+ <Panel>
+ <c:TagsBox IsReadOnly="True"
+ Margin="4,6,0,0"
+ Items="{Binding FilteredLabels}" />
+ </Panel>
+ </ToolTip.Tip>
+ </Button>
+ </DockPanel>
+
+ <TextBlock Text="Customize this?." TextWrapping="Wrap" HorizontalAlignment="Center" />
+
+ </StackPanel>
+ </Border>
+ </Panel>
+</UserControl>

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

MODIFY
WalletWasabi.Fluent/Views/Wallets/Send/TransactionPreviewView.axaml
WalletWasabi.Fluent/Views/Wallets/Send/TransactionPreviewView.axaml
</Style>
<Style Selector="ListBoxItem Border#PART_MainContentBorder">
- <Setter Property="Padding" Value="30,45,30,40" />
+ <Setter Property="Padding" Value="15,25,15,25" />
<Setter Property="CornerRadius" Value="4" />
- <Setter Property="Margin" Value="5" />
+ <Setter Property="MaxWidth" Value="250" />
+ <Setter Property="MaxHeight" Value="300" />
</Style>
<Style Selector="ListBoxItem Border#PART_DecorationBorder">
- <Setter Property="Padding" Value="15 30 15 30" />
+ <Setter Property="Padding" Value="15 25 15 25" />
<Setter Property="CornerRadius" Value="4" />
- <Setter Property="Margin" Value="14" />
+ <Setter Property="Margin" Value="5" />
<Setter Property="BorderBrush" Value="#14FFFFFF" />
<Setter Property="BorderThickness" Value="1" />
</ListBox.ItemsPanel>
<ListBox.DataTemplates>
<DataTemplate DataType="vm:ChangeAvoidanceSuggestionViewModel">
- <send:PrivacySuggestionControl />
+ <send:ChangeAvoidanceSuggestionControl />
+ </DataTemplate>
+ <DataTemplate DataType="vm:PocketSuggestionViewModel">
+ <send:PocketSuggestionControl />
</DataTemplate>
</ListBox.DataTemplates>
</ListBox>

MODIFY
WalletWasabi.Fluent/Views/Wallets/Send/TransactionSummary.axaml
WalletWasabi.Fluent/Views/Wallets/Send/TransactionSummary.axaml
<Separator />
- <DockPanel IsVisible="{Binding TransactionHasPockets}">
- <Button Classes="plain"
- Command="{Binding Parent.ChangePocketsCommand}"
- ToolTip.Tip="Change who could know about this transaction"
- DockPanel.Dock="Right"
- Margin="10 0"
- IsVisible="{Binding !IsPreview}">
- <Viewbox Height="20">
- <PathIcon Data="{StaticResource entities_edit_regular}" Foreground="{DynamicResource SystemAccentColor}" />
- </Viewbox>
- </Button>
-
- <c:PreviewItem Icon="{StaticResource entities_regular}"
- Text="will be sent to and may be known by">
- <c:TagsBox Padding="0" IsReadOnly="True" Items="{Binding Labels}">
- <c:TagsBox.Styles>
- <Style Selector="c|TagsBox:readonly WrapPanel">
- <Setter Property="Margin" Value="0" />
- </Style>
- </c:TagsBox.Styles>
- </c:TagsBox>
- </c:PreviewItem>
- </DockPanel>
- <Separator IsVisible="{Binding TransactionHasPockets}"/>
-
<c:PreviewItem Icon="{StaticResource transceive_regular}"
Text="to the Bitcoin address">
<TextBlock Classes="monoSpaced" Text="{Binding AddressText, FallbackValue=btc029382398fkj34f98df239823}" />

initial work to show pocket selection in the privacy shield.