Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI] Exclude coins from coinjoin #12893

Merged
merged 34 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
36f0129
Exclude coins
SuperJMN Apr 18, 2024
4cf4c12
Fix build
SuperJMN Apr 18, 2024
019211b
Add "Forbidden" icon
SuperJMN Apr 22, 2024
72dfb8d
Add logic
SuperJMN Apr 22, 2024
35f7f27
Fix CF
SuperJMN Apr 22, 2024
c9e7b17
Implement selection policy
SuperJMN Apr 24, 2024
10ad5a6
New icon
SuperJMN Apr 24, 2024
d7504a2
Implement select all/none
SuperJMN Apr 24, 2024
1c1fffa
Change toggle selection button
SuperJMN Apr 24, 2024
96cdacd
minor fixes
soosr Apr 24, 2024
c14ce31
Merge from master
SuperJMN Apr 25, 2024
8b71718
Remove AppLifetime
SuperJMN Apr 25, 2024
27aaedd
Reviewed code
SuperJMN Apr 25, 2024
35b5c61
Fix messed up selection column after scrolling
soosr Apr 25, 2024
6dc81c4
Make checkbox disabled instead if hidden
soosr Apr 25, 2024
241513d
Don't show Banned when coin is excluded from CJ
SuperJMN Apr 25, 2024
0dbaa49
Merge branch 'features/exclude-coins' of https://github.com/SuperJMN/…
SuperJMN Apr 25, 2024
645a516
Attempt
SuperJMN Apr 25, 2024
f8390d3
Fixes
soosr Apr 25, 2024
9d17528
more cleanup and fix
soosr Apr 25, 2024
0a37995
fix init values
soosr Apr 25, 2024
53fb531
Fix indicator on pockets
soosr Apr 25, 2024
6885544
Fix multiple save at a time
soosr Apr 25, 2024
f1a589c
don"t use leaky abstraction
soosr Apr 25, 2024
6ac36ee
add missing dispose
soosr Apr 25, 2024
13c016e
Fix memory leak
soosr Apr 25, 2024
b88ddac
cleanup
soosr Apr 25, 2024
0be2ee9
Coinjoin -> coinjoin
soosr Apr 30, 2024
2e82fa8
Fix selection desync
SuperJMN Apr 30, 2024
34ca433
Add priority for excluded coins
SuperJMN Apr 30, 2024
6269c0b
Merge branch 'master' into pr/12893
soosr May 7, 2024
7f806d8
Fix initial coin selection
SuperJMN May 7, 2024
71dca70
Merge from master
SuperJMN May 10, 2024
58b01d8
Add Pockets is the source of truth
SuperJMN May 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions WalletWasabi.Fluent/Icons/Icons.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
<PathIcon Data="{StaticResource up_arrow}" />
<PathIcon Data="{StaticResource down_arrow}" />
<PathIcon Data="{StaticResource sorting}" />
<PathIcon Data="{StaticResource exclude_coins}" />
<PathIcon Data="{StaticResource forbidden}" />
<PathIcon Data="{StaticResource select_none}" />
<PathIcon Data="{StaticResource select_all}" />
</WrapPanel>
</Design.PreviewWith>
<Style>
Expand Down Expand Up @@ -197,6 +201,10 @@
<StreamGeometry x:Key="down_arrow">M3.93698 0.00427978L4.00059 0C4.23783 0 4.43389 0.176289 4.46488 0.405019L4.46919 0.468605L4.46863 8.40116L6.48013 6.38853C6.64646 6.22214 6.90681 6.2069 7.09032 6.34292L7.14287 6.38828C7.30931 6.55454 7.32456 6.8149 7.18848 6.9984L7.14318 7.05101L4.33386 9.86264C4.1676 10.029 3.90724 10.0443 3.72373 9.90826L3.67119 9.86289L0.857175 7.05126C0.6741 6.86832 0.673975 6.57166 0.8569 6.38853C1.02319 6.22214 1.28352 6.2069 1.46703 6.34292L1.51961 6.38828L3.53142 8.39866L3.53198 0.468605C3.53198 0.231366 3.70824 0.0353077 3.93698 0.00427978Z</StreamGeometry>
<StreamGeometry x:Key="sorting">M3.28077 0L3.21719 0.00427978C2.98846 0.0353077 2.81217 0.231366 2.81217 0.468605L2.81163 8.39866L0.79982 6.38828L0.747243 6.34292C0.563737 6.2069 0.303405 6.22214 0.137112 6.38853C-0.0458124 6.57166 -0.0456874 6.86832 0.137387 7.05126L2.95137 9.86289L3.00395 9.90826C3.18745 10.0443 3.44778 10.029 3.61408 9.86264L6.42339 7.05101L6.46869 6.9984C6.60477 6.8149 6.58953 6.55454 6.42308 6.38828L6.37053 6.34292C6.18703 6.2069 5.92667 6.22214 5.76035 6.38853L3.74884 8.40116L3.74938 0.468605L3.7451 0.405019C3.71407 0.176289 3.51801 0 3.28077 0ZM5.46706 0.312404C5.20827 0.312404 4.99846 0.522208 4.99846 0.781009C4.99846 1.03981 5.20827 1.24961 5.46706 1.24961H10.4655C10.7243 1.24961 10.9341 1.03981 10.9341 0.781009C10.9341 0.522208 10.7243 0.312404 10.4655 0.312404H5.46706ZM4.99846 2.65543C4.99846 2.39663 5.20827 2.18683 5.46706 2.18683H8.5911C8.84989 2.18683 9.0597 2.39663 9.0597 2.65543C9.0597 2.91423 8.84989 3.12404 8.5911 3.12404H5.46706C5.20827 3.12404 4.99846 2.91423 4.99846 2.65543ZM5.46706 4.06125C5.20827 4.06125 4.99846 4.27106 4.99846 4.52985C4.99846 4.78865 5.20827 4.99846 5.46706 4.99846H6.71668C6.97547 4.99846 7.18528 4.78865 7.18528 4.52985C7.18528 4.27106 6.97547 4.06125 6.71668 4.06125H5.46706Z</StreamGeometry>
<StreamGeometry x:Key="mail_unread">M16 6.5H5.25a1.75 1.75 0 0 0-1.744 1.606l-.004.1L11 12.153l6.03-3.174a3.489 3.489 0 0 0 2.97.985v6.786a3.25 3.25 0 0 1-3.066 3.245L16.75 20H5.25a3.25 3.25 0 0 1-3.245-3.066L2 16.75v-8.5a3.25 3.25 0 0 1 3.066-3.245L5.25 5h11.087A3.487 3.487 0 0 0 16 6.5Zm2.5 3.399-7.15 3.765a.75.75 0 0 1-.603.042l-.096-.042L3.5 9.9v6.85a1.75 1.75 0 0 0 1.606 1.744l.144.006h11.5a1.75 1.75 0 0 0 1.744-1.607l.006-.143V9.899ZM19.5 4a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5Z</StreamGeometry>
<StreamGeometry x:Key="exclude_coins">M 14.75 0 C 12.5 0 10.57 1.34 9.72 3.28 C 9.69 3.34 9.66 3.42 9.63 3.5 C 9.47 3.9 9.36 4.32 9.3 4.77 C 9.29 4.84 9.29 4.91 9.28 5 C 9.26 5.15 9.25 5.33 9.25 5.5 c 0 0.54 0.08 1.06 0.22 1.55 c 0.25 0.84 0.68 1.59 1.26 2.2 c 0.4 0.42 0.86 0.79 1.37 1.07 c 0.78 0.43 1.69 0.68 2.65 0.68 c 0.26 0 0.51 -0.03 0.75 -0.06 h 0.01 c 0.26 -0.04 0.5 -0.09 0.74 -0.15 c 0.26 -0.08 0.51 -0.16 0.75 -0.27 c 0.26 -0.12 0.51 -0.25 0.75 -0.42 c 0.27 -0.17 0.52 -0.36 0.75 -0.58 c 0.28 -0.26 0.53 -0.56 0.75 -0.87 c 0.63 -0.88 1 -1.98 1 -3.15 c 0 -3.05 -2.46 -5.5 -5.5 -5.5 z m 2.67 3.53 l -4.64 4.64 c -0.09 0.1 -0.22 0.15 -0.35 0.15 c -0.13 0 -0.26 -0.05 -0.35 -0.15 c -0.2 -0.19 -0.2 -0.51 0 -0.7 l 4.64 -4.64 c 0.19 -0.2 0.51 -0.2 0.7 0 c 0.2 0.19 0.2 0.51 0 0.7 z m 0.88 7.41 c -0.5 0.32 -1.03 0.57 -1.58 0.74 c -0.25 0.34 -0.7 0.68 -1.29 0.98 c -1.39 0.7 -3.59 1.22 -6.18 1.22 c -2.59 0 -4.79 -0.52 -6.18 -1.22 C 2.48 12.36 2.03 12.02 1.78 11.68 C 1.59 11.45 1.5 11.22 1.5 10.99 v -0.88 c 0.09 0.07 0.18 0.13 0.28 0.19 c 0.39 0.26 0.83 0.49 1.33 0.69 c 0.8 0.33 1.73 0.59 2.76 0.77 c 1.04 0.18 2.17 0.28 3.38 0.28 c 1.21 0 2.34 -0.1 3.38 -0.28 c 0.09 -0.02 0.17 -0.03 0.26 -0.05 c -0.84 -0.24 -1.62 -0.66 -2.29 -1.23 c -0.44 0.04 -0.89 0.06 -1.35 0.06 c -1.23 0 -2.37 -0.12 -3.38 -0.32 C 4.75 10.01 3.8 9.69 3.07 9.32 C 2.48 9.02 2.03 8.68 1.78 8.34 C 1.59 8.11 1.5 7.88 1.5 7.65 C 1.5 6.39 4.34 4.98 8.29 4.79 C 8.34 4.26 8.46 3.75 8.65 3.27 C 3.68 3.41 0 5.26 0 7.65 v 6.68 c 0 2.5 3.98 4.39 9.25 4.39 c 5.27 0 9.25 -1.89 9.25 -4.39 V 10.8 c -0.06 0.05 -0.13 0.1 -0.2 0.14 z m -1.3 3.4 c 0 1.36 -3.31 2.89 -7.75 2.89 c -4.44 0 -7.75 -1.53 -7.75 -2.89 v -0.88 c 0.09 0.06 0.18 0.13 0.28 0.19 c 1.66 1.07 4.33 1.74 7.47 1.74 c 3.14 0 5.81 -0.67 7.47 -1.74 c 0.1 -0.06 0.19 -0.13 0.28 -0.19 z</StreamGeometry>
<StreamGeometry x:Key="forbidden">M 8.01608 0 C 12.1582 0 15.5161 3.35787 15.5161 7.5 C 15.5161 11.6421 12.1582 15 8.01608 15 C 3.87395 15 0.516083 11.6421 0.516083 7.5 C 0.516083 3.35787 3.87395 0 8.01608 0 Z M 12.9574 3.25666 L 3.77274 12.4413 C 4.91254 13.4211 6.39517 14.0132 8.01608 14.0132 C 11.6132 14.0132 14.5292 11.0971 14.5292 7.5 C 14.5292 5.87909 13.9371 4.39646 12.9574 3.25666 Z M 8.01608 0.986842 C 4.41896 0.986842 1.50292 3.90288 1.50292 7.5 C 1.50292 9.12091 2.09504 10.6035 3.07477 11.7433 L 12.2594 2.55868 C 11.1196 1.57896 9.63699 0.986842 8.01608 0.986842 Z</StreamGeometry>
<StreamGeometry x:Key="select_none">M 1.6875 0 C 0.811127 0 0.090651 0.668804 0.0078125 1.52344 C 0.00255634 1.57766 0 1.63189 0 1.6875 C -1.21318e-05 1.69014 0 1.69267 0 1.69531 L 0 11.4355 L 0 11.4434 C 0.000255319 11.4989 0.00231271 11.5533 0.0078125 11.6074 C 0.090651 12.4621 0.811127 13.1309 1.6875 13.1309 L 11.4355 13.1309 C 12.3119 13.1309 13.0304 12.4621 13.1133 11.6074 C 13.119 11.5507 13.123 11.4938 13.123 11.4355 L 13.123 1.69531 L 13.123 1.6875 C 13.1228 1.63195 13.1188 1.5776 13.1133 1.52344 C 13.0304 0.668808 12.3119 0 11.4355 0 L 1.6875 0 z M 1.6875 1.13281 L 4.47656 1.13281 L 11.4355 1.13281 C 11.7073 1.13281 11.9339 1.32571 11.9863 1.58203 C 11.9933 1.61615 11.9975 1.65144 11.998 1.6875 L 11.998 1.69531 L 11.998 11.4355 C 11.998 11.4744 11.9938 11.5122 11.9863 11.5488 C 11.9339 11.8051 11.7073 11.998 11.4355 11.998 L 1.6875 11.998 C 1.41567 11.998 1.18917 11.8051 1.13672 11.5488 C 1.12923 11.5122 1.125 11.4744 1.125 11.4355 L 1.125 1.69531 L 1.125 1.6875 C 1.1255 1.65144 1.12974 1.61615 1.13672 1.58203 C 1.18917 1.32571 1.41567 1.13281 1.6875 1.13281 z M 13.873 2.7207 L 13.873 2.72852 L 13.8711 4.27344 L 13.8711 4.2832 L 13.875 4.3125 L 13.875 4.32031 L 13.875 11.8125 L 13.875 11.8203 C 13.8747 11.8888 13.872 11.9567 13.8652 12.0234 C 13.7596 13.0635 12.8804 13.875 11.8125 13.875 L 4.29297 13.875 L 2.7207 13.873 C 2.72168 13.8758 2.72362 13.8781 2.72461 13.8809 L 2.7207 13.8809 C 2.95155 14.5378 3.57668 15.0078 4.3125 15.0078 L 11.8125 15.0078 C 13.4655 15.0078 14.8247 13.7497 14.9844 12.1387 C 14.9953 12.0315 15 11.9225 15 11.8125 L 15 4.32031 L 15 4.3125 C 14.9998 4.26652 14.998 4.22083 14.9941 4.17578 C 14.9907 4.13334 14.985 4.09228 14.9785 4.05078 C 14.8818 3.43142 14.4502 2.92353 13.873 2.7207 z</StreamGeometry>
<StreamGeometry x:Key="select_all">M 1.6875 0 C 0.755521 0 0 0.755521 0 1.6875 L 0 11.4355 C 0 12.3675 0.755521 13.123 1.6875 13.123 L 11.4355 13.123 C 12.3675 13.123 13.123 12.3675 13.123 11.4355 L 13.123 1.6875 C 13.123 0.755521 12.3675 0 11.4355 0 L 1.6875 0 z M 1.6875 1.125 L 11.4355 1.125 C 11.7461 1.125 11.998 1.37684 11.998 1.6875 L 11.998 11.4355 C 11.998 11.7461 11.7461 11.998 11.4355 11.998 L 1.6875 11.998 C 1.37684 11.998 1.125 11.7461 1.125 11.4355 L 1.125 1.6875 C 1.125 1.37684 1.37684 1.125 1.6875 1.125 z M 13.873 2.7207 L 13.8711 4.27344 L 13.875 4.3125 L 13.875 11.8125 C 13.875 12.9516 12.9516 13.875 11.8125 13.875 L 4.29297 13.875 L 2.7207 13.873 C 2.95155 14.5299 3.57668 15 4.3125 15 L 11.8125 15 C 13.5729 15 15 13.5729 15 11.8125 L 15 4.3125 C 15 3.57668 14.5299 2.95155 13.873 2.7207 z M 9 3.9375 C 8.85606 3.9375 8.7114 3.99173 8.60156 4.10156 L 5.68555 7.01953 L 4.94922 6.03711 L 4.89453 5.97461 C 4.69964 5.78172 4.38805 5.75632 4.16211 5.92578 C 3.91358 6.11215 3.86438 6.46434 4.05078 6.71289 L 5.17578 8.21289 L 5.23047 8.27539 C 5.44628 8.48876 5.80158 8.49536 6.02344 8.27344 L 9.39844 4.89844 L 9.45312 4.83398 C 9.61654 4.61377 9.59816 4.30126 9.39844 4.10156 C 9.2886 3.99173 9.14394 3.9375 9 3.9375 z</StreamGeometry>

<ControlTemplate x:Key="wasabi_logo_text_dynamic">
<StackPanel Margin="0,0,0,-5" TextElement.FontFamily="{StaticResource WasabiLogoTextFont}"
Expand Down
15 changes: 15 additions & 0 deletions WalletWasabi.Fluent/Models/Wallets/WalletModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using NBitcoin;
using ReactiveUI;
Expand Down Expand Up @@ -68,6 +69,20 @@ public WalletModel(Wallet wallet, IAmountProvider amountProvider)
.BindTo(this, x => x.IsLoggedIn);
}

public IEnumerable<ICoinModel> ExcludedCoins
{
get => Coins.List.Items.Where(x => x.GetSmartCoin().IsExcludedFromCoinJoin);
set
{
var excludedOutpoints = value.Select(x => x.GetSmartCoin().Outpoint).ToHashSet();

foreach (var coin in Wallet.Coins)
{
Wallet.ExcludeCoinFromCoinJoin(coin.Outpoint, excludedOutpoints.Contains(coin.Outpoint));
}
}
}

public IAddressesModel Addresses { get; }

internal Wallet Wallet { get; }
Expand Down
10 changes: 9 additions & 1 deletion WalletWasabi.Fluent/Styles/Button.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@
</Style>
</ControlTheme>

<ControlTheme x:Key="DialogSortButton" TargetType="Button" BasedOn="{StaticResource SortButtonBase}">
<ControlTheme x:Key="DialogButton" TargetType="Button" BasedOn="{StaticResource SortButtonBase}">
<Setter Property="Width" Value="35" />
<Setter Property="Height" Value="35" />
<Setter Property="CornerRadius" Value="100" />
<Setter Property="Padding" Value="-1 1 0 0" />
</ControlTheme>

<ControlTheme x:Key="DialogSortButton" TargetType="Button" BasedOn="{StaticResource DialogButton}">
<Setter Property="Width" Value="35" />
<Setter Property="Height" Value="35" />
<Setter Property="CornerRadius" Value="100" />
Expand Down Expand Up @@ -212,6 +219,7 @@
<Button Theme="{StaticResource AccentButton}" IsEnabled="False" Content="Accent Button Disabled" />
<Button Theme="{StaticResource SortButtonBase}">Layer2</Button>
<Button Theme="{StaticResource HistorySortButton}" />
<Button Theme="{StaticResource DialogButton}" />
<Button Theme="{StaticResource DialogSortButton}" />
</StackPanel>
</Border>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@

NavigateToSettingsCommand = coinJoinSettingsCommand;
CanNavigateToCoinjoinSettings = coinJoinSettingsCommand.CanExecute;
NavigateToExcludedCoinsCommand = ReactiveCommand.Create(() => UiContext.Navigate().To().ExcludedCoins(_wallet));

Check warning on line 168 in WalletWasabi.Fluent/ViewModels/Wallets/CoinJoinStateViewModel.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (master)

❌ Getting worse: Large Method

CoinJoinStateViewModel increases from 78 to 79 lines of code, threshold = 70. Large functions with many lines of code are generally harder to understand and lower the code health. Avoid adding more lines to this function.
}

private enum State
Expand Down Expand Up @@ -195,6 +196,8 @@

public ICommand NavigateToSettingsCommand { get; }

public ICommand NavigateToExcludedCoinsCommand { get; }

public bool IsAutoCoinJoinEnabled => _wallet.Settings.AutoCoinjoin;

public IObservable<bool> AutoCoinJoinObservable { get; }
Expand Down
6 changes: 3 additions & 3 deletions WalletWasabi.Fluent/ViewModels/Wallets/Coins/CoinListItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public abstract partial class CoinListItem : ViewModelBase, ITreeDataGridExpande
[AutoNotify] private bool _isControlPointerOver;
[AutoNotify] private bool _isExpanded;
[AutoNotify] private bool _isCoinjoining;
[AutoNotify] private bool _isExcludedFromCoinJoin;
[AutoNotify] private bool _canBeSelected;

protected CoinListItem()
{
Expand Down Expand Up @@ -93,9 +95,7 @@ public bool IsSelectedProxy
public bool IsChild { get; set; }

public bool IsLastChild { get; set; }

public bool CanBeSelected { get; protected set; }


public bool IgnorePrivacyMode { get; protected set; }

public bool? IsSelected
Expand Down
7 changes: 7 additions & 0 deletions WalletWasabi.Fluent/ViewModels/Wallets/Coins/CoinViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reactive.Disposables;
using System.Reactive.Linq;
using ReactiveUI;
using WalletWasabi.Blockchain.Analysis.Clustering;
using WalletWasabi.Fluent.Helpers;
Expand Down Expand Up @@ -26,7 +27,13 @@ public CoinViewModel(LabelsArray labels, ICoinModel coin, bool ignorePrivacyMode
IsSelected = false;
ScriptType = coin.ScriptType;
IgnorePrivacyMode = ignorePrivacyMode;
this.WhenAnyValue(x => x.Coin.IsExcludedFromCoinJoin).BindTo(this, x => x.IsExcludedFromCoinJoin).DisposeWith(_disposables);
this.WhenAnyValue(x => x.Coin.IsCoinJoinInProgress).BindTo(this, x => x.IsCoinjoining).DisposeWith(_disposables);
this.WhenAnyValue(x => x.Coin.IsCoinJoinInProgress, b => !b).BindTo(this, x => x.CanBeSelected).DisposeWith(_disposables);
soosr marked this conversation as resolved.
Show resolved Hide resolved
this.WhenAnyValue(x => x.CanBeSelected)
.Where(b => !b)
.Do(_ => IsSelected = false)
.Subscribe();
}

public ICoinModel Coin { get; }
Expand Down
24 changes: 19 additions & 5 deletions WalletWasabi.Fluent/ViewModels/Wallets/Coins/PocketViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Reactive.Disposables;
using System.Reactive.Linq;
using DynamicData;
using DynamicData.Aggregation;
using ReactiveUI;
using WalletWasabi.Blockchain.TransactionOutputs;
using WalletWasabi.Fluent.Models;
Expand Down Expand Up @@ -30,10 +31,13 @@ public PocketViewModel(IWalletModel wallet, Pocket pocket, bool ignorePrivacyMod
AnonymityScore = GetAnonScore(pocketCoins);
Labels = pocket.Labels;
Children =
pocketCoins.Select(wallet.Coins.GetCoinModel)
.OrderByDescending(x => x.AnonScore)
.Select(coin => new CoinViewModel("", coin, ignorePrivacyMode) { IsChild = true })
.ToList();
pocketCoins
.Select(wallet.Coins.GetCoinModel)
.OrderByDescending(x => x.AnonScore)
.Select(coin => new CoinViewModel("", coin, ignorePrivacyMode) { IsChild = true })
.ToList();

IsExcludedFromCoinJoin = pocketCoins.All(x => x.IsExcludedFromCoinJoin);

Children
.AsObservableChangeSet()
Expand All @@ -42,7 +46,6 @@ public PocketViewModel(IWalletModel wallet, Pocket pocket, bool ignorePrivacyMod
.BindTo(this, x => x.IsCoinjoining)
.DisposeWith(_disposables);

CanBeSelected = true;
ScriptType = null;

Children
Expand Down Expand Up @@ -81,8 +84,19 @@ public PocketViewModel(IWalletModel wallet, Pocket pocket, bool ignorePrivacyMod
})
.Subscribe()
.DisposeWith(_disposables);

ThereAreSelectableCoins()
.BindTo(this, x => x.CanBeSelected)
.DisposeWith(_disposables);
}

private IObservable<bool> ThereAreSelectableCoins() => Children
.AsObservableChangeSet()
.AutoRefresh(x => x.CanBeSelected)
.Filter(x => x.CanBeSelected)
.Count()
.Select(i => i > 0);

public void Dispose()
{
_disposables.Dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows.Input;
using DynamicData;
using DynamicData.Aggregation;
using DynamicData.Binding;
using ReactiveUI;
using WalletWasabi.Fluent.Infrastructure;
using WalletWasabi.Fluent.Models.Wallets;
using WalletWasabi.Fluent.ViewModels.Dialogs.Base;
using WalletWasabi.Fluent.ViewModels.Wallets.Coins;

namespace WalletWasabi.Fluent.ViewModels.Wallets.Settings;

[AppLifetime]
soosr marked this conversation as resolved.
Show resolved Hide resolved
[NavigationMetaData(Title = "Excluded Coins", NavigationTarget = NavigationTarget.DialogScreen)]
public partial class ExcludedCoinsViewModel : DialogViewModelBase<Unit>
{
private readonly IWalletModel _wallet;
private readonly CompositeDisposable _disposables = new();
soosr marked this conversation as resolved.
Show resolved Hide resolved

[AutoNotify] private bool _hasSelection;

public ExcludedCoinsViewModel(IWalletModel wallet)
{
_wallet = wallet;
CoinList = new CoinListViewModel(wallet, wallet.ExcludedCoins.ToList(), true);
SetupCancel(enableCancel: true, enableCancelOnEscape: true, enableCancelOnPressed: true);
NextCommand = ReactiveCommand.Create(
() =>
{
ExcludeSelectedCoins();
Close();
});

ToggleSelectionCommand = ReactiveCommand.Create(() => SelectAll(!CoinList.Selection.Any()));
}

private void SelectAll(bool value)
{
foreach (var coin in CoinList.CoinItems)
{
coin.IsSelected = value;
}
}

public ICommand ToggleSelectionCommand { get; }
soosr marked this conversation as resolved.
Show resolved Hide resolved

protected override void OnNavigatedTo(bool isInHistory, CompositeDisposable disposables)
{
CoinList.CoinItems
.ToObservableChangeSet()
.WhenPropertyChanged(x => x.IsSelected)
.Select(_ => CoinList.Selection.Count > 0)
.BindTo(this, x => x.HasSelection)
.DisposeWith(_disposables);
soosr marked this conversation as resolved.
Show resolved Hide resolved
}

protected override void OnNavigatedFrom(bool isInHistory)
{
if (!isInHistory)
{
_disposables.Dispose();
}
}
soosr marked this conversation as resolved.
Show resolved Hide resolved

public CoinListViewModel CoinList { get; set; }

private void ExcludeSelectedCoins()
{
_wallet.ExcludedCoins = CoinList.Selection;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,14 @@
ToolTip.Tip="Pending" />
</Panel>

<Panel IsVisible="{Binding !IsBanned}">
<Panel>
<!-- CJ active -->
<Panel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
<Binding Path="!IsBanned"/>
<Binding Path="!IsExcludedFromCoinJoin"/>
</MultiBinding>
</Panel.IsVisible>
<PathIcon IsVisible="{Binding IsCoinjoining}"
Data="{StaticResource wallet_action_coinjoin}"
Foreground="{DynamicResource SystemAccentColor}"
Expand All @@ -48,6 +54,12 @@
Height="14"
ToolTip.Tip="{Binding BannedUntilUtcToolTip}" />

<PathIcon IsVisible="{Binding IsExcludedFromCoinJoin}"
Data="{StaticResource forbidden}"
Foreground="{DynamicResource CoinjoinActiveColor}"
Height="14"
ToolTip.Tip="Excluded from coinjoins" />

<Border BorderThickness="1"
VerticalAlignment="Center"
IsVisible="{Binding ScriptType.ShortName, Converter={x:Static StringConverters.IsNotNullOrEmpty}, FallbackValue='False'}"
Expand Down
5 changes: 5 additions & 0 deletions WalletWasabi.Fluent/Views/Wallets/MusicControlsView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
<PathIcon Data="{StaticResource settings_general_regular}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Exclude Coins" Command="{Binding NavigateToExcludedCoinsCommand}">
<MenuItem.Icon>
<PathIcon Data="{StaticResource exclude_coins}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Button.Flyout>
<PathIcon Data="{StaticResource more_regular}" Opacity="0.6" />
Expand Down