Add label suggestions to send tab too
MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabView.xaml
WalletWasabi.Gui/Controls/WalletExplorer/SendTabView.xaml
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
+ xmlns:iac="clr-namespace:Avalonia.Xaml.Interactions.Custom;assembly=Avalonia.Xaml.Interactions.Custom"
xmlns:converters="clr-namespace:WalletWasabi.Gui.Converters;assembly=WalletWasabi.Gui"
xmlns:behaviors="clr-namespace:WalletWasabi.Gui.Behaviors;assembly=WalletWasabi.Gui"
xmlns:local="clr-namespace:WalletWasabi.Gui.Controls.WalletExplorer;assembly=WalletWasabi.Gui">
<StackPanel DockPanel.Dock="Bottom" Margin="0 10" Spacing="10" HorizontalAlignment="Left">
<TextBlock>Note that, you must select coins you want to spend from.</TextBlock>
<controls:ExtendedTextBox Text="{Binding Address}" Watermark="Address" UseFloatingWatermark="True" />
- <controls:ExtendedTextBox Text="{Binding Label}" Watermark="Label" UseFloatingWatermark="True" IsReadOnly="{Binding IsMax}" ToolTip.Tip="{Binding LabelToolTip}" />
+ <StackPanel Spacing="8">
+ <controls:ExtendedTextBox Text="{Binding Label}" Watermark="Label" UseFloatingWatermark="True" IsReadOnly="{Binding IsMax}" ToolTip.Tip="{Binding LabelToolTip}" CaretIndex="{Binding CaretIndex, Mode=TwoWay}">
+ <i:Interaction.Behaviors>
+ <behaviors:SuggestionBehavior SuggestionItems="{Binding Suggestions}" />
+ <behaviors:CommandOnEnterBehavior Command="{Binding GenerateCommand}" />
+ <behaviors:FocusBehavior IsFocused="{Binding IsSelected}" />
+ <iac:FocusOnAttachedToVisualTreeBehavior />
+ </i:Interaction.Behaviors>
+ </controls:ExtendedTextBox>
+ <ItemsControl Items="{Binding Suggestions}">
+ <ItemsControl.ItemsPanel>
+ <ItemsPanelTemplate>
+ <StackPanel Orientation ="Horizontal" Spacing="2" />
+ </ItemsPanelTemplate>
+ </ItemsControl.ItemsPanel>
+ <ItemsControl.ItemTemplate>
+ <DataTemplate>
+ <Button Focusable="False" Content="{Binding Word}" Command="{Binding OnSelected}" IsPressed ="{Binding IsHighLighted}" />
+ </DataTemplate>
+ </ItemsControl.ItemTemplate>
+ </ItemsControl>
+ </StackPanel>
<StackPanel Orientation="Horizontal" Spacing="10">
<Button Content="{Binding MaxClear}" Command="{Binding MaxCommand}" VerticalAlignment="Top" />
<controls:ExtendedTextBox Foreground="{Binding IsMax, Converter={StaticResource AmountForegroundConverter}}" IsReadOnly="{Binding IsMax}" Text="{Binding Amount}" Watermark="Amount (BTC)" UseFloatingWatermark="True" MinWidth="124" MinHeight="46" />

MODIFY
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
WalletWasabi.Gui/Controls/WalletExplorer/SendTabViewModel.cs
@@ -14,6 +14,8 @@ using WalletWasabi.Gui.ViewModels.Validation;
using WalletWasabi.Helpers;
using ReactiveUI.Legacy;
using WalletWasabi.Exceptions;
+using System.Collections.ObjectModel;
+using WalletWasabi.Gui.Tabs.WalletManager;
namespace WalletWasabi.Gui.Controls.WalletExplorer
{
@@ -35,10 +37,14 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
private string _successMessage;
private const string BuildTransactionButtonTextString = "Send Transaction";
private const string BuildingTransactionButtonTextString = "Sending Transaction...";
+ private int _caretIndex;
+ private ObservableCollection<SuggestionViewModel> _suggestions;
public SendTabViewModel(WalletViewModel walletViewModel)
: base("Send", walletViewModel)
{
+ Label = "";
+
var onCoinsSetModified = Observable.FromEventPattern(Global.WalletService.Coins, nameof(Global.WalletService.Coins.HashSetChanged))
.ObserveOn(RxApp.MainThreadScheduler);
@@ -189,6 +195,17 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
}
}
});
+
+ this.WhenAnyValue(x => x.Label).Subscribe(x => UpdateSuggestions(x));
+ this.WhenAnyValue(x => x.CaretIndex).Subscribe(_ =>
+ {
+ if (Label == null) return;
+ if (CaretIndex != Label.Length)
+ {
+ CaretIndex = Label.Length;
+ }
+ });
+ _suggestions = new ObservableCollection<SuggestionViewModel>();
}
private void SetWarningMessage(string message)
@@ -299,6 +316,66 @@ namespace WalletWasabi.Gui.Controls.WalletExplorer
set { this.RaiseAndSetIfChanged(ref _password, value); }
}
+ public int CaretIndex
+ {
+ get { return _caretIndex; }
+ set { this.RaiseAndSetIfChanged(ref _caretIndex, value); }
+ }
+
+ public ObservableCollection<SuggestionViewModel> Suggestions
+ {
+ get { return _suggestions; }
+ set { this.RaiseAndSetIfChanged(ref _suggestions, value); }
+ }
+
+ private void UpdateSuggestions(string words)
+ {
+ if (string.IsNullOrWhiteSpace(words))
+ {
+ Suggestions?.Clear();
+ return;
+ }
+
+ var enteredWordList = words.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
+ var lastWorld = enteredWordList.LastOrDefault().Replace("\t", "");
+
+ if (lastWorld.Length < 1)
+ {
+ Suggestions.Clear();
+ return;
+ }
+
+ string[] nonSpecialLabels = Global.WalletService.GetNonSpecialLabels().ToArray();
+ IEnumerable<string> suggestedWords = nonSpecialLabels.Where(w => w.StartsWith(lastWorld, StringComparison.InvariantCultureIgnoreCase))
+ .Union(nonSpecialLabels.Where(w => w.Contains(lastWorld, StringComparison.InvariantCultureIgnoreCase)))
+ .Except(enteredWordList)
+ .Take(3);
+
+ Suggestions.Clear();
+ foreach (var suggestion in suggestedWords)
+ {
+ Suggestions.Add(new SuggestionViewModel(suggestion, OnAddWord));
+ }
+ }
+
+ public void OnAddWord(string word)
+ {
+ var words = Label.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();
+ if (words.Length == 0)
+ {
+ Label = word + ", ";
+ }
+ else
+ {
+ words[words.Length - 1] = word;
+ Label = string.Join(", ", words) + ", ";
+ }
+
+ CaretIndex = Label.Length;
+
+ Suggestions.Clear();
+ }
+
public string ValidateAddress()
{
if (string.IsNullOrEmpty(Address))

Add label suggestions to send tab too