Make suggestions sophisticated and actually useful
MODIFY
WalletWasabi.Fluent/Behaviors/PasteButtonFlashBehavior.cs
WalletWasabi.Fluent/Behaviors/PasteButtonFlashBehavior.cs
@@ -78,6 +78,12 @@ public class PasteButtonFlashBehavior : AttachedToVisualTreeBehavior<AnimatedBut
{
var clipboardValue = await clipboard.GetTextAsync();
+ // Yes, it can be null, the software crashed without this condition.
+ if (clipboardValue is null)
+ {
+ return;
+ }
+
if (AssociatedObject is null)
{
return;

MODIFY
WalletWasabi.Fluent/Helpers/WalletHelpers.cs
WalletWasabi.Fluent/Helpers/WalletHelpers.cs
@@ -22,13 +22,20 @@ public static class WalletHelpers
return keyManager.IsHardwareWallet ? WalletType.Hardware : WalletType.Normal;
}
+ /// <returns>Labels ordered by blockchain.</returns>
public static IEnumerable<SmartLabel> GetTransactionLabels() => Services.BitcoinStore.TransactionStore.GetLabels();
- public static IEnumerable<SmartLabel> GetAddressLabels() =>
+ public static IEnumerable<SmartLabel> GetReceiveAddressLabels() =>
Services.WalletManager
.GetWallets(refreshWalletList: false) // Don't refresh wallet list as it may be slow.
.Select(x => x.KeyManager)
- .SelectMany(x => x.GetLabels());
+ .SelectMany(x => x.GetReceiveLabels());
+
+ public static IEnumerable<SmartLabel> GetChangeAddressLabels() =>
+ Services.WalletManager
+ .GetWallets(refreshWalletList: false) // Don't refresh wallet list as it may be slow.
+ .Select(x => x.KeyManager)
+ .SelectMany(x => x.GetChangeLabels());
public static (ErrorSeverity Severity, string Message)? ValidateWalletName(string walletName)
{

MODIFY
WalletWasabi.Fluent/ViewModels/Dialogs/LabelEntryDialogViewModel.cs
WalletWasabi.Fluent/ViewModels/Dialogs/LabelEntryDialogViewModel.cs
@@ -21,7 +21,7 @@ public partial class LabelEntryDialogViewModel : DialogViewModelBase<SmartLabel?
public LabelEntryDialogViewModel(Wallet wallet, TransactionInfo info)
{
_wallet = wallet;
- SuggestionLabels = new SuggestionLabelsViewModel(Intent.Send, 3)
+ SuggestionLabels = new SuggestionLabelsViewModel(wallet.KeyManager, Intent.Send, 3)
{
Labels = { info.UserLabels.Labels }
};

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Labels/SuggestionLabelsViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Labels/SuggestionLabelsViewModel.cs
@@ -6,7 +6,9 @@ using System.Reactive.Linq;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
+using WalletWasabi.Blockchain.Keys;
using WalletWasabi.Fluent.Helpers;
+using WalletWasabi.Wallets;
namespace WalletWasabi.Fluent.ViewModels.Wallets.Labels;
@@ -19,8 +21,9 @@ public partial class SuggestionLabelsViewModel : ViewModelBase
[AutoNotify] private bool _isCurrentTextValid;
- public SuggestionLabelsViewModel(Intent intent, int topSuggestionsCount, IEnumerable<string>? labels = null)
+ public SuggestionLabelsViewModel(KeyManager keyManager, Intent intent, int topSuggestionsCount, IEnumerable<string>? labels = null)
{
+ KeyManager = keyManager;
Intent = intent;
_sourceLabels = new SourceList<SuggestionLabelViewModel>();
_topSuggestions = new ObservableCollectionExtended<string>();
@@ -37,29 +40,64 @@ public partial class SuggestionLabelsViewModel : ViewModelBase
public ObservableCollection<string> Labels => _labels;
+ public KeyManager KeyManager { get; }
public Intent Intent { get; }
public void UpdateLabels()
{
var labelPool = new Dictionary<string, int>(); // int: score.
- foreach (var label in WalletHelpers.GetAddressLabels().SelectMany(x => x.Labels))
+
+ // Make recent and receive labels count more for the current wallet
+ var multiplier = 100;
+ foreach (var label in KeyManager.GetReceiveLabels().Reverse().SelectMany(x => x.Labels))
+ {
+ var score = (Intent == Intent.Receive ? 100 : 1) * multiplier;
+ if (!labelPool.TryAdd(label, score))
+ {
+ labelPool[label] += score;
+ }
+
+ if (multiplier > 1)
+ {
+ multiplier--;
+ }
+ }
+
+ // Receive addresses should be more dominant.
+ foreach (var label in WalletHelpers.GetReceiveAddressLabels().SelectMany(x => x.Labels))
{
- var score = Intent == Intent.Receive ? 10 : 1;
+ var score = Intent == Intent.Receive ? 100 : 1;
if (!labelPool.TryAdd(label, score))
{
labelPool[label] += score;
}
}
- foreach (var label in WalletHelpers.GetTransactionLabels().SelectMany(x => x.Labels))
+ // Change addresses shouldn't be much dominant, but should be present.
+ foreach (var label in WalletHelpers.GetChangeAddressLabels().SelectMany(x => x.Labels))
{
- var score = Intent == Intent.Send ? 10 : 1;
+ var score = 1;
if (!labelPool.TryAdd(label, score))
{
labelPool[label] += score;
}
}
+ multiplier = 100; // Make recent labels count more.
+ foreach (var label in WalletHelpers.GetTransactionLabels().SelectMany(x => x.Labels).Reverse())
+ {
+ var score = (Intent == Intent.Send ? 100 : 1) * multiplier;
+ if (!labelPool.TryAdd(label, score))
+ {
+ labelPool[label] += score;
+ }
+
+ if (multiplier > 1)
+ {
+ multiplier--;
+ }
+ }
+
var unwantedLabelSuggestions = new[]
{
"test", // Often people use the string "test" as a label. It obviously cannot be a real label, just a test label.

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Receive/AddressLabelEditViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Receive/AddressLabelEditViewModel.cs
@@ -14,7 +14,7 @@ public partial class AddressLabelEditViewModel : RoutableViewModel
public AddressLabelEditViewModel(ReceiveAddressesViewModel owner, HdPubKey hdPubKey, KeyManager keyManager)
{
- SuggestionLabels = new SuggestionLabelsViewModel(Intent.Receive, 3, hdPubKey.Label);
+ SuggestionLabels = new SuggestionLabelsViewModel(keyManager, Intent.Receive, 3, hdPubKey.Label);
SetupCancel(enableCancel: true, enableCancelOnEscape: true, enableCancelOnPressed: true);

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Receive/ReceiveViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Receive/ReceiveViewModel.cs
@@ -31,7 +31,7 @@ public partial class ReceiveViewModel : RoutableViewModel
EnableBack = false;
- SuggestionLabels = new SuggestionLabelsViewModel(Intent.Receive, 3);
+ SuggestionLabels = new SuggestionLabelsViewModel(wallet.KeyManager, Intent.Receive, 3);
var nextCommandCanExecute =
SuggestionLabels

MODIFY
WalletWasabi/Blockchain/Keys/KeyManager.cs
WalletWasabi/Blockchain/Keys/KeyManager.cs
@@ -522,7 +522,9 @@ public class KeyManager
return extKeysAndPubs;
}
- public IEnumerable<SmartLabel> GetLabels() => GetKeys().Select(x => x.Label);
+ public IEnumerable<SmartLabel> GetChangeLabels() => GetKeys(x => x.IsInternal).Select(x => x.Label);
+
+ public IEnumerable<SmartLabel> GetReceiveLabels() => GetKeys(x => !x.IsInternal).Select(x => x.Label);
public ExtKey GetMasterExtKey(string password)
{

MODIFY
WalletWasabi/Blockchain/Transactions/AllTransactionStore.cs
WalletWasabi/Blockchain/Transactions/AllTransactionStore.cs
@@ -206,6 +206,7 @@ public class AllTransactionStore : IAsyncDisposable
}
}
+ /// <returns>Transactions ordered by blockchain.</returns>
public IEnumerable<SmartTransaction> GetTransactions()
{
lock (Lock)
@@ -261,6 +262,7 @@ public class AllTransactionStore : IAsyncDisposable
}
}
+ /// <returns>Labels ordered by blockchain.</returns>
public IEnumerable<SmartLabel> GetLabels() => GetTransactions().Select(x => x.Label);
#endregion Accessors

Make suggestions sophisticated and actually useful