initial implementation of send direct coins
MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Advanced/WalletCoins/WalletCoinViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Advanced/WalletCoins/WalletCoinViewModel.cs
@@ -15,17 +15,21 @@ public partial class WalletCoinViewModel : ViewModelBase, IDisposable
[AutoNotify] private SmartLabel _smartLabel = "";
[AutoNotify] private bool _confirmed;
[AutoNotify] private bool _coinJoinInProgress;
+ [AutoNotify] private bool _isSelected;
public WalletCoinViewModel(SmartCoin coin)
{
- Amount = coin.Amount;
+ Coin = coin;
+ Amount = Coin.Amount;
- coin.WhenAnyValue(c => c.Confirmed).Subscribe(x => Confirmed = x).DisposeWith(_disposables);
- coin.WhenAnyValue(c => c.HdPubKey.Cluster.Labels).Subscribe(x => SmartLabel = x).DisposeWith(_disposables);
- coin.WhenAnyValue(c => c.HdPubKey.AnonymitySet).Subscribe(x => AnonymitySet = x).DisposeWith(_disposables);
- coin.WhenAnyValue(c => c.CoinJoinInProgress).Subscribe(x => CoinJoinInProgress = x).DisposeWith(_disposables);
+ Coin.WhenAnyValue(c => c.Confirmed).Subscribe(x => Confirmed = x).DisposeWith(_disposables);
+ Coin.WhenAnyValue(c => c.HdPubKey.Cluster.Labels).Subscribe(x => SmartLabel = x).DisposeWith(_disposables);
+ Coin.WhenAnyValue(c => c.HdPubKey.AnonymitySet).Subscribe(x => AnonymitySet = x).DisposeWith(_disposables);
+ Coin.WhenAnyValue(c => c.CoinJoinInProgress).Subscribe(x => CoinJoinInProgress = x).DisposeWith(_disposables);
}
+ public SmartCoin Coin { get; }
+
public static Comparison<WalletCoinViewModel?> SortAscending<T>(Func<WalletCoinViewModel, T> selector)
{
return (x, y) =>

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Advanced/WalletCoins/WalletCoinsViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Advanced/WalletCoins/WalletCoinsViewModel.cs
-using System.Collections.Generic;
+using System.Collections.Immutable;
using DynamicData;
using ReactiveUI;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
+using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Controls.Templates;
using DynamicData.Binding;
+using NBitcoin;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Fluent.Extensions;
+using WalletWasabi.Fluent.ViewModels.Dialogs;
using WalletWasabi.Fluent.ViewModels.Navigation;
+using WalletWasabi.Fluent.ViewModels.Wallets.Send;
using WalletWasabi.Fluent.Views.Wallets.Advanced.WalletCoins.Columns;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Advanced.WalletCoins;
@@ -24,6 +28,7 @@ public partial class WalletCoinsViewModel : RoutableViewModel
private readonly ObservableCollectionExtended<WalletCoinViewModel> _coins;
private readonly SourceList<WalletCoinViewModel> _coinsSourceList = new();
[AutoNotify] private FlatTreeDataGridSource<WalletCoinViewModel>? _source;
+ [AutoNotify] private bool _anySelected;
public WalletCoinsViewModel(WalletViewModel walletViewModel, IObservable<Unit> balanceChanged)
{
@@ -32,6 +37,32 @@ public partial class WalletCoinsViewModel : RoutableViewModel
_walletViewModel = walletViewModel;
_balanceChanged = balanceChanged;
_coins = new ObservableCollectionExtended<WalletCoinViewModel>();
+
+ SkipCommand = ReactiveCommand.CreateFromTask(OnSendCoins);
+ }
+
+ private async Task OnSendCoins()
+ {
+ var wallet = _walletViewModel.Wallet;
+ var selectedSmartCoins = _coins.Where(x => x.IsSelected).Select(x => x.Coin).ToImmutableArray();
+ var info = new TransactionInfo(wallet.KeyManager.AnonScoreTarget);
+
+ // TODO: Ask for address
+ var address = BitcoinAddress.Create("tb1qmmsk4y4guxl0q2f5e7t485ssq4f7ju899tk6pj", wallet.Network);
+
+ var labelDialog = new LabelEntryDialogViewModel(wallet, info);
+ var result = await NavigateDialogAsync(labelDialog, NavigationTarget.CompactDialogScreen);
+ if (result.Result is not { } label)
+ {
+ return;
+ }
+
+ info.Coins = selectedSmartCoins;
+ info.Amount = selectedSmartCoins.Sum(x => x.Amount);
+ info.SubtractFee = true;
+ info.UserLabels = label;
+
+ Navigate().To(new TransactionPreviewViewModel(wallet, info, address, isFixedAmount: true));
}
private IObservable<Unit> CoinsUpdated => _balanceChanged
@@ -52,6 +83,14 @@ public partial class WalletCoinsViewModel : RoutableViewModel
.Subscribe()
.DisposeWith(disposables);
+ _coinsSourceList
+ .Connect()
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .WhenValueChanged(x => x.IsSelected)
+ .Select(_ => _coinsSourceList.Items.Any(x => x.IsSelected))
+ .Subscribe(anySelected => AnySelected = anySelected)
+ .DisposeWith(disposables);
+
// [Column] [View] [Header] [Width] [MinWidth] [MaxWidth] [CanUserSort]
// Indicators IndicatorsColumnView - Auto - - false
// Amount AmountColumnView Amount Auto - - true
@@ -62,6 +101,17 @@ public partial class WalletCoinsViewModel : RoutableViewModel
{
Columns =
{
+ // Indicators
+ new TemplateColumn<WalletCoinViewModel>(
+ null,
+ new FuncDataTemplate<WalletCoinViewModel>((node, ns) => new SelectionColumnView(), true),
+ options: new ColumnOptions<WalletCoinViewModel>
+ {
+ CanUserResizeColumn = false,
+ CanUserSortColumn = false
+ },
+ width: new GridLength(0, GridUnitType.Auto)),
+
// Indicators
new TemplateColumn<WalletCoinViewModel>(
null,

ADD
WalletWasabi.Fluent/Views/Wallets/Advanced/WalletCoins/Columns/SelectionColumnView.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:walletcoins="clr-namespace:WalletWasabi.Fluent.ViewModels.Wallets.Advanced.WalletCoins"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:DataType="walletcoins:WalletCoinViewModel"
+ x:CompileBindings="True"
+ x:Class="WalletWasabi.Fluent.Views.Wallets.Advanced.WalletCoins.Columns.SelectionColumnView">
+ <CheckBox IsChecked="{Binding IsSelected}" Margin="2 0" HorizontalAlignment="Center" VerticalAlignment="Center" />
+</UserControl>

ADD
WalletWasabi.Fluent/Views/Wallets/Advanced/WalletCoins/Columns/SelectionColumnView.axaml.cs
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WalletWasabi.Fluent.Views.Wallets.Advanced.WalletCoins.Columns;
+
+public class SelectionColumnView : UserControl
+{
+ public SelectionColumnView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}

MODIFY
WalletWasabi.Fluent/Views/Wallets/Advanced/WalletCoins/WalletCoinsView.axaml
WalletWasabi.Fluent/Views/Wallets/Advanced/WalletCoins/WalletCoinsView.axaml
EnableCancel="{Binding EnableCancel}"
EnableBack="{Binding EnableBack}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
- ScrollViewer.HorizontalScrollBarVisibility="Disabled">
+ ScrollViewer.HorizontalScrollBarVisibility="Disabled"
+ SkipContent="Send coins"
+ EnableSkip="{Binding AnySelected}">
<TreeDataGrid Source="{Binding Source}"
CanUserSortColumns="True">
<TreeDataGrid.Styles>

initial implementation of send direct coins