feat(@desktop/wallet) reduce number of digits shown for large currency amounts

Fixes #8917
This commit is contained in:
Dario Gabriel Lipicar 2023-04-06 16:26:56 -03:00 committed by dlipicar
parent a2a6287537
commit da1839fbbb
6 changed files with 180 additions and 12 deletions

View File

@ -45,6 +45,10 @@ ListModel {
title: "CommunityMintedTokensView"
section: "Views"
}
ListElement {
title: "AmountToSendView"
section: "Views"
}
ListElement {
title: "StatusCommunityCard"
section: "Panels"

View File

@ -0,0 +1,113 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import AppLayouts.Profile.views 1.0
import Storybook 1.0
import StatusQ.Core 0.1
import utils 1.0
import shared.views 1.0
SplitView {
id: root
readonly property double maxCryptoBalance: parseFloat(maxCryptoBalanceText.text)
readonly property double rate: parseFloat(rateText.text)
readonly property int decimals: parseInt(decimalsText.text)
Logs { id: logs }
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
Item {
SplitView.fillWidth: true
SplitView.fillHeight: true
AmountToSend {
id: amountToSendInput
isBridgeTx: false
interactive: true
selectedSymbol: "Crypto"
maxInputBalance: inputIsFiat ? getFiatValue(root.maxCryptoBalance) : root.maxCryptoBalance
currentCurrency: "Fiat"
getFiatValue: function(cryptoValue) {
return cryptoValue * root.rate
}
getCryptoValue: function(fiatValue) {
return fiatValue / root.rate
}
formatCurrencyAmount: function(amount, symbol, options = null, locale = null) {
const currencyAmount = {
amount: amount,
symbol: symbol,
displayDecimals: root.decimals,
stripTrailingZeroes: true
}
return LocaleUtils.currencyAmountToLocaleString(currencyAmount, options)
}
onReCalculateSuggestedRoute: function() {
logs.logEvent("onReCalculateSuggestedRoute")
}
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
logsView.logText: logs.logText
}
}
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
ColumnLayout {
Label {
Layout.topMargin: 10
Layout.fillWidth: true
text: "Max Crypto Balance"
}
TextField {
id: maxCryptoBalanceText
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200
text: "1000000"
}
Label {
Layout.topMargin: 10
Layout.fillWidth: true
text: "Fiat/Crypto rate"
}
TextField {
id: rateText
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200
text: "10"
}
Label {
Layout.topMargin: 10
Layout.fillWidth: true
text: "Decimals"
}
TextField {
id: decimalsText
background: Rectangle { border.color: 'lightgrey' }
Layout.preferredWidth: 200
text: "6"
}
}
}
}

View File

@ -239,7 +239,7 @@ Item {
id: txtFiatBalance
Layout.rightMargin: 4
font.pixelSize: 15
text: LocaleUtils.currencyAmountToLocaleString(currencyBalance, {onlyAmount: true})
text: LocaleUtils.currencyAmountToLocaleString(currencyBalance, {noSymbol: true})
color: Theme.palette.directColor1
}
StatusBaseText {

View File

@ -8,6 +8,35 @@ QtObject {
readonly property var userInputLocale: Qt.locale("en_US")
function integralPartLength(num) {
num = Math.abs(num)
// According to the JS Reference:
//
// Scientific notation is used if the radix is 10 and the number's
// magnitude (ignoring sign) is greater than or equal to 10^21 or less
// than 10^-6. In this case, the returned string always explicitly
// specifies the sign of the exponent.
//
// In order to take it into account, numbers in scientific notation
// is handled separately.
if (num < 1) {
return 1
}
if (num >= 10**21) {
const split = num.toString().split('e')
if (split.length === 2) {
const base = parseFloat(split[0])
const exp = parseInt(split[1], 10)
return integralPartLength(base) + exp
}
}
return num.toFixed().length
}
function fractionalPartLength(num) {
if (Number.isInteger(num))
return 0
@ -86,12 +115,16 @@ QtObject {
return "N/A"
// Parse options
var optShowOnlyAmount = false
var optNoSymbol = false
var optRawAmount = false
var optDisplayDecimals = currencyAmount.displayDecimals
var optStripTrailingZeroes = currencyAmount.stripTrailingZeroes
if (options) {
if (options.onlyAmount !== undefined) {
optShowOnlyAmount = true
if (options.noSymbol !== undefined) {
optNoSymbol = true
}
if (options.rawAmount !== undefined) {
optRawAmount = true
}
if (options.minDecimals !== undefined && options.minDecimals > optDisplayDecimals) {
optDisplayDecimals = options.minDecimals
@ -101,23 +134,40 @@ QtObject {
}
}
var amountStr
var amountStr = ""
var amountSuffix = ""
let minAmount = 10**-optDisplayDecimals
if (currencyAmount.amount > 0 && currencyAmount.amount < minAmount && !optShowOnlyAmount)
if (currencyAmount.amount > 0 && currencyAmount.amount < minAmount && !optRawAmount)
{
// Handle amounts smaller than resolution
amountStr = "<%1".arg(numberToLocaleString(minAmount, optDisplayDecimals, locale))
amountStr = "<%1".arg(numberToLocaleString(minAmount, displayDecimals, locale))
} else {
// Normal formatting
amountStr = numberToLocaleString(currencyAmount.amount, optDisplayDecimals, locale)
var amount
var displayDecimals
const numIntegerDigits = integralPartLength(currencyAmount.amount)
const maxDigits = 10
// For large numbers, we use the short scale system (https://en.wikipedia.org/wiki/Long_and_short_scales)
// and 2 decimal digits.
if (numIntegerDigits > maxDigits && !optRawAmount) {
amount = currencyAmount.amount/10**9 // Billion => 9 zeroes
displayDecimals = 2
amountSuffix = qsTr("B", "Billion")
} else {
// For normal numbers, we show the whole integral part and as many decimal places not
// not to exceed the maximum
amount = currencyAmount.amount
displayDecimals = Math.min(optDisplayDecimals, Math.max(0, maxDigits - numIntegerDigits))
}
amountStr = numberToLocaleString(amount, displayDecimals, locale)
if (optStripTrailingZeroes) {
amountStr = stripTrailingZeroes(amountStr, locale)
}
}
// Add symbol
if (currencyAmount.symbol && !optShowOnlyAmount) {
amountStr = "%1 %2".arg(amountStr).arg(currencyAmount.symbol)
if (currencyAmount.symbol && !optNoSymbol) {
amountStr = "%1%2 %3".arg(amountStr).arg(amountSuffix).arg(currencyAmount.symbol)
}
return amountStr

View File

@ -132,7 +132,7 @@ ColumnLayout {
onClicked: {
topAmountToSendInput.validate()
if(!!topAmountToSendInput.text) {
topAmountToSendInput.text = root.formatCurrencyAmount(bottomItem.bottomAmountToSend, bottomItem.bottomAmountSymbol, {onlyAmount: true}, LocaleUtils.userInputLocale)
topAmountToSendInput.text = root.formatCurrencyAmount(bottomItem.bottomAmountToSend, bottomItem.bottomAmountSymbol, {noSymbol: true, rawAmount: true}, LocaleUtils.userInputLocale)
}
inputIsFiat = !inputIsFiat
d.waitTimer.restart()

View File

@ -11,3 +11,4 @@ ProfileDialogView 1.0 ProfileDialogView.qml
AssetsView 1.0 AssetsView.qml
HistoryView 1.0 HistoryView.qml
DeviceSyncingView 1.0 DeviceSyncingView.qml
AmountToSend 1.0 AmountToSend.qml