feat(@desktop/wallet): implement unified currency formatting in send/bridge modal

Fixes #8934
This commit is contained in:
Dario Gabriel Lipicar 2023-01-08 19:23:51 -03:00 committed by dlipicar
parent ae55e78faf
commit d11017f7b3
31 changed files with 336 additions and 247 deletions

View File

@ -43,6 +43,9 @@ proc isMnemonicBackedUp*(self: Controller): bool =
proc getCurrencyBalance*(self: Controller): CurrencyAmount =
return currencyAmountToItem(self.walletAccountService.getTotalCurrencyBalance(), self.currencyService.getCurrencyFormat(self.getCurrency()))
proc getCurrencyAmount*(self: Controller, amount: float64, symbol: string): CurrencyAmount =
return currencyAmountToItem(amount, self.currencyService.getCurrencyFormat(symbol))
proc updateCurrency*(self: Controller, currency: string) =
self.walletAccountService.updateCurrency(currency)

View File

@ -1,3 +1,6 @@
import ../../shared_models/currency_amount
export CurrencyAmount
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
## Abstract class for any input/interaction with this module.
@ -23,6 +26,9 @@ method updateCurrency*(self: AccessInterface, currency: string) {.base.} =
method setTotalCurrencyBalance*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method getCurrencyAmount*(self: AccessInterface, amount: float64, symbol: string): CurrencyAmount {.base.} =
raise newException(ValueError, "No implementation available")
# View Delegate Interface
# Delegate for the view must be declared here due to use of QtObject and multi
# inheritance, which is not well supported in Nim.

View File

@ -100,6 +100,9 @@ method switchAccountByAddress*(self: Module, address: string) =
method setTotalCurrencyBalance*(self: Module) =
self.view.setTotalCurrencyBalance(self.controller.getCurrencyBalance())
method getCurrencyAmount*(self: Module, amount: float64, symbol: string): CurrencyAmount =
return self.controller.getCurrencyAmount(amount, symbol)
method load*(self: Module) =
singletonInstance.engine.setRootContextProperty("walletSection", newQVariant(self.view))

View File

@ -1,4 +1,4 @@
import NimQml
import NimQml, json
import ./io_interface
import ../../shared_models/currency_amount
@ -75,6 +75,13 @@ QtObject:
self.currentCurrency = currency
self.currentCurrencyChanged()
# Returning a QVariant from a slot with parameters other than "self" won't compile
# proc getCurrencyAmount*(self: View, amount: float, symbol: string): QVariant {.slot.} =
# return newQVariant(self.delegate.getCurrencyAmount(amount, symbol))
proc getCurrencyAmountAsJson*(self: View, amount: float, symbol: string): string {.slot.} =
return $self.delegate.getCurrencyAmount(amount, symbol).toJsonNode()
proc setData*(self: View, currency, signingPhrase: string, mnemonicBackedUp: bool) =
self.currentCurrency = currency
self.signingPhrase = signingPhrase

View File

@ -21,6 +21,14 @@ logScope:
include async_tasks
const ETHEREUM_SYMBOL = "ETH"
const CRYPTO_SUB_UNITS_TO_FACTOR = {
"WEI": (ETHEREUM_SYMBOL, 1e-18),
"KWEI": (ETHEREUM_SYMBOL, 1e-15),
"MWEI": (ETHEREUM_SYMBOL, 1e-12),
"GWEI": (ETHEREUM_SYMBOL, 1e-9),
}.toTable()
# Signals which may be emitted by this service:
const SIGNAL_TOKEN_HISTORICAL_DATA_LOADED* = "tokenHistoricalDataLoaded"
const SIGNAL_BALANCE_HISTORY_DATA_READY* = "tokenBalanceHistoryDataReady"
@ -130,26 +138,35 @@ QtObject:
proc getTokenPriceCacheKey(crypto: string, fiat: string) : string =
return renameSymbol(crypto) & renameSymbol(fiat)
proc getCryptoKeyAndFactor(crypto: string) : (string, float64) =
let cryptoKey = renameSymbol(crypto)
return CRYPTO_SUB_UNITS_TO_FACTOR.getOrDefault(cryptoKey, (cryptoKey, 1.0))
proc isCachedTokenPriceRecent*(self: Service, crypto: string, fiat: string): bool =
let cacheKey = getTokenPriceCacheKey(crypto, fiat)
let (cryptoKey, _) = getCryptoKeyAndFactor(crypto)
let cacheKey = getTokenPriceCacheKey(cryptoKey, fiat)
return self.priceCache.isCached(cacheKey)
proc getCachedTokenPrice*(self: Service, crypto: string, fiat: string): float64 =
let cacheKey = getTokenPriceCacheKey(crypto, fiat)
let (cryptoKey, factor) = getCryptoKeyAndFactor(crypto)
let cacheKey = getTokenPriceCacheKey(cryptoKey, fiat)
if self.priceCache.hasKey(cacheKey):
return self.priceCache.get(cacheKey)
return self.priceCache.get(cacheKey) * factor
else:
return 0.0
proc getTokenPrice*(self: Service, crypto: string, fiat: string, fetchIfNotAvailable: bool = true): float64 =
let cacheKey = getTokenPriceCacheKey(crypto, fiat)
proc getTokenPrice*(self: Service, crypto: string, fiat: string): float64 =
let fiatKey = renameSymbol(fiat)
let (cryptoKey, factor) = getCryptoKeyAndFactor(crypto)
let cacheKey = getTokenPriceCacheKey(cryptoKey, fiatKey)
if self.priceCache.isCached(cacheKey):
return self.priceCache.get(cacheKey)
return self.priceCache.get(cacheKey) * factor
var prices = initTable[string, Table[string, float]]()
try:
let cryptoKey = renameSymbol(crypto)
let fiatKey = renameSymbol(fiat)
let response = backend.fetchPrices(@[cryptoKey], @[fiatKey])
for (symbol, pricePerCurrency) in response.result.pairs:
prices[symbol] = initTable[string, float]()
@ -157,7 +174,7 @@ QtObject:
prices[symbol][currency] = price.getFloat
self.updateCachedTokenPrice(cryptoKey, fiatKey, prices[cryptoKey][fiatKey])
return prices[cryptoKey][fiatKey]
return prices[cryptoKey][fiatKey] * factor
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription

View File

@ -27,20 +27,28 @@ QtObject {
return num.toLocaleString(locale, 'f', precision)
}
function currencyAmountToLocaleString(currencyAmount, locale) {
if (!locale) {
console.log("Unspecified locale for: " + JSON.stringify(currencyAmount))
locale = Qt.locale()
function numberFromLocaleString(num, locale = null) {
locale = locale || Qt.locale()
return Number.fromLocaleString(locale, num)
}
function currencyAmountToLocaleString(currencyAmount, options = null, locale = null) {
locale = locale || Qt.locale()
if (!currencyAmount) {
return "N/A"
}
if (typeof(currencyAmount) !== "object") {
console.log("Wrong type for currencyAmount: " + JSON.stringify(currencyAmount))
console.trace()
return NaN
}
var amountStr = numberToLocaleString(currencyAmount.amount, currencyAmount.displayDecimals, locale)
if (currencyAmount.stripTrailingZeroes) {
amountStr = stripTrailingZeroes(amountStr, locale)
}
if (currencyAmount.symbol) {
if (currencyAmount.symbol && !(options && options.onlyAmount)) {
amountStr = "%1 %2".arg(amountStr).arg(currencyAmount.symbol)
}
return amountStr

View File

@ -204,10 +204,12 @@ Popup {
AssetsView {
id: assetsTab
locale: RootStore.locale
account: WalletStore.dappBrowserAccount
}
HistoryView {
id: historyTab
locale: RootStore.locale
account: WalletStore.dappBrowserAccount
}
}

View File

@ -46,7 +46,7 @@ Item {
font.pixelSize: 28
font.bold: true
color: Theme.palette.baseColor1
text: LocaleUtils.currencyAmountToLocaleString(root.currentAccount.currencyBalance, root.locale)
text: LocaleUtils.currencyAmountToLocaleString(root.currentAccount.currencyBalance)
}
}

View File

@ -82,7 +82,7 @@ Rectangle {
objectName: "walletLeftListAmountValue"
color: Style.current.textColor
text: {
LocaleUtils.currencyAmountToLocaleString(RootStore.totalCurrencyBalance, RootStore.currencyStore.locale)
LocaleUtils.currencyAmountToLocaleString(RootStore.totalCurrencyBalance)
}
selectByMouse: true
cursorVisible: true
@ -117,7 +117,7 @@ Rectangle {
width: ListView.view.width
highlighted: RootStore.currentAccount.name === model.name
title: model.name
subTitle: LocaleUtils.currencyAmountToLocaleString(model.currencyBalance, RootStore.currencyStore.locale)
subTitle: LocaleUtils.currencyAmountToLocaleString(model.currencyBalance)
asset.emoji: !!model.emoji ? model.emoji: ""
asset.color: model.color
asset.name: !model.emoji ? "filled-account": ""

View File

@ -104,6 +104,7 @@ Item {
}
}
HistoryView {
locale: RootStore.locale
account: RootStore.currentAccount
onLaunchTransactionDetail: {
transactionDetailView.transaction = transaction
@ -127,6 +128,7 @@ Item {
}
TransactionDetailView {
id: transactionDetailView
locale: RootStore.locale
Layout.fillWidth: true
Layout.fillHeight: true
sendModal: root.sendModal

View File

@ -54,7 +54,7 @@ Item {
anchors.leftMargin: Style.current.smallPadding
font.pixelSize: 15
color: Style.current.secondaryText
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkBalance, root.locale)
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkBalance)
}
StyledText {
@ -65,6 +65,6 @@ Item {
anchors.rightMargin: 0
font.pixelSize: 15
font.strikeout: false
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance, root.locale)
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance)
}
}

View File

@ -16,11 +16,12 @@ Item {
property string selectedTokenSymbol
property string currentCurrency
property string currentCurrencySymbol
property var bestRoutes: []
property var getGasEthValue: function () {}
property var getFiatValue: function () {}
property var getCurrencyAmount: function () {}
property var locale
width: parent.width
height: visible ? advancedGasSelector.height + Style.current.halfPadding : 0
@ -48,19 +49,20 @@ Item {
statusListItemIcon.active: true
statusListItemIcon.opacity: modelData.isFirstSimpleTx
title: qsTr("%1 transaction fee").arg(modelData.fromNetwork.chainName)
subTitle: "%1 eth".arg(LocaleUtils.numberToLocaleString(parseFloat(totalGasAmount)))
property string totalGasAmount : {
subTitle: LocaleUtils.currencyAmountToLocaleString(totalGasAmountEth)
property var totalGasAmountEth: {
let maxFees = modelData.gasFees.maxFeePerGasM
let gasPrice = modelData.gasFees.eip1559Enabled ? maxFees : modelData.gasFees.gasPrice
return root.getGasEthValue(gasPrice , modelData.gasAmount)
}
property var totalGasAmountFiat: root.getFiatValue(totalGasAmountEth.amount, "ETH", root.currentCurrency)
statusListItemSubTitle.width: listItem.width/2 - Style.current.smallPadding
statusListItemSubTitle.elide: Text.ElideMiddle
statusListItemSubTitle.wrapMode: Text.NoWrap
components: [
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: "%1%2".arg(currentCurrencySymbol).arg(LocaleUtils.numberToLocaleString(parseFloat(root.getFiatValue(totalGasAmount, "ETH", root.currentCurrency))))
text: LocaleUtils.currencyAmountToLocaleString(totalGasAmountFiat)
font.pixelSize: 15
color: Theme.palette.baseColor1
width: listItem.width/2 - Style.current.padding
@ -82,7 +84,9 @@ Item {
statusListItemIcon.active: true
statusListItemIcon.opacity: modelData.isFirstSimpleTx
title: qsTr("Approve %1 %2 Bridge").arg(modelData.fromNetwork.chainName).arg(root.selectedTokenSymbol)
subTitle: "%1 eth".arg(LocaleUtils.numberToLocaleString(modelData.approvalGasFees))
property var approvalGasFees: root.getCurrencyAmount(modelData.approvalGasFees, "ETH")
property var approvalGasFeesFiat: root.getFiatValue(approvalGasFees.amount, "ETH", root.currentCurrency)
subTitle: LocaleUtils.currencyAmountToLocaleString(approvalGasFees)
statusListItemSubTitle.width: listItem.width/2 - Style.current.smallPadding
statusListItemSubTitle.elide: Text.ElideMiddle
statusListItemSubTitle.wrapMode: Text.NoWrap
@ -90,7 +94,7 @@ Item {
components: [
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: "%1%2".arg(currentCurrencySymbol).arg(LocaleUtils.numberToLocaleString(parseFloat(root.getFiatValue(modelData.approvalGasFees, "ETH", root.currentCurrency))))
text: LocaleUtils.currencyAmountToLocaleString(approvalGasFeesFiat)
font.pixelSize: 15
color: Theme.palette.baseColor1
width: listItem.width/2 - Style.current.padding
@ -113,14 +117,16 @@ Item {
statusListItemIcon.active: true
statusListItemIcon.opacity: modelData.isFirstBridgeTx
title: qsTr("%1 -> %2 bridge").arg(modelData.fromNetwork.chainName).arg(modelData.toNetwork.chainName)
subTitle: "%1 %2".arg(LocaleUtils.numberToLocaleString(modelData.tokenFees)).arg(root.selectedTokenSymbol)
property var tokenFees: root.getCurrencyAmount(modelData.tokenFees, root.selectedTokenSymbol)
property var tokenFeesFiat: root.getFiatValue(tokenFees.amount, root.selectedTokenSymbol, root.currentCurrency)
subTitle: LocaleUtils.currencyAmountToLocaleString(tokenFees)
visible: modelData.bridgeName !== "Simple"
statusListItemSubTitle.width: 100
statusListItemSubTitle.elide: Text.ElideMiddle
components: [
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: "%1%2".arg(currentCurrencySymbol).arg(LocaleUtils.numberToLocaleString(parseFloat(root.getFiatValue(modelData.tokenFees, root.selectedTokenSymbol, root.currentCurrency))))
text: LocaleUtils.currencyAmountToLocaleString(tokenFeesFiat)
font.pixelSize: 15
color: Theme.palette.baseColor1
width: listItem2.width/2 - Style.current.padding

View File

@ -16,7 +16,7 @@ StatusListItem {
signal tokenSelected(var selectedToken)
title: name
label: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance, root.locale)
label: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance)
asset.name: symbol ? Style.png("tokens/" + symbol) : ""
asset.isImage: true
asset.width: 32
@ -42,7 +42,7 @@ StatusListItem {
id: expandedItem
StatusListItemTag {
height: 16
title: LocaleUtils.currencyAmountToLocaleString(balance, root.locale)
title: LocaleUtils.currencyAmountToLocaleString(balance)
titleText.font.pixelSize: 12
closeButtonVisible: false
bgColor: "transparent"

View File

@ -12,7 +12,7 @@ StatusListItem {
id: root
property var locale
title: name
subTitle: LocaleUtils.currencyAmountToLocaleString(enabledNetworkBalance, root.locale)
subTitle: LocaleUtils.currencyAmountToLocaleString(enabledNetworkBalance)
asset.name: symbol ? Style.png("tokens/" + symbol) : ""
asset.isImage: true
components: [
@ -25,7 +25,7 @@ StatusListItem {
anchors.right: parent.right
font.pixelSize: 15
font.strikeout: false
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance, root.locale)
text: LocaleUtils.currencyAmountToLocaleString(enabledNetworkCurrencyBalance)
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
@ -35,7 +35,7 @@ StatusListItem {
font.pixelSize: 15
font.strikeout: false
color: valueColumn.textColor
text: LocaleUtils.currencyAmountToLocaleString(currencyPrice, root.locale)
text: LocaleUtils.currencyAmountToLocaleString(currencyPrice)
}
Rectangle {
width: 1

View File

@ -11,13 +11,13 @@ import shared 1.0
StatusListItem {
id: root
property var locale
property var modelData
property string symbol
property bool isIncoming
property int transferStatus
property string currentCurrency
property string cryptoValue
property string fiatValue
property var cryptoValue
property var fiatValue
property string networkIcon
property string networkColor
property string networkName
@ -62,13 +62,13 @@ StatusListItem {
}
StatusBaseText {
id: cryptoValueText
text: "%1 %2".arg(cryptoValue).arg(resolvedSymbol)
text: LocaleUtils.currencyAmountToLocaleString(cryptoValue)
color: Theme.palette.directColor1
}
}
StatusBaseText {
Layout.alignment: Qt.AlignRight
text: "%1 %2".arg(fiatValue).arg(currentCurrency.toUpperCase())
text: LocaleUtils.currencyAmountToLocaleString(fiatValue)
font.pixelSize: 15
color: Theme.palette.baseColor1
}

View File

@ -89,7 +89,7 @@ StatusFloatingButtonsSelector {
popupMenuDelegate: StatusListItem {
implicitWidth: 272
title: name
subTitle: LocaleUtils.currencyAmountToLocaleString(currencyBalance, locale)
subTitle: LocaleUtils.currencyAmountToLocaleString(currencyBalance)
asset.emoji: !!emoji ? emoji: ""
asset.color: model.color
asset.name: !emoji ? "filled-account": ""

View File

@ -33,6 +33,7 @@ StatusDialog {
property var store: TransactionStore{}
property var contactsStore: store.contactStore
property var currencyStore: store.currencyStore
property var selectedAccount: store.currentAccount
property var bestRoutes
property string addressText
@ -60,7 +61,7 @@ StatusDialog {
popup.selectedAccount.address,
recipientAddress,
assetSelector.selectedAsset.symbol,
amountToSendInput.cryptoValueToSend,
amountToSendInput.cryptoValueToSend.amount,
d.uuid,
JSON.stringify(popup.bestRoutes)
)
@ -69,7 +70,7 @@ StatusDialog {
property var recalculateRoutesAndFees: Backpressure.debounce(popup, 600, function() {
if(!!popup.selectedAccount && !!assetSelector.selectedAsset && d.recipientReady && amountToSendInput.input.valid) {
popup.isLoading = true
let amount = Math.round(parseFloat(amountToSendInput.cryptoValueToSend) * Math.pow(10, assetSelector.selectedAsset.decimals))
let amount = Math.round(amountToSendInput.cryptoValueToSend.amount * Math.pow(10, assetSelector.selectedAsset.decimals))
popup.store.suggestedRoutes(popup.selectedAccount.address, amount.toString(16), assetSelector.selectedAsset.symbol,
store.disabledChainIdsFromList, store.disabledChainIdsToList,
store.preferredChainIds, popup.sendType, store.lockedInAmounts)
@ -81,7 +82,7 @@ StatusDialog {
readonly property int errorType: !amountToSendInput.input.valid ? Constants.SendAmountExceedsBalance :
(networkSelector.bestRoutes && networkSelector.bestRoutes.length <= 0 && !!amountToSendInput.input.text && recipientReady && !popup.isLoading) ?
Constants.NoRoute : Constants.NoError
readonly property var maxFiatBalance: !!assetSelector.selectedAsset ? (amountToSendInput.cryptoFiatFlipped ?
readonly property var maxFiatBalance: !!assetSelector.selectedAsset ? (amountToSendInput.inputIsFiat ?
assetSelector.selectedAsset.totalCurrencyBalance :
assetSelector.selectedAsset.totalBalance): undefined
readonly property bool errorMode: popup.isLoading || !recipientReady ? false : errorType !== Constants.NoError || networkSelector.errorMode || isNaN(amountToSendInput.input.text)
@ -95,9 +96,9 @@ StatusDialog {
readonly property string uuid: Utils.uuid()
property bool isPendingTx: false
property string totalTimeEstimate
property string totalFeesInEth
property string totalFeesInFiat
property double totalAmountToReceive: 0
property var totalFeesInEth
property var totalFeesInFiat
property var totalAmountToReceive
property Timer waitTimer: Timer {
interval: 1500
@ -156,6 +157,7 @@ StatusDialog {
header: AccountsModalHeader {
anchors.top: parent.top
anchors.topMargin: -height - 18
locale: popup.store.locale
model: popup.store.accounts
selectedAccount: popup.selectedAccount
changeSelectedAccount: function(newAccount, newIndex) {
@ -244,7 +246,7 @@ StatusDialog {
StatusListItemTag {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.preferredHeight: 22
title: d.maxFiatBalance && d.maxFiatBalance.amount > 0 ? qsTr("Max: %1").arg(LocaleUtils.currencyAmountToLocaleString(d.maxFiatBalance, popup.store.locale)) : qsTr("No balances active")
title: d.maxFiatBalance && d.maxFiatBalance.amount > 0 ? qsTr("Max: %1").arg(LocaleUtils.currencyAmountToLocaleString(d.maxFiatBalance)) : qsTr("No balances active")
closeButtonVisible: false
titleText.font.pixelSize: 12
bgColor: amountToSendInput.input.valid ? Theme.palette.primaryColor3 : Theme.palette.dangerColor2
@ -263,10 +265,16 @@ StatusDialog {
maxFiatBalance: d.maxFiatBalance
currentCurrency: popup.store.currentCurrency
getFiatValue: function(cryptoValue) {
return popup.store.getFiatValue(cryptoValue, selectedAsset.symbol, currentCurrency)
return selectedAsset ? popup.currencyStore.getFiatValue(cryptoValue, selectedAsset.symbol, currentCurrency) : undefined
}
getCryptoValue: function(fiatValue) {
return popup.store.getFiatValue(fiatValue, selectedAsset.symbol, currentCurrency)
return selectedAsset ? popup.currencyStore.getCryptoValue(fiatValue, selectedAsset.symbol, currentCurrency) : undefined
}
getFiatCurrencyAmount: function(fiatValue) {
return popup.currencyStore.getCurrencyAmount(fiatValue, currentCurrency)
}
getCryptoCurrencyAmount: function(cryptoValue) {
return selectedAsset ? popup.currencyStore.getCurrencyAmount(cryptoValue, selectedAsset.symbol) : undefined
}
onReCalculateSuggestedRoute: popup.recalculateRoutesAndFees()
}
@ -280,8 +288,12 @@ StatusDialog {
isLoading: popup.isLoading
selectedAsset: assetSelector.selectedAsset
isBridgeTx: popup.isBridgeTx
amountToReceive: d.totalAmountToReceive
cryptoFiatFlipped: amountToSendInput.cryptoFiatFlipped
cryptoValueToReceive: d.totalAmountToReceive
inputIsFiat: amountToSendInput.inputIsFiat
currentCurrency: popup.store.currentCurrency
getFiatValue: function(cryptoValue) {
return popup.currencyStore.getFiatValue(cryptoValue, selectedAsset.symbol, currentCurrency)
}
}
}
TokenListView {
@ -416,8 +428,8 @@ StatusDialog {
store: popup.store
interactive: popup.interactive
selectedAccount: popup.selectedAccount
amountToSend: isNaN(parseFloat(amountToSendInput.cryptoValueToSend)) ? 0 : parseFloat(amountToSendInput.cryptoValueToSend)
requiredGasInEth:d.totalFeesInEth
amountToSend: amountToSendInput.cryptoValueToSend
requiredGasInEth: d.totalFeesInEth
selectedAsset: assetSelector.selectedAsset
onReCalculateSuggestedRoute: popup.recalculateRoutesAndFees()
visible: d.recipientReady && !!assetSelector.selectedAsset
@ -449,10 +461,10 @@ StatusDialog {
footer: SendModalFooter {
nextButtonText: popup.isBridgeTx ? qsTr("Bridge") : qsTr("Send")
maxFiatFees: popup.isLoading ? "..." : "%1 %2".arg(LocaleUtils.numberToLocaleString(d.totalFeesInFiat, -1, popup.store.locale)).arg(popup.store.currentCurrency.toUpperCase())
maxFiatFees: popup.isLoading ? "..." : LocaleUtils.currencyAmountToLocaleString(d.totalFeesInFiat)
totalTimeEstimate: popup.isLoading? "..." : d.totalTimeEstimate
pending: d.isPendingTx || popup.isLoading
visible: d.recipientReady && !isNaN(amountToSendInput.cryptoValueToSend) && !d.errorMode
visible: d.recipientReady && amountToSendInput.cryptoValueToSend.amount > 0 && !d.errorMode
onNextButtonClicked: popup.sendTransaction()
}
@ -472,10 +484,11 @@ StatusDialog {
popup.bestRoutes = response.suggestedRoutes.best
let gasTimeEstimate = response.suggestedRoutes.gasTimeEstimate
d.totalTimeEstimate = popup.store.getLabelForEstimatedTxTime(gasTimeEstimate.totalTime)
d.totalFeesInEth = gasTimeEstimate.totalFeesInEth
d.totalFeesInFiat = parseFloat(popup.store.getFiatValue( gasTimeEstimate.totalFeesInEth, "ETH", popup.store.currentCurrency)) +
parseFloat(popup.store.getFiatValue(gasTimeEstimate.totalTokenFees, fees.selectedTokenSymbol, popup.store.currentCurrency))
d.totalAmountToReceive = popup.store.getWei2Eth(response.suggestedRoutes.amountToReceive, assetSelector.selectedAsset.decimals)
d.totalFeesInEth = popup.currencyStore.getCurrencyAmount(gasTimeEstimate.totalFeesInEth, "ETH")
let totalFeesInFiat = popup.currencyStore.getFiatValue( gasTimeEstimate.totalFeesInEth, "ETH", popup.store.currentCurrency).amount +
popup.currencyStore.getFiatValue(gasTimeEstimate.totalTokenFees, fees.selectedTokenSymbol, popup.store.currentCurrency).amount
d.totalFeesInFiat = popup.currencyStore.getCurrencyAmount(totalFeesInFiat, popup.store.currentCurrency)
d.totalAmountToReceive = popup.currencyStore.getCurrencyAmount(popup.store.getWei2Eth(response.suggestedRoutes.amountToReceive, assetSelector.selectedAsset.decimals), fees.selectedTokenSymbol)
networkSelector.toNetworksList = response.suggestedRoutes.toNetworks
popup.isLoading = false
}

View File

@ -1,11 +1,16 @@
import QtQuick 2.13
import utils 1.0
import "../../../app/AppLayouts/Profile/stores"
QtObject {
id: root
property var locale: Qt.locale(localAppSettings.language)
// Some token+currency-related functions are implemented in the profileSectionModule.
// We should probably refactor this and move those functions to some Wallet module.
property ProfileSectionStore profileSectionStore: ProfileSectionStore {}
property string currentCurrency: walletSection.currentCurrency
property int currentCurrencyModelIndex: {
for (var i=0; i<currenciesModel.count; i++) {
@ -952,4 +957,32 @@ QtObject {
function updateCurrency(newCurrency) {
walletSection.updateCurrency(newCurrency)
}
function getCurrencyAmount(amount, symbol) {
let obj = JSON.parse((walletSection.getCurrencyAmountAsJson(amount, symbol)))
if (obj.error) {
console.error("Error parsing currency amount json object, amount: ", amount, ", symbol ", symbol, " error: ", obj.error)
return {amount: nan, symbol: symbol}
}
return obj
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
var amount = profileSectionModule.ensUsernamesModule.getFiatValue(balance, cryptoSymbol, fiatSymbol)
return getCurrencyAmount(parseFloat(amount), fiatSymbol)
}
function getCryptoValue(balance, cryptoSymbol, fiatSymbol) {
var amount = profileSectionModule.ensUsernamesModule.getCryptoValue(balance, cryptoSymbol, fiatSymbol)
return getCurrencyAmount(parseFloat(amount), cryptoSymbol)
}
function getGasEthValue(gweiValue, gasLimit) {
var amount = profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
return getCurrencyAmount(parseFloat(amount), "ETH")
}
function formatCurrencyAmount(currencyAmount) {
return LocaleUtils.currencyAmountToLocaleString(currencyAmount)
}
}

View File

@ -63,10 +63,6 @@ QtObject {
return networksModule.all.getNetworkName(symbol)
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
return profileSectionModule.ensUsernamesModule.getFiatValue(balance, cryptoSymbol, fiatSymbol)
}
function hex2Dec(value) {
return globalUtils.hex2Dec(value)
}
@ -207,8 +203,24 @@ QtObject {
return walletSectionTransactions.getLastTxBlockNumber()
}
function getCurrencyAmount(amount, symbol) {
return currencyStore.getCurrencyAmount(amount, symbol)
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
return currencyStore.getFiatValue(balance, cryptoSymbol, fiatSymbol)
}
function getCryptoValue(balance, cryptoSymbol, fiatSymbol) {
return currencyStore.getCryptoValue(balance, cryptoSymbol, fiatSymbol)
}
function getGasEthValue(gweiValue, gasLimit) {
return profileSectionModule.ensUsernamesModule.getGasEthValue(gweiValue, gasLimit)
return currencyStore.getGasEthValue(gweiValue, gasLimit)
}
function formatCurrencyAmount(currencyAmount) {
return currencyStore.formatCurrencyAmount(currencyAmount)
}
function getHistoricalDataForToken(symbol, currency) {

View File

@ -61,18 +61,6 @@ QtObject {
globalUtils.copyToClipboard(text)
}
function getFiatValue(balance, cryptoSymbol, fiatSymbol) {
return profileSectionStore.ensUsernamesStore.getFiatValue(balance, cryptoSymbol, fiatSymbol)
}
function getCryptoValue(balance, cryptoSymbol, fiatSymbol) {
return profileSectionStore.ensUsernamesStore.getCryptoValue(balance, cryptoSymbol, fiatSymbol)
}
function getGasEthValue(gweiValue, gasLimit) {
return profileSectionStore.ensUsernamesStore.getGasEthValue(gweiValue, gasLimit)
}
function authenticateAndTransfer(from, to, tokenSymbol, amount, uuid, selectedRoutes) {
walletSectionTransactions.authenticateAndTransfer(from, to, tokenSymbol, amount, uuid, selectedRoutes)
}
@ -233,7 +221,7 @@ QtObject {
property var lockedInAmounts: []
function addLockedInAmount(chainID, value, decimals, locked) {
let amount = Number.fromLocaleString(Qt.locale(), value) * Math.pow(10, decimals)
let amount = value * Math.pow(10, decimals)
let index = lockedInAmounts.findIndex(lockedItem => lockedItem !== undefined && lockedItem.chainID === chainID)
if(index === -1) {
lockedInAmounts.push({"chainID": chainID, "value": amount.toString(16)})
@ -253,18 +241,6 @@ QtObject {
return undefined
}
const jsonObj = selectedAccount.getTokenBalanceOnChainAsJson(chainId, tokenSymbol)
if (jsonObj === "") {
console.warn("failed to get balance, returned json is empty")
return undefined
}
const obj = JSON.parse(jsonObj)
if (obj.error) {
console.warn("failed to get balance, json parse error: ", obj.error)
return undefined
}
return obj
return JSON.parse(selectedAccount.getTokenBalanceOnChainAsJson(chainId, tokenSymbol))
}
}

View File

@ -5,6 +5,7 @@ import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
import shared.stores 1.0
ColumnLayout {
id: root
@ -13,21 +14,24 @@ ColumnLayout {
property var store
property var selectedAsset
property bool isLoading: false
property string amountToReceive
property var cryptoValueToReceive
property bool isBridgeTx: false
property bool cryptoFiatFlipped: false
property bool inputIsFiat: false
property string currentCurrency
property var getFiatValue: function(cryptoValue) {}
QtObject {
id: d
function formatValue(value) {
const precision = (value === 0 ? 2 : 0)
return LocaleUtils.numberToLocaleString(value, precision, root.locale)
}
readonly property string fiatValue: {
if(!root.selectedAsset || !amountToReceive)
return formatValue(0)
let cryptoValue = root.store.getFiatValue(amountToReceive, root.selectedAsset.symbol, root.store.currentCurrency)
return formatValue(parseFloat(cryptoValue))
if(!root.selectedAsset || !cryptoValueToReceive)
return LocaleUtils.numberToLocaleString(0, 2)
let fiatValue = root.getFiatValue(cryptoValueToReceive.amount, root.selectedAsset.symbol, RootStore.currentCurrency)
return LocaleUtils.currencyAmountToLocaleString(fiatValue)
}
readonly property string cryptoValue: {
if(!root.selectedAsset || !cryptoValueToReceive)
return LocaleUtils.numberToLocaleString(0, 2)
return LocaleUtils.currencyAmountToLocaleString(cryptoValueToReceive)
}
}
@ -45,31 +49,17 @@ ColumnLayout {
StatusBaseText {
id: amountToReceiveText
Layout.alignment: Qt.AlignVCenter
text: isLoading ? "..." : cryptoFiatFlipped ? d.fiatValue: amountToReceive
text: isLoading ? "..." : inputIsFiat ? d.fiatValue : d.cryptoValue
font.pixelSize: Utils.getFontSizeBasedOnLetterCount(text)
color: Theme.palette.directColor1
}
StatusBaseText {
Layout.alignment: Qt.AlignVCenter
text: isLoading ? "..." : root.store.currentCurrency.toUpperCase()
font.pixelSize: amountToReceiveText.font.pixelSize
color: Theme.palette.directColor1
visible: cryptoFiatFlipped
}
}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
StatusBaseText {
id: txtFiatBalance
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
text: isLoading ? "..." : cryptoFiatFlipped ? amountToReceive : d.fiatValue
font.pixelSize: 13
color: Theme.palette.directColor5
}
StatusBaseText {
Layout.alignment: Qt.AlignTop
Layout.leftMargin: 4
text: isLoading ? "..." : !cryptoFiatFlipped ? root.store.currentCurrency.toUpperCase() : !!root.selectedAsset ? root.selectedAsset.symbol.toUpperCase() : ""
text: isLoading ? "..." : inputIsFiat ? d.cryptoValue : d.fiatValue
font.pixelSize: 13
color: Theme.palette.directColor5
}

View File

@ -12,54 +12,54 @@ import utils 1.0
ColumnLayout {
id: root
property alias input: amountToSendInput
property alias input: topAmountToSendInput
property var locale
property var selectedAsset
property bool isBridgeTx: false
property bool interactive: false
property var maxFiatBalance
property bool cryptoFiatFlipped: false
property string cryptoValueToSend: !cryptoFiatFlipped ? amountToSendInput.text : txtFiatBalance.text
property bool inputIsFiat: false
property var cryptoValueToSend
Binding {
target: root
property: "cryptoValueToSend"
value: root.selectedAsset, !inputIsFiat ? getCryptoCurrencyAmount(LocaleUtils.numberFromLocaleString(topAmountToSendInput.text)) : getCryptoValue(fiatValueToSend ? fiatValueToSend.amount : 0.0)
delayed: true
}
property var fiatValueToSend
Binding {
target: root
property: "fiatValueToSend"
value: root.selectedAsset, inputIsFiat ? getFiatCurrencyAmount(LocaleUtils.numberFromLocaleString(topAmountToSendInput.text)) : getFiatValue(cryptoValueToSend ? cryptoValueToSend.amount : 0.0)
delayed: true
}
property string currentCurrency
property var getFiatValue: function(cryptoValue) {}
property var getCryptoValue: function(fiatValue) {}
property var getFiatCurrencyAmount: function(fiatValue) {}
property var getCryptoCurrencyAmount: function(cryptoValue) {}
signal reCalculateSuggestedRoute()
QtObject {
id: d
readonly property string zeroString: formatValue(0, 2)
readonly property string zeroString: LocaleUtils.numberToLocaleString(0, 2)
property Timer waitTimer: Timer {
interval: 1000
onTriggered: reCalculateSuggestedRoute()
}
function formatValue(value, precision) {
const precisionVal = !!precision ? precision : (value === 0 ? 2 : 0)
return LocaleUtils.numberToLocaleString(value, precisionVal, root.locale)
}
function getFiatValue(value) {
if(!root.selectedAsset || !value)
return zeroString
let cryptoValue = root.getFiatValue(value)
return formatValue(parseFloat(cryptoValue))
}
function getCryptoValue(value) {
if(!root.selectedAsset || !value)
return zeroString
let cryptoValue = root.getCryptoValue(value)
return formatValue(parseFloat(cryptoValue))
}
}
onSelectedAssetChanged: {
if(!!root.selectedAsset) {
txtFiatBalance.text = !cryptoFiatFlipped ? d.getFiatValue(amountToSendInput.text): d.getCryptoValue(amountToSendInput.text)
function formatValue(value) {
if (!value) {
return zeroString
}
return LocaleUtils.currencyAmountToLocaleString(value)
}
}
onMaxFiatBalanceChanged: {
floatValidator.top = maxFiatBalance.amount
floatValidator.top = maxFiatBalance ? maxFiatBalance.amount : 0.0
input.validate()
}
@ -72,9 +72,11 @@ ColumnLayout {
color: Theme.palette.directColor1
}
RowLayout {
id: topItem
property var topAmountToSend: !inputIsFiat ? cryptoValueToSend : fiatValueToSend
Layout.alignment: Qt.AlignLeft
AmountInputWithCursor {
id: amountToSendInput
id: topAmountToSendInput
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.maximumWidth: 163
Layout.preferredWidth: (!!text) ? input.edit.paintedWidth : textMetrics.advanceWidth
@ -91,45 +93,29 @@ ColumnLayout {
]
TextMetrics {
id: textMetrics
text: amountToSendInput.placeholderText
font: amountToSendInput.input.placeholder.font
text: topAmountToSendInput.placeholderText
font: topAmountToSendInput.input.placeholder.font
}
Keys.onReleased: {
const amount = amountToSendInput.text.trim()
const amount = topAmountToSendInput.text.trim()
if (!Utils.containsOnlyDigits(amount) || isNaN(amount)) {
return
}
txtFiatBalance.text = !cryptoFiatFlipped ? d.getFiatValue(amount): d.getCryptoValue(amount)
d.waitTimer.restart()
}
}
StatusBaseText {
Layout.alignment: Qt.AlignVCenter
text: root.currentCurrency.toUpperCase()
font.pixelSize: amountToSendInput.input.edit.font.pixelSize
color: Theme.palette.baseColor1
visible: cryptoFiatFlipped
}
}
Item {
id: fiatBalanceLayout
id: bottomItem
property var bottomAmountToSend: inputIsFiat ? cryptoValueToSend : fiatValueToSend
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
Layout.preferredWidth: txtFiatBalance.width + currencyText.width
Layout.preferredHeight: txtFiatBalance.height
Layout.preferredWidth: txtBottom.width
Layout.preferredHeight: txtBottom.height
StatusBaseText {
id: txtFiatBalance
id: txtBottom
anchors.top: parent.top
anchors.left: parent.left
text: d.getFiatValue(amountToSendInput.text)
font.pixelSize: 13
color: Theme.palette.directColor5
}
StatusBaseText {
id: currencyText
anchors.top: parent.top
anchors.left: txtFiatBalance.right
anchors.leftMargin: 4
text: !cryptoFiatFlipped ? root.currentCurrency.toUpperCase() : !!root.selectedAsset ? root.selectedAsset.symbol.toUpperCase() : ""
text: d.formatValue(bottomItem.bottomAmountToSend)
font.pixelSize: 13
color: Theme.palette.directColor5
}
@ -137,13 +123,12 @@ ColumnLayout {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
cryptoFiatFlipped = !cryptoFiatFlipped
amountToSendInput.validate()
if(!!amountToSendInput.text) {
const tempVal = Number.fromLocaleString(txtFiatBalance.text)
txtFiatBalance.text = !!amountToSendInput.text ? amountToSendInput.text : d.zeroString
amountToSendInput.text = tempVal
topAmountToSendInput.validate()
if(!!topAmountToSendInput.text) {
topAmountToSendInput.text = LocaleUtils.currencyAmountToLocaleString(bottomItem.bottomAmountToSend, {onlyAmount: true})
}
inputIsFiat = !inputIsFiat
d.waitTimer.restart()
}
}
}

View File

@ -58,8 +58,8 @@ Item {
asset.name: token && token.symbol ? Style.png("tokens/%1".arg(token.symbol)) : ""
asset.isImage: true
primaryText: token ? token.name : ""
secondaryText: token ? LocaleUtils.currencyAmountToLocaleString(token.enabledNetworkBalance, RootStore.locale) : ""
tertiaryText: token ? LocaleUtils.currencyAmountToLocaleString(token.enabledNetworkCurrencyBalance, RootStore.locale) : ""
secondaryText: token ? LocaleUtils.currencyAmountToLocaleString(token.enabledNetworkBalance) : ""
tertiaryText: token ? LocaleUtils.currencyAmountToLocaleString(token.enabledNetworkCurrencyBalance) : ""
balances: token && token.balances ? token.balances : null
getNetworkColor: function(chainId){
return RootStore.getNetworkColor(chainId)
@ -68,7 +68,7 @@ Item {
return RootStore.getNetworkIcon(chainId)
}
formatBalance: function(balance){
return LocaleUtils.currencyAmountToLocaleString(balance, RootStore.locale)
return LocaleUtils.currencyAmountToLocaleString(balance)
}
}
@ -228,7 +228,7 @@ Item {
fontColor: (Theme.palette.name === "dark") ? '#909090' : '#939BA1',
padding: 8,
callback: function(value, index, ticks) {
return LocaleUtils.numberToLocaleString(value, -1, RootStore.locale)
return LocaleUtils.numberToLocaleString(value)
},
}
}]
@ -267,17 +267,17 @@ Item {
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Market Cap")
secondaryText: token && token.marketCap ? LocaleUtils.currencyAmountToLocaleString(token.marketCap, RootStore.locale) : "---"
secondaryText: token && token.marketCap ? LocaleUtils.currencyAmountToLocaleString(token.marketCap) : "---"
}
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Day Low")
secondaryText: token && token.lowDay ? LocaleUtils.currencyAmountToLocaleString(token.lowDay, RootStore.locale) : "---"
secondaryText: token && token.lowDay ? LocaleUtils.currencyAmountToLocaleString(token.lowDay) : "---"
}
InformationTile {
maxWidth: parent.width
primaryText: qsTr("Day High")
secondaryText: token && token.highDay ? LocaleUtils.currencyAmountToLocaleString(token.highDay, RootStore.locale) : "---"
secondaryText: token && token.highDay ? LocaleUtils.currencyAmountToLocaleString(token.highDay) : "---"
}
Item {
Layout.fillWidth: true

View File

@ -7,15 +7,18 @@ import StatusQ.Core.Theme 0.1
import utils 1.0
import shared.stores 1.0
import "../controls"
Rectangle {
id: root
property string gasFiatAmount
property var gasFiatAmount
property bool isLoading: false
property var bestRoutes
property var store
property var currencyStore: store.currencyStore
property var selectedTokenSymbol
property int errorType: Constants.NoError
@ -56,7 +59,7 @@ Rectangle {
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
id: totalFeesAdvanced
text: root.isLoading ? "..." : root.gasFiatAmount
text: root.isLoading ? "..." : LocaleUtils.currencyAmountToLocaleString(root.gasFiatAmount)
font.pixelSize: 15
color: Theme.palette.directColor1
visible: !!root.bestRoutes && root.bestRoutes !== undefined && root.bestRoutes.length > 0
@ -64,11 +67,12 @@ Rectangle {
}
GasSelector {
id: gasSelector
locale: root.store.locale
width: parent.width
getGasEthValue: root.store.getGasEthValue
getFiatValue: root.store.getFiatValue
currentCurrency: root.store.currencyStore.currentCurrency
currentCurrencySymbol: root.store.currencyStore.currentCurrencySymbol
getGasEthValue: root.currencyStore.getGasEthValue
getFiatValue: root.currencyStore.getFiatValue
getCurrencyAmount: root.currencyStore.getCurrencyAmount
currentCurrency: root.currencyStore.currentCurrency
visible: root.errorType === Constants.NoError && !root.isLoading
bestRoutes: root.bestRoutes
selectedTokenSymbol: root.selectedTokenSymbol

View File

@ -17,6 +17,7 @@ import "../controls"
ColumnLayout {
id: historyView
property var locale
property var account
property int pageSize: 20 // number of transactions per page
property bool isLoading: false
@ -113,17 +114,18 @@ ColumnLayout {
Component {
id: transactionDelegate
TransactionDelegate {
isIncoming: modelData !== undefined && !!modelData ? modelData.to === account.address: false
currentCurrency: RootStore.currentCurrency
cryptoValue: modelData !== undefined && !!modelData ? RootStore.hex2Eth(modelData.value) : ""
locale: historyView.locale
property bool modelDataValid: modelData !== undefined && !!modelData
isIncoming: modelDataValid ? modelData.to === account.address: false
cryptoValue: modelDataValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(modelData.value), resolvedSymbol) : ""
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
networkIcon: modelData !== undefined && !!modelData ? RootStore.getNetworkIcon(modelData.chainId) : ""
networkColor: modelData !== undefined && !!modelData ? RootStore.getNetworkColor(modelData.chainId) : ""
networkName: modelData !== undefined && !!modelData ? RootStore.getNetworkShortName(modelData.chainId) : ""
symbol: modelData !== undefined && !!modelData ? !!modelData.symbol ? modelData.symbol : RootStore.findTokenSymbolByAddress(modelData.contract) : ""
transferStatus: modelData !== undefined && !!modelData ? RootStore.hex2Dec(modelData.txStatus) : ""
shortTimeStamp: modelData !== undefined && !!modelData ? LocaleUtils.formatTime(modelData.timestamp * 1000, Locale.ShortFormat) : ""
savedAddressName: modelData !== undefined && !!modelData ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
networkIcon: modelDataValid ? RootStore.getNetworkIcon(modelData.chainId) : ""
networkColor: modelDataValid ? RootStore.getNetworkColor(modelData.chainId) : ""
networkName: modelDataValid ? RootStore.getNetworkShortName(modelData.chainId) : ""
symbol: modelDataValid ? !!modelData.symbol ? modelData.symbol : RootStore.findTokenSymbolByAddress(modelData.contract) : ""
transferStatus: modelDataValid ? RootStore.hex2Dec(modelData.txStatus) : ""
shortTimeStamp: modelDataValid ? LocaleUtils.formatTime(modelData.timestamp * 1000, Locale.ShortFormat) : ""
savedAddressName: modelDataValid ? RootStore.getNameForSavedWalletAddress(modelData.to) : ""
onClicked: launchTransactionDetail(modelData)
}
}

View File

@ -16,18 +16,20 @@ Item {
id: root
property var store
property var locale
property var bestRoutes
property var selectedAccount
property var selectedAsset
property var allNetworks
property bool customMode: false
property double amountToSend: 0
property double requiredGasInEth: 0
property bool errorMode: d.customAmountToSend > root.amountToSend
property var amountToSend
property var requiredGasInEth
property bool errorMode: !root.amountToSend || d.customAmountToSend > root.amountToSend.amount
property bool interactive: true
property bool showPreferredChains: false
property var weiToEth: function(wei) {}
property var reCalculateSuggestedRoute: function() {}
property var getCryptoCurrencyAmount: function(cryptoValue) {}
property int errorType: Constants.NoError
property bool isLoading
@ -50,7 +52,7 @@ Item {
d.customAmountToSend = 0
for(var i = 0; i<fromNetworksRepeater.count; i++) {
if(fromNetworksRepeater.itemAt(i).locked) {
let amountEntered = parseFloat(fromNetworksRepeater.itemAt(i).advancedInputText)
let amountEntered = fromNetworksRepeater.itemAt(i).advancedInputCurrencyAmount.amount
d.customAmountToSend += isNaN(amountEntered) ? 0 : amountEntered
}
}
@ -91,26 +93,28 @@ Item {
objectName: model.chainId
property double amountToSend: 0
property int routeOnNetwork: 0
property bool tokenBalanceOnChainValid: selectedAccount && selectedAccount !== undefined && selectedAsset !== undefined
property var tokenBalanceOnChain: tokenBalanceOnChainValid ? root.store.getTokenBalanceOnChain(selectedAccount, model.chainId, selectedAsset.symbol) : undefined
property var hasGas: selectedAccount.hasGas(model.chainId, model.nativeCurrencySymbol, requiredGasInEth)
property bool selectedAssetValid: selectedAccount && selectedAccount !== undefined && selectedAsset !== undefined
property var tokenBalanceOnChain: selectedAssetValid ? root.store.getTokenBalanceOnChain(selectedAccount, model.chainId, selectedAsset.symbol) : undefined
property bool hasGas: selectedAssetValid && requiredGasInEth ? selectedAccount.hasGas(model.chainId, model.nativeCurrencySymbol, requiredGasInEth.amount) : false
property var advancedInputCurrencyAmount: selectedAssetValid ? root.getCryptoCurrencyAmount(LocaleUtils.numberFromLocaleString(advancedInputText)) : undefined
primaryText: model.chainName
secondaryText: (tokenBalanceOnChain.amount === 0) && root.amountToSend !== 0 ?
qsTr("No Balance") : !hasGas ? qsTr("No Gas") : advancedInputText
tertiaryText: root.errorMode && parseFloat(advancedInputText) !== 0 && advancedInput.valid ? qsTr("EXCEEDS SEND AMOUNT"): qsTr("BALANCE: ") + LocaleUtils.currencyAmountToLocaleString(tokenBalanceOnChain, root.store.locale)
secondaryText: !tokenBalanceOnChain || (tokenBalanceOnChain.amount === 0 && root.amountToSend && root.amountToSend.amount !== 0) ?
qsTr("No Balance") : !hasGas ? qsTr("No Gas") : advancedInputCurrencyAmount ? LocaleUtils.currencyAmountToLocaleString(advancedInputCurrencyAmount) : "N/A"
tertiaryText: root.errorMode && advancedInputCurrencyAmount && advancedInputCurrencyAmount.amount !== 0 && advancedInput.valid ? qsTr("EXCEEDS SEND AMOUNT"): qsTr("BALANCE: ") + LocaleUtils.currencyAmountToLocaleString(tokenBalanceOnChain)
locked: store.lockedInAmounts.findIndex(lockedItem => lockedItem !== undefined && lockedItem.chainID === model.chainId) !== -1
preCalculatedAdvancedText: {
let index = store.lockedInAmounts.findIndex(lockedItem => lockedItem!== undefined && lockedItem.chainID === model.chainId)
if(locked && index !== -1) {
return root.weiToEth(parseInt(store.lockedInAmounts[index].value, 16))
let amount = root.weiToEth(parseInt(store.lockedInAmounts[index].value, 16))
return LocaleUtils.numberToLocaleString(amount.amount)
}
else return LocaleUtils.numberToLocaleString(fromNetwork.amountToSend)
}
maxAdvancedValue: tokenBalanceOnChain.amount
state: tokenBalanceOnChain.amount === 0 || !hasGas ?
maxAdvancedValue: tokenBalanceOnChain ? tokenBalanceOnChain.amount : 0.0
state: !tokenBalanceOnChain || tokenBalanceOnChain.amount === 0 || !hasGas ?
"unavailable" :
(root.errorMode || !advancedInput.valid) && (parseFloat(advancedInputText) !== 0) ? "error" : "default"
(root.errorMode || !advancedInput.valid) && (advancedInputCurrencyAmount.amount !== 0) ? "error" : "default"
cardIcon.source: Style.svg(model.iconUrl)
disabledText: qsTr("Disabled")
disableText: qsTr("Disable")
@ -130,9 +134,9 @@ Item {
}
onCardLocked: {
store.addLockedInAmount(model.chainId, advancedInputText, root.selectedAsset.decimals, isLocked)
store.addLockedInAmount(model.chainId, advancedInputCurrencyAmount.amount, root.selectedAsset.decimals, isLocked)
d.calculateCustomAmounts()
if(!locked || (d.customAmountToSend <= root.amountToSend && advancedInput.valid))
if(!locked || (d.customAmountToSend <= root.amountToSend.amount && advancedInput.valid))
root.reCalculateSuggestedRoute()
}
}
@ -141,7 +145,7 @@ Item {
BalanceExceeded {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
amountToSend: root.amountToSend
amountToSend: root.amountToSend ? root.amountToSend.amount : 0.0
isLoading: root.isLoading
errorType: root.errorType
}
@ -166,9 +170,10 @@ Item {
property int routeOnNetwork: 0
property int bentLine: 0
property double amountToReceive: 0
property var currencyAmountToReceive: root.getCryptoCurrencyAmount(amountToReceive)
property bool preferred: store.preferredChainIds.includes(model.chainId)
primaryText: model.chainName
secondaryText: LocaleUtils.numberToLocaleString(amountToReceive)
secondaryText: LocaleUtils.currencyAmountToLocaleString(currencyAmountToReceive)
tertiaryText: state === "unpreferred" ? qsTr("UNPREFERRED") : ""
state: !preferred ? "unpreferred" : "default"
opacity: preferred || showPreferredChains ? 1 : 0
@ -252,8 +257,8 @@ Item {
xOffset = (fromN.y - toN.y > 0 ? -1 : 1) * toN.bentLine * 16
let amountToSend = weiToEth(bestRoutes[i].amountIn)
let amountToReceive = weiToEth(bestRoutes[i].amountOut)
fromN.amountToSend = amountToSend
toN.amountToReceive += amountToReceive
fromN.amountToSend = amountToSend.amount
toN.amountToReceive += amountToReceive.amount
fromN.routeOnNetwork += 1
toN.routeOnNetwork += 1
toN.bentLine = toN.objectName !== fromN.objectName

View File

@ -2,6 +2,7 @@
import QtQuick.Layouts 1.13
import utils 1.0
import shared.stores 1.0
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
@ -17,10 +18,11 @@ Item {
implicitHeight: visible ? tabBar.height + stackLayout.height + Style.current.xlPadding : 0
property var store
property var currencyStore : store.currencyStore
property var selectedAccount
property var selectedAsset
property double amountToSend: 0
property double requiredGasInEth: 0
property var amountToSend
property var requiredGasInEth
property var bestRoutes
property bool isLoading: false
property bool advancedOrCustomMode: (tabBar.currentIndex === 1) || (tabBar.currentIndex === 2)
@ -78,13 +80,14 @@ Item {
amountToSend: root.amountToSend
isLoading: root.isLoading
store: root.store
locale: root.store.locale
selectedAsset: root.selectedAsset
selectedAccount: root.selectedAccount
errorMode: root.errorMode
errorType: root.errorType
toNetworksList: root.toNetworksList
weiToEth: function(wei) {
return "%1 %2".arg(LocaleUtils.numberToLocaleString(parseFloat(store.getWei2Eth(wei, selectedAsset.decimals)))).arg(selectedAsset.symbol)
return root.currencyStore.getCurrencyAmount(parseFloat(store.getWei2Eth(wei, selectedAsset.decimals)), selectedAsset.symbol)
}
reCalculateSuggestedRoute: function() {
root.reCalculateSuggestedRoute()
@ -114,7 +117,10 @@ Item {
isBridgeTx: root.isBridgeTx
errorType: root.errorType
weiToEth: function(wei) {
return parseFloat(store.getWei2Eth(wei, selectedAsset.decimals))
return root.currencyStore.getCurrencyAmount(parseFloat(store.getWei2Eth(wei, selectedAsset.decimals)), selectedAsset.symbol)
}
getCryptoCurrencyAmount: function(cryptoValue) {
return selectedAsset ? root.currencyStore.getCurrencyAmount(parseFloat(cryptoValue), selectedAsset.symbol) : undefined
}
}
}

View File

@ -16,14 +16,15 @@ ColumnLayout {
property var store
property var selectedAccount
property double amountToSend: 0
property double requiredGasInEth: 0
property var amountToSend
property var requiredGasInEth
property bool customMode: false
property var selectedAsset
property var bestRoutes
property bool isLoading: false
property bool errorMode: networksLoader.item ? networksLoader.item.errorMode : false
property var weiToEth: function(wei) {}
property var getCryptoCurrencyAmount: function(cryptoValue) {}
property bool interactive: true
property bool isBridgeTx: false
property bool showUnpreferredNetworks: preferredToggleButton.checked
@ -81,6 +82,7 @@ ColumnLayout {
visible: active
sourceComponent: NetworkCardsComponent {
store: root.store
locale: root.store.locale
selectedAccount: root.selectedAccount
allNetworks: root.store.allNetworks
amountToSend: root.amountToSend
@ -93,6 +95,7 @@ ColumnLayout {
showPreferredChains: preferredToggleButton.checked
bestRoutes: root.bestRoutes
weiToEth: root.weiToEth
getCryptoCurrencyAmount: root.getCryptoCurrencyAmount
interactive: root.interactive
errorType: root.errorType
isLoading: root.isLoading

View File

@ -16,8 +16,9 @@ RowLayout {
id: root
property var store
property var locale
property var bestRoutes
property double amountToSend: 0
property var amountToSend
property bool isLoading: false
property bool isBridgeTx: false
property var selectedAsset
@ -79,7 +80,7 @@ RowLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Style.current.bigPadding
amountToSend: root.amountToSend
amountToSend: root.amountToSend ? root.amountToSend.amount : 0.0
isLoading: root.isLoading
errorType: root.errorType
}
@ -98,12 +99,14 @@ RowLayout {
implicitWidth: 410
title: modelData.chainName
subTitle: {
let index = store.lockedInAmounts.findIndex(lockedItem => lockedItem !== undefined && lockedItem.chainID === modelData.chainId)
let index = store.lockedInAmounts.findIndex(lockedItem => lockedItem !== undefined && lockedItem.chainID === modelData.chainId)
var amountOut
if(!root.errorMode || index === -1)
return root.weiToEth(modelData.amountOut)
amountOut = root.weiToEth(modelData.amountOut)
else {
return root.weiToEth(parseInt(store.lockedInAmounts[index].value, 16))
amountOut = root.weiToEth(parseInt(store.lockedInAmounts[index].value, 16))
}
return LocaleUtils.currencyAmountToLocaleString(amountOut)
}
statusListItemSubTitle.color: root.errorMode ? Theme.palette.dangerColor1 : Theme.palette.primaryColor1
asset.width: 32
@ -128,7 +131,7 @@ RowLayout {
title: chainName
property bool tokenBalanceOnChainValid: selectedAccount && selectedAccount !== undefined && selectedAsset !== undefined
property var tokenBalanceOnChain: tokenBalanceOnChainValid ? root.store.getTokenBalanceOnChain(selectedAccount, chainId, selectedAsset.symbol) : undefined
subTitle: tokenBalanceOnChain ? LocaleUtils.currencyAmountToLocaleString(tokenBalanceOnChain, root.store.locale) : "N/A"
subTitle: tokenBalanceOnChain ? LocaleUtils.currencyAmountToLocaleString(tokenBalanceOnChain) : "N/A"
statusListItemSubTitle.color: Theme.palette.primaryColor1
asset.width: 32
asset.height: 32

View File

@ -153,7 +153,7 @@ Item {
objectName: model.name
height: visible ? 64 : 0
title: !!model.name ? model.name : ""
subTitle: LocaleUtils.currencyAmountToLocaleString(model.currencyBalance, root.locale)
subTitle: LocaleUtils.currencyAmountToLocaleString(model.currencyBalance)
asset.emoji: !!model.emoji ? model.emoji: ""
asset.color: model.color
asset.name: !model.emoji ? "filled-account": ""

View File

@ -18,6 +18,7 @@ import "../controls"
Item {
id: root
property var locale
property var currentAccount: RootStore.currentAccount
property var contactsStore
property var transaction
@ -57,18 +58,19 @@ Item {
objectName: "transactionDetailHeader"
width: parent.width
locale: root.locale
modelData: transaction
isIncoming: d.isIncoming
currentCurrency: RootStore.currentCurrency
cryptoValue: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Eth(transaction.value): ""
fiatValue: root.transaction !== undefined && !!root.transaction ? RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency): ""
networkIcon: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkIcon(transaction.chainId): ""
networkColor: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkColor(transaction.chainId): ""
networkName: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkShortName(transaction.chainId): ""
symbol: root.transaction !== undefined && !!root.transaction ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
transferStatus: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(transaction.txStatus): ""
shortTimeStamp: root.transaction !== undefined && !!root.transaction ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
savedAddressName: root.transaction !== undefined && !!root.transaction ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
property bool transactionValid: root.transaction !== undefined && !!root.transaction
cryptoValue: transactionValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(transaction.value), resolvedSymbol): undefined
fiatValue: transactionValid ? RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency): ""
networkIcon: transactionValid ? RootStore.getNetworkIcon(transaction.chainId): ""
networkColor: transactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
networkName: transactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
symbol: transactionValid ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
transferStatus: transactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
shortTimeStamp: transactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
savedAddressName: transactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
sensor.enabled: false
@ -154,18 +156,19 @@ Item {
spacing: 8
TransactionDelegate {
width: parent.width
locale: root.locale
modelData: transaction
isIncoming: d.isIncoming
currentCurrency: RootStore.currentCurrency
cryptoValue: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Eth(transaction.value): ""
property bool transactionValid: root.transaction !== undefined && !!root.transaction
cryptoValue: transactionValid ? RootStore.getCurrencyAmount(RootStore.hex2Eth(transaction.value), resolvedSymbol): ""
fiatValue: RootStore.getFiatValue(cryptoValue, resolvedSymbol, RootStore.currentCurrency)
networkIcon: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkIcon(transaction.chainId) : ""
networkColor: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkColor(transaction.chainId): ""
networkName: root.transaction !== undefined && !!root.transaction ? RootStore.getNetworkShortName(transaction.chainId): ""
symbol: root.transaction !== undefined && !!root.transaction ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
transferStatus: root.transaction !== undefined && !!root.transaction ? RootStore.hex2Dec(transaction.txStatus): ""
shortTimeStamp: root.transaction !== undefined && !!root.transaction ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
savedAddressName: root.transaction !== undefined && !!root.transaction ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
networkIcon: transactionValid ? RootStore.getNetworkIcon(transaction.chainId) : ""
networkColor: transactionValid ? RootStore.getNetworkColor(transaction.chainId): ""
networkName: transactionValid ? RootStore.getNetworkShortName(transaction.chainId): ""
symbol: transactionValid ? RootStore.findTokenSymbolByAddress(transaction.contract): ""
transferStatus: transactionValid ? RootStore.hex2Dec(transaction.txStatus): ""
shortTimeStamp: transactionValid ? LocaleUtils.formatTime(transaction.timestamp * 1000, Locale.ShortFormat): ""
savedAddressName: transactionValid ? RootStore.getNameForSavedWalletAddress(transaction.to): ""
title: d.isIncoming ? qsTr("Received %1 %2 from %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.from) :
qsTr("Sent %1 %2 to %3").arg(cryptoValue).arg(resolvedSymbol).arg(d.to)
sensor.enabled: false