Add transaction search
MODIFY
WalletWasabi.Fluent/App.axaml.cs
WalletWasabi.Fluent/App.axaml.cs
@@ -42,6 +42,7 @@ public class App : Application
new ApplicationStateManager(desktop, _startInBg);
DataContext = _applicationStateManager.ApplicationViewModel;
+ TransactionsWatcher.Instance = new TransactionsWatcher();
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;

ADD
WalletWasabi.Fluent/TransactionsWatcher.cs
+using System.Linq;
+using DynamicData;
+using ReactiveUI;
+using WalletWasabi.Fluent.ViewModels.SearchBar.Patterns;
+using WalletWasabi.Fluent.ViewModels.Wallets.Home.History;
+
+namespace WalletWasabi.Fluent;
+
+public class TransactionsWatcher
+{
+ public IObservable<IChangeSet<TransactionEntry, ComposedKey>> TransactionChanges { get; }
+ public static TransactionsWatcher Instance { get; set; } = new();
+
+ public TransactionsWatcher()
+ {
+ var cache = new SourceCache<TransactionEntry, ComposedKey>(x => x.Key);
+
+ MessageBus.Current.Listen<TransactionsChangedMessage>()
+ .Subscribe(msg =>
+ {
+ cache.Edit(r =>
+ {
+ var toRemove = r.Items.Where(r => r.Parent == msg.HistoryViewModel).ToList();
+ r.Remove(toRemove);
+ r.AddOrUpdate(msg.NewHistoryList
+ .OrderByDescending(r => r.Date)
+ .Select(b => new TransactionEntry(msg.HistoryViewModel, b)));
+ });
+ });
+
+ TransactionChanges = cache.Connect();
+ }
+}

MODIFY
WalletWasabi.Fluent/ViewModels/MainViewModel.cs
WalletWasabi.Fluent/ViewModels/MainViewModel.cs
+using System.Collections.Generic;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using Avalonia.Controls;
+using DynamicData;
using NBitcoin;
using ReactiveUI;
using WalletWasabi.Fluent.AppServices.Tor;
@@ -12,6 +14,7 @@ using WalletWasabi.Fluent.ViewModels.NavBar;
using WalletWasabi.Fluent.ViewModels.Navigation;
using WalletWasabi.Fluent.ViewModels.OpenDirectory;
using WalletWasabi.Fluent.ViewModels.SearchBar;
+using WalletWasabi.Fluent.ViewModels.SearchBar.SearchItems;
using WalletWasabi.Fluent.ViewModels.SearchBar.Sources;
using WalletWasabi.Fluent.ViewModels.Settings;
using WalletWasabi.Fluent.ViewModels.StatusIcon;
@@ -105,7 +108,7 @@ public partial class MainViewModel : ViewModelBase
}
});
- var source = new CompositeSearchItemsSource(new ActionsSource(), new SettingsSource(_settingsPage));
+ var source = new CompositeSearchItemsSource(new ActionsSource(), new SettingsSource(_settingsPage), new TransactionsSource());
SearchBar = new SearchBarViewModel(source.Changes);
NetworkBadgeName = Services.Config.Network == Network.Main ? "" : Services.Config.Network.Name;

ADD
WalletWasabi.Fluent/ViewModels/SearchBar/SearchItems/TransactionSearchItem.cs
+using System.Collections.Generic;
+using System.Linq;
+using NBitcoin;
+using WalletWasabi.Fluent.ViewModels.Wallets.Home.History.HistoryItems;
+
+namespace WalletWasabi.Fluent.ViewModels.SearchBar.SearchItems;
+
+internal class TransactionSearchItem
+{
+ public HistoryItemViewModelBase Transaction { get; }
+
+ public TransactionSearchItem(HistoryItemViewModelBase transaction)
+ {
+ Transaction = transaction;
+ Labels = transaction.Label.Labels.ToList();
+ Date = transaction.Date;
+ Id = transaction.Id.ToString();
+ Amount = transaction.IncomingAmount ?? -transaction.OutgoingAmount ?? Money.Zero;
+ Balance = transaction.Balance;
+ }
+
+ public Money Balance { get; }
+
+ public string Id { get; }
+
+ public DateTimeOffset Date { get; }
+
+ public List<string> Labels { get; }
+
+ public Money Amount { get; }
+}

ADD
WalletWasabi.Fluent/ViewModels/SearchBar/Sources/TransactionItemsSource.cs
+using System.Linq;
+using DynamicData;
+using WalletWasabi.Fluent.ViewModels.SearchBar.Patterns;
+using WalletWasabi.Fluent.ViewModels.SearchBar.SearchItems;
+using WalletWasabi.Fluent.ViewModels.Wallets.Home.History;
+
+namespace WalletWasabi.Fluent.ViewModels.SearchBar.Sources;
+
+public class TransactionsSource : ISearchItemSource
+{
+ public IObservable<IChangeSet<ISearchItem, ComposedKey>> Changes =>
+ TransactionsWatcher.Instance.TransactionChanges
+ .Transform(ToSearchItem);
+
+ private static ISearchItem ToSearchItem(TransactionEntry r)
+ {
+ var transactionId = r.HistoryItem.Id.ToString().Trim('0');
+ var keywords = r.HistoryItem.Label?.Concat(new[] { transactionId }) ?? Enumerable.Empty<string>();
+ return new NonActionableSearchItem(new TransactionSearchItem(r.HistoryItem), "", "Transactions", keywords.ToList(), "normal_transaction");
+ }
+}

MODIFY
WalletWasabi.Fluent/ViewModels/Wallets/Home/History/HistoryViewModel.cs
WalletWasabi.Fluent/ViewModels/Wallets/Home/History/HistoryViewModel.cs
@@ -223,6 +223,7 @@ public partial class HistoryViewModel : ActivatableViewModel
var rawHistoryList = await Task.Run(historyBuilder.BuildHistorySummary);
var orderedRawHistoryList = rawHistoryList.OrderBy(x => x.DateTime).ThenBy(x => x.Height).ThenBy(x => x.BlockIndex).ToList();
var newHistoryList = GenerateHistoryList(orderedRawHistoryList).ToArray();
+ MessageBus.Current.SendMessage(new TransactionsChangedMessage(this, newHistoryList));
_transactionSourceList.Edit(x =>
{

ADD
WalletWasabi.Fluent/ViewModels/Wallets/Home/History/TransactionEntry.cs
+using WalletWasabi.Fluent.ViewModels.SearchBar.Patterns;
+using WalletWasabi.Fluent.ViewModels.Wallets.Home.History.HistoryItems;
+
+namespace WalletWasabi.Fluent.ViewModels.Wallets.Home.History;
+
+public class TransactionEntry
+{
+ public HistoryItemViewModelBase HistoryItem { get; }
+
+ public TransactionEntry(HistoryViewModel parent, HistoryItemViewModelBase historyItem)
+ {
+ Parent = parent;
+ HistoryItem = historyItem;
+ Key = new ComposedKey(Parent, HistoryItem.Id);
+ }
+
+ public ComposedKey Key { get; }
+ public HistoryViewModel Parent { get; set; }
+}

MODIFY
WalletWasabi.Fluent/Views/SearchBar/SearchBarDropdown.axaml
WalletWasabi.Fluent/Views/SearchBar/SearchBarDropdown.axaml
</settings:SettingSelector.DataTemplates>
</settings:SettingSelector>
+ <DataTemplate DataType="searchItems:TransactionSearchItem">
+ <DockPanel ToolTip.Tip="{Binding Id}">
+ <TextBlock VerticalAlignment="Center" DockPanel.Dock="Right" Text="{Binding Amount, Converter={x:Static conv:MoneyConverters.ToFormattedString}}" Margin="10 0" />
+ <TextBlock VerticalAlignment="Center" DockPanel.Dock="Right" Text="{Binding Date, StringFormat='{}{0:d}'}" Margin="10 0" />
+ </DockPanel>
+ </DataTemplate>
+
<DataTemplate DataType="searchItems:NonActionableSearchItem">
<DockPanel Background="Transparent" Margin="10">

Add transaction search