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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VDG] Unify amount display #11506

Merged
merged 37 commits into from
Oct 1, 2023

Conversation

SuperJMN
Copy link
Collaborator

@SuperJMN SuperJMN commented Sep 18, 2023

This PR normalizes amount displaying by using a BtcAmount type on the ViewModel side and an AmountControl in the View side. This also centralizes how things are displayed.

Benefits are:

  • We no longer have to worry about how an amount will be displayed in the UI.

  • By default, the amount will include the approximate USD equivalence (when needed).

  • Fee amounts will always obey user settings (either sats or BTC).

  • Bonus track 馃榿: If a new exchange rate arrives, the USD amount will vary accordingly, in a dynamic way.

    Fixes: 11423

@SuperJMN SuperJMN marked this pull request as draft September 18, 2023 09:04
@SuperJMN SuperJMN marked this pull request as ready for review September 18, 2023 09:43
@SuperJMN
Copy link
Collaborator Author

OK, after discussing a bit with @ichthus1604 we've decided to integrate the ability to create amounts in UiContext.
This is because creating amount is a cross-cutting concern in several ViewModels and adding a separate factory clutters contructors too much and doesn't offer any direct benefit (apart from being more explicit).

If this approach doesn't give the desired results, we can explorer further, but I think this will satisfy our needs while making things testable and decoupled.

@soosr
Copy link
Collaborator

soosr commented Sep 26, 2023

Oh, many conflicts!

Comment on lines 44 to 47
public BtcAmount CreateAmount(Money? money)
{
return new BtcAmount(money ?? Money.Zero, ExchangeRateProvider);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not have this method in the UiContext class itself, but rather inside a service.

Something like:

var amount = UiContext.AmountProvider.Create(money);

Also, don't forget to rename IExchangeRateProvider to IAmountProvider, because the former already exists in the backend and we don't want to introduce a name clash. Not a compilation problem because they're in different namespaces, but still confusing for people who look for these interfaces using Ctrl .

Copy link
Collaborator Author

@SuperJMN SuperJMN Sep 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't include a service because it's currently only a method now, but I'm OK with it.
Regarding the rename of IExchangeRateProvider to IAmountProvider. I think they're 2 different things. We still need an IExchangeRateProvider for scenarios like this:

https://github.com/zkSNACKs/WalletWasabi/blob/c2774d2af624a02796ffd6c8082ad31adbe051f5/WalletWasabi.Fluent/ViewModels/Wallets/Home/Tiles/BtcPriceTileViewModel.cs#L5C2-L5C2

We don't need an amount here, but only the exchange rate.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SuperJMN Also, in most cases we do have an IWalletModel, except for specific places like TransactionBroadcasterViewModel.

It's probably a good idea to add IWalletModel.CreateAmount(Money money) method as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SuperJMN Also, in most cases we do have an IWalletModel, except for specific places like TransactionBroadcasterViewModel.

It's probably a good idea to add IWalletModel.CreateAmount(Money money) method as well.

OK!

BTW, please, check BtcPriceTileViewModel.cs, where only the exchange rate is used, not a full amount.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SuperJMN How about moving the exchange rate observable to IAmountProvider? That way you only have 1 interface and you still keep the ability to provider exchange rate to ViewModels that need it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SuperJMN How about moving the exchange rate observable to IAmountProvider? That way you only have 1 interface and you still keep the ability to provider exchange rate to ViewModels that need it.

That makes me happier, but the name might be confusing. I wonder if there's a good name for the abstraction.

  • It deals with amounts in BTC and USD.
  • It provides exchange rates

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SuperJMN

I wonder if there's a good name for the abstraction

There are 2 hard things in computer science:

  • naming things <- you are here
  • cache misses
  • off by one errors

Jokes aside, maybe ICurrencyProvider is a better name? you'd probably have to rename BtcAmount to Currency as well

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed BtcAmount to just Amount. I think it plays well. What are your feelings @zkSNACKs/ui-team ?

@SuperJMN
Copy link
Collaborator Author

I think this is pretty much done.

Copy link
Collaborator

@ichthus1604 ichthus1604 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather keep the HasBalance observable, because that's required in many places and now those places are duplicating the logic:

this.WhenAnyObservable(x => x._wallet.Balances).Select(x => x != Money.Zero)

since you've deleted the WalletBalancesModel, maybe just add this property to the WalletModel itself.

@SuperJMN
Copy link
Collaborator Author

I'd rather keep the HasBalance observable, because that's required in many places and now those places are duplicating the logic:

this.WhenAnyObservable(x => x._wallet.Balances).Select(x => x != Money.Zero)

since you've deleted the WalletBalancesModel, maybe just add this property to the WalletModel itself.

Done! The logic is duplicated however, because in the Model I can't have accesss to Amount (Amount is a considered a ViewModel 馃榿).

As a side note, as I progress in my career, I see that the distinction between VMs and Models sometimes fades so much that you end up having a Model that is crafted so well that I can be used in the View with no changes.

@soosr
Copy link
Collaborator

soosr commented Sep 28, 2023

@ichthus1604 Merge this PR when you are happy with it

Copy link
Collaborator

@ichthus1604 ichthus1604 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. There are improvements I want to make to the design, but these can be part of a future PR.

@ichthus1604 ichthus1604 merged commit 3d9cc44 into WalletWasabi:master Oct 1, 2023
3 of 6 checks passed
@MarnixCroes
Copy link
Collaborator

#2110 would now be easy to implement?

@soosr
Copy link
Collaborator

soosr commented Oct 3, 2023

#2110 would now be easy to implement?

Maybe. Would be good to know why the original request got rejected.

@Kruwed
Copy link
Collaborator

Kruwed commented Nov 8, 2023

#2110 would now be easy to implement?

Maybe. Would be good to know why the original request got rejected.

It was one of the many that were closed due to being years old. It is still a relevant/requested feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Amounts are inconsistently created/displayed
5 participants