fix(@desktop/keycard): Keycard -> Factory reset: $NaN amount is shown in factory reset flow when account has no funds

Fixes: #9418
This commit is contained in:
Sale Djenic 2023-02-13 18:19:08 +01:00 committed by saledjenic
parent 31be818e0e
commit 86fb93ecb7
14 changed files with 151 additions and 52 deletions

View File

@ -80,6 +80,7 @@ type
urlsManager: UrlsManager
keycardService: keycard_service.Service
settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service
accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service
@ -163,6 +164,7 @@ proc newModule*[T](
result.urlsManager = urlsManager
result.keycardService = keycardService
result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService
result.accountsService = accountsService
result.walletAccountService = walletAccountService
@ -981,7 +983,7 @@ method getKeycardSharedModule*[T](self: Module[T]): QVariant =
proc createSharedKeycardModule[T](self: Module[T]) =
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
@ -1003,7 +1005,7 @@ method onSharedKeycarModuleKeycardSyncPurposeTerminated*[T](self: Module[T], las
method tryKeycardSync*[T](self: Module[T], keyUid: string, pin: string) =
self.keycardSharedModuleKeycardSyncPurpose = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
if self.keycardSharedModuleKeycardSyncPurpose.isNil:
return

View File

@ -8,6 +8,7 @@ import ../../../../core/eventemitter
import ../../../../../app_service/service/keycard/service as keycard_service
import ../../../../../app_service/service/settings/service as settings_service
import ../../../../../app_service/service/network/service as network_service
import ../../../../../app_service/service/privacy/service as privacy_service
import ../../../../../app_service/service/accounts/service as accounts_service
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
@ -36,6 +37,7 @@ type
events: EventEmitter
keycardService: keycard_service.Service
settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service
accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service
@ -49,6 +51,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
events: EventEmitter,
keycardService: keycard_service.Service,
settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service,
accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service,
@ -58,6 +61,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result.events = events
result.keycardService = keycardService
result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService
result.accountsService = accountsService
result.walletAccountService = walletAccountService
@ -102,7 +106,7 @@ proc createSharedKeycardModule(self: Module) =
self.view.emitSharedModuleBusy()
return
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =

View File

@ -106,8 +106,8 @@ proc newModule*(delegate: delegate_interface.AccessInterface,
result, events, settingsService, ensService, walletAccountService, networkService, tokenService
)
result.communitiesModule = communities_module.newModule(result, communityService)
result.keycardModule = keycard_module.newModule(result, events, keycardService, settingsService, privacyService,
accountsService, walletAccountService, keychainService)
result.keycardModule = keycard_module.newModule(result, events, keycardService, settingsService, networkService,
privacyService, accountsService, walletAccountService, keychainService)
singletonInstance.engine.setRootContextProperty("profileSectionModule", result.viewVariant)

View File

@ -237,7 +237,7 @@ method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid:
method createSharedKeycardModule*(self: Module) =
if self.keycardSharedModule.isNil:
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER,
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService,
self.events, self.keycardService, settingsService = nil, networkService = nil, privacyService = nil, self.accountsService,
self.walletAccountService, keychainService = nil)
method destroySharedKeycarModule*(self: Module) =

View File

@ -12,6 +12,7 @@ import ../../../../app_service/common/utils
import ../../../../app_service/common/account_constants
import ../../../../app_service/service/keycard/service as keycard_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/network/service as network_service
import ../../../../app_service/service/privacy/service as privacy_service
import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
@ -29,6 +30,7 @@ type
events: EventEmitter
keycardService: keycard_service.Service
settingsService: settings_service.Service
networkService: network_service.Service
privacyService: privacy_service.Service
accountsService: accounts_service.Service
walletAccountService: wallet_account_service.Service
@ -71,6 +73,7 @@ proc newController*(delegate: io_interface.AccessInterface,
events: EventEmitter,
keycardService: keycard_service.Service,
settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service,
accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service,
@ -82,6 +85,7 @@ proc newController*(delegate: io_interface.AccessInterface,
result.events = events
result.keycardService = keycardService
result.settingsService = settingsService
result.networkService = networkService
result.privacyService = privacyService
result.accountsService = accountsService
result.walletAccountService = walletAccountService
@ -112,6 +116,8 @@ proc serviceApplicable[T](service: T): bool =
serviceName = "PrivacyService"
when (service is settings_service.Service):
serviceName = "SettingsService"
when (service is network_service.Service):
serviceName = "NetworkService"
when (service is accounts_service.Service):
serviceName = "AccountsService"
when (service is keychain_service.Service):
@ -182,6 +188,11 @@ proc init*(self: Controller) =
self.delegate.onSecondaryActionClicked()
self.connectionIds.add(handlerId)
handlerId = self.events.onWithUUID(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args):
let arg = TokensPerAccountArgs(e)
self.delegate.onTokensRebuilt(arg.accountsTokens)
self.connectionIds.add(handlerId)
proc switchToWalletSection*(self: Controller) =
let data = ActiveSectionChatArgs(sectionId: conf.WALLET_SECTION_ID)
self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data)
@ -602,10 +613,11 @@ proc isKeyPairAlreadyAdded*(self: Controller, keyUid: string): bool =
let accountsForKeyUid = walletAccounts.filter(a => a.keyUid == keyUid)
return accountsForKeyUid.len > 0
proc getCurrencyBalanceForAddress*(self: Controller, address: string): float64 =
proc getOrFetchBalanceForAddressInPreferredCurrency*(self: Controller, address: string): tuple[balance: float64, fetched: bool] =
if not serviceApplicable(self.walletAccountService):
return
return self.walletAccountService.getCurrencyBalanceForAddress(address)
# Return 0, casuse JSON-RPC client is unavailable before user logs in.
return (0.0, true)
return self.walletAccountService.getOrFetchBalanceForAddressInPreferredCurrency(address)
proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto) =
if not serviceApplicable(self.walletAccountService):
@ -682,6 +694,16 @@ proc getSigningPhrase*(self: Controller): string =
return
return self.settingsService.getSigningPhrase()
proc getCurrency*(self: Controller): string =
if not serviceApplicable(self.settingsService):
return
return self.settingsService.getCurrency()
proc getChainIdsOfAllKnownNetworks*(self: Controller): seq[int] =
if not serviceApplicable(self.networkService):
return
return self.networkService.getNetworks().map(n => n.chainId)
proc enterKeycardPin*(self: Controller, pin: string) =
if not serviceApplicable(self.keycardService):
return

View File

@ -1,6 +1,7 @@
import NimQml
import NimQml, tables
import ../../../../app/core/eventemitter
from ../../../../app_service/service/keycard/service import KeycardEvent, CardMetadata, KeyDetails
from ../../../../app_service/service/wallet_account/service as wallet_account_service import WalletTokenDto
import models/key_pair_item
const SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED_AND_WALLET_ADDRESS_GENERATED* = "sharedKeycarModuleUserAuthenticatedAndWalletAddressGenerated"
@ -202,5 +203,8 @@ method syncKeycardBasedOnAppState*(self: AccessInterface, keyUid: string, pin: s
method getPin*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method onTokensRebuilt*(self: AccessInterface, accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) {.base.} =
raise newException(ValueError, "No implementation available")
type
DelegateInterface* = concept c

View File

@ -10,12 +10,13 @@ QtObject:
color: string
icon: string
balance: float
balanceFetched: bool
proc delete*(self: KeyPairAccountItem) =
self.QObject.delete
proc newKeyPairAccountItem*(name = "", path = "", address = "", pubKey = "", emoji = "", color = "", icon = "",
balance = 0.0): KeyPairAccountItem =
balance = 0.0, balanceFetched = true): KeyPairAccountItem =
new(result, delete)
result.QObject.setup
result.name = name
@ -26,6 +27,7 @@ QtObject:
result.color = color
result.icon = icon
result.balance = balance
result.balanceFetched = balanceFetched
proc `$`*(self: KeyPairAccountItem): string =
result = fmt"""KeyPairAccountItem[
@ -37,7 +39,8 @@ QtObject:
color: {self.color},
icon: {self.icon},
icon: {$self.icon},
balance: {self.balance}
balance: {self.balance},
balanceFetched: {self.balanceFetched}
]"""
proc nameChanged*(self: KeyPairAccountItem) {.signal.}
@ -122,8 +125,15 @@ QtObject:
return self.balance
proc setBalance*(self: KeyPairAccountItem, value: float) {.slot.} =
self.balance = value
self.balanceFetched = true
self.balanceChanged()
QtProperty[float] balance:
read = getBalance
write = setBalance
notify = balanceChanged
proc getBalanceFetched*(self: KeyPairAccountItem): bool {.slot.} =
return self.balanceFetched
QtProperty[bool] balanceFetched:
read = getBalanceFetched
notify = balanceChanged

View File

@ -119,4 +119,9 @@ QtObject:
if emoji.len > 0:
self.items[i].setEmoji(emoji)
return
proc setBalanceForAddress*(self: KeyPairAccountModel, address: string, balance: float) =
for i in 0 ..< self.items.len:
if cmpIgnoreCase(self.items[i].getAddress(), address) == 0:
self.items[i].setBalance(balance)

View File

@ -196,6 +196,8 @@ QtObject:
return self.accounts.containsPathOutOfTheDefaultStatusDerivationTree()
proc updateDetailsForAccountWithAddressIfTheyAreSet*(self: KeyPairItem, address, name, color, emoji: string) =
self.accounts.updateDetailsForAddressIfTheyAreSet(address, name, color, emoji)
proc setBalanceForAddress*(self: KeyPairItem, address: string, balance: float) =
self.accounts.setBalanceForAddress(address, balance)
proc setItem*(self: KeyPairItem, item: KeyPairItem) =
self.setKeyUid(item.getKeyUid())

View File

@ -1,4 +1,4 @@
import NimQml, random, strutils, marshal, sequtils, sugar, chronicles
import NimQml, tables, random, strutils, marshal, sequtils, sugar, chronicles
import io_interface
import view, controller
@ -11,6 +11,7 @@ import ../../../../app_service/common/utils
import ../../../../app_service/service/keycard/constants
import ../../../../app_service/service/keycard/service as keycard_service
import ../../../../app_service/service/settings/service as settings_service
import ../../../../app_service/service/network/service as network_service
import ../../../../app_service/service/privacy/service as privacy_service
import ../../../../app_service/service/accounts/service as accounts_service
import ../../../../app_service/service/wallet_account/service as wallet_account_service
@ -43,6 +44,7 @@ proc newModule*[T](delegate: T,
events: EventEmitter,
keycardService: keycard_service.Service,
settingsService: settings_service.Service,
networkService: network_service.Service,
privacyService: privacy_service.Service,
accountsService: accounts_service.Service,
walletAccountService: wallet_account_service.Service,
@ -53,7 +55,7 @@ proc newModule*[T](delegate: T,
result.view = view.newView(result)
result.viewVariant = newQVariant(result.view)
result.controller = controller.newController(result, uniqueIdentifier, events, keycardService, settingsService,
privacyService, accountsService, walletAccountService, keychainService)
networkService, privacyService, accountsService, walletAccountService, keychainService)
result.initialized = false
result.authenticationPopupIsAlreadyRunning = false
result.derivingAccountDetails.deriveAddressAfterAuthentication = false
@ -624,10 +626,17 @@ proc updateKeyPairItemIfDataAreKnown[T](self: Module[T], address: string, item:
if a.walletType == WalletTypeDefaultStatusAccount:
icon = "wallet"
item.setKeyUid(a.keyUid)
item.addAccount(newKeyPairAccountItem(a.name, a.path, a.address, a.publicKey, a.emoji, a.color, icon, balance = 0.0))
item.addAccount(newKeyPairAccountItem(a.name, a.path, a.address, a.publicKey, a.emoji, a.color, icon, balance = 0.0, balanceFetched = true))
return true
return false
method onTokensRebuilt*[T](self: Module[T], accountsTokens: OrderedTable[string, seq[WalletTokenDto]]) =
let chainIds = self.controller.getChainIdsOfAllKnownNetworks()
let currency = self.controller.getCurrency()
for address, tokens in accountsTokens.pairs:
let balance = tokens.map(t => t.getCurrencyBalance(chainIds, currency)).foldl(a + b, 0.0)
self.getKeyPairForProcessing().setBalanceForAddress(address, balance)
proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardMetadata):
tuple[item: KeyPairItem, knownKeyPair: bool] =
result.item = newKeyPairItem(keyUid = "",
@ -646,9 +655,10 @@ proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardM
for wa in cardMetadata.walletAccounts:
if self.updateKeyPairItemIfDataAreKnown(wa.address, result.item):
continue
let balance = self.controller.getCurrencyBalanceForAddress(wa.address)
let (balance, balanceFetched) = self.controller.getOrFetchBalanceForAddressInPreferredCurrency(wa.address)
result.knownKeyPair = false
result.item.addAccount(newKeyPairAccountItem(name = "", wa.path, wa.address, pubKey = wa.publicKey, emoji = "", color = self.generateRandomColor(), icon = "wallet", balance))
result.item.addAccount(newKeyPairAccountItem(name = "", wa.path, wa.address, pubKey = wa.publicKey, emoji = "",
color = self.generateRandomColor(), icon = "wallet", balance, balanceFetched))
method updateKeyPairForProcessing*[T](self: Module[T], cardMetadata: CardMetadata) =
let(item, knownKeyPair) = self.buildKeyPairItemBasedOnCardMetadata(cardMetadata)

View File

@ -129,7 +129,7 @@ method getKeycardSharedModule*[T](self: Module[T]): QVariant =
proc createSharedKeycardModule[T](self: Module[T]) =
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_STARTUP_MODULE_IDENTIFIER,
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService,
self.events, self.keycardService, settingsService = nil, networkService = nil, privacyService = nil, self.accountsService,
walletAccountService = nil, self.keychainService)
method moveToLoadingAppState*[T](self: Module[T]) =

View File

@ -112,11 +112,21 @@ const fetchDerivedAddressDetailsTask*: Task = proc(argEncoded: string) {.gcsafe,
type
BuildTokensTaskArg = ref object of QObjectTaskArg
accounts: seq[string]
storeResult: bool
const prepareTokensTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[BuildTokensTaskArg](argEncoded)
let response = backend.getWalletToken(arg.accounts)
arg.finish(response.result)
var output = %*{
"result": "",
"storeResult": false
}
try:
let response = backend.getWalletToken(arg.accounts)
output["result"] = response.result
output["storeResult"] = %* arg.storeResult
except Exception as e:
let err = fmt"Error getting wallet tokens"
arg.finish(output)
#################################################
# Async add migrated keypair

View File

@ -120,7 +120,7 @@ QtObject:
walletAccounts {.guard: walletAccountsLock.}: OrderedTable[string, WalletAccountDto]
# Forward declaration
proc buildAllTokens(self: Service, accounts: seq[string])
proc buildAllTokens(self: Service, accounts: seq[string], store: bool)
proc checkRecentHistory*(self: Service)
proc checkConnected(self: Service)
proc startWallet(self: Service)
@ -212,7 +212,7 @@ QtObject:
account.relatedAccounts = accounts.filter(x => not account.derivedFrom.isEmptyOrWhitespace and (cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0))
self.storeAccount(account)
self.buildAllTokens(self.getAddresses())
self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory()
self.startWallet()
except Exception as e:
@ -231,7 +231,7 @@ QtObject:
var data = WalletSignal(e)
case data.eventType:
of "wallet-tick-reload":
self.buildAllTokens(self.getAddresses())
self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory()
of "wallet-tick-check-connected":
self.checkConnected()
@ -290,7 +290,7 @@ QtObject:
newAccount.relatedAccounts = accounts.filter(x => cmpIgnoreCase(x.derivedFrom, account.derivedFrom) == 0)
break
self.storeAccount(newAccount)
self.buildAllTokens(@[newAccount.address])
self.buildAllTokens(@[newAccount.address], store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
proc addOrReplaceWalletAccount(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
@ -405,7 +405,7 @@ QtObject:
proc updateCurrency*(self: Service, newCurrency: string) =
discard self.settingsService.saveCurrency(newCurrency)
self.buildAllTokens(self.getAddresses())
self.buildAllTokens(self.getAddresses(), store = true)
self.events.emit(SIGNAL_WALLET_ACCOUNT_CURRENCY_UPDATED, CurrencyUpdated())
proc toggleNetworkEnabled*(self: Service, chainId: int) =
@ -525,27 +525,33 @@ QtObject:
let chainIds = self.networkService.getNetworks().map(n => n.chainId)
let responseObj = response.parseJson
var storeResult: bool
var resultObj: JsonNode
discard responseObj.getProp("storeResult", storeResult)
discard responseObj.getProp("result", resultObj)
var data = TokensPerAccountArgs()
if responseObj.kind == JObject:
for wAddress, tokensDetailsObj in responseObj:
if resultObj.kind == JObject:
for wAddress, tokensDetailsObj in resultObj:
if tokensDetailsObj.kind == JArray:
var tokens: seq[WalletTokenDto]
tokens = map(tokensDetailsObj.getElems(), proc(x: JsonNode): WalletTokenDto = x.toWalletTokenDto())
tokens.sort(priorityTokenCmp)
data.accountsTokens[wAddress] = tokens
self.storeTokensForAccount(wAddress, tokens)
self.tokenService.updateTokenPrices(tokens) # For efficiency. Will be removed when token info fetching gets moved to the tokenService
# Gather symbol for visible tokens
for token in tokens:
if token.getVisibleForNetworkWithPositiveBalance(chainIds) and find(visibleSymbols, token.symbol) == -1:
visibleSymbols.add(token.symbol)
if storeResult:
self.storeTokensForAccount(wAddress, tokens)
self.tokenService.updateTokenPrices(tokens) # For efficiency. Will be removed when token info fetching gets moved to the tokenService
# Gather symbol for visible tokens
for token in tokens:
if token.getVisibleForNetworkWithPositiveBalance(chainIds) and find(visibleSymbols, token.symbol) == -1:
visibleSymbols.add(token.symbol)
self.events.emit(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT, data)
discard backend.updateVisibleTokens(visibleSymbols)
if visibleSymbols.len > 0:
discard backend.updateVisibleTokens(visibleSymbols)
except Exception as e:
error "error: ", procName="onAllTokensBuilt", errName = e.name, errDesription = e.msg
proc buildAllTokens(self: Service, accounts: seq[string]) =
proc buildAllTokens(self: Service, accounts: seq[string], store: bool) =
if not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled() or
accounts.len == 0:
return
@ -554,16 +560,17 @@ QtObject:
tptr: cast[ByteAddress](prepareTokensTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAllTokensBuilt",
accounts: accounts
accounts: accounts,
storeResult: store
)
self.threadpool.start(arg)
proc onIsWalletEnabledChanged*(self: Service) {.slot.} =
self.buildAllTokens(self.getAddresses())
self.buildAllTokens(self.getAddresses(), store = true)
self.checkRecentHistory()
self.startWallet()
proc getCurrentCurrencyIfEmpty(self: Service, currency: string): string =
proc getCurrentCurrencyIfEmpty(self: Service, currency = ""): string =
if currency != "":
return currency
else:
@ -577,9 +584,15 @@ QtObject:
proc findTokenSymbolByAddress*(self: Service, address: string): string =
return self.tokenService.findTokenSymbolByAddress(address)
proc getCurrencyBalanceForAddress*(self: Service, address: string, currency: string = ""): float64 =
let chainIds = self.networkService.getNetworks().map(n => n.chainId)
return self.getAccountByAddress(address).getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty(currency))
proc getOrFetchBalanceForAddressInPreferredCurrency*(self: Service, address: string): tuple[balance: float64, fetched: bool] =
if self.walletAccountsContainsAddress(address):
let chainIds = self.networkService.getNetworks().map(n => n.chainId)
result.balance = self.getAccountByAddress(address).getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty())
result.fetched = true
else:
self.buildAllTokens(@[address], store = false)
result.balance = 0.0
result.fetched = false
proc getTotalCurrencyBalance*(self: Service, currency: string = ""): float64 =
let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId)

View File

@ -126,17 +126,34 @@ Rectangle {
Layout.preferredHeight: parent.height
}
StatusBaseText {
Layout.alignment: Qt.AlignVCenter
text: {
return LocaleUtils.currencyAmountToLocaleString({
amount: parseFloat(model.account.balance.amount),
symbol: SharedStore.RootStore.currencyStore.currentCurrencySymbol,
displayDecimals: 2})
Component {
id: balance
StatusBaseText {
text: {
return LocaleUtils.currencyAmountToLocaleString({
amount: parseFloat(model.account.balance),
symbol: SharedStore.RootStore.currencyStore.currentCurrencySymbol,
displayDecimals: 2})
}
wrapMode: Text.WordWrap
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
}
wrapMode: Text.WordWrap
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
}
Component {
id: fetchingBalance
StatusLoadingIndicator {
width: 12
height: 12
}
}
Loader {
id: fetchLoaderIndicator
Layout.alignment: Qt.AlignVCenter
sourceComponent: model.account.balanceFetched? balance : fetchingBalance
}
}
}