203 lines
7.6 KiB
QML
203 lines
7.6 KiB
QML
import QtQml 2.15
|
||
|
||
import StatusQ 0.1
|
||
import StatusQ.Models 0.1
|
||
import StatusQ.Core.Utils 0.1
|
||
|
||
import utils 1.0
|
||
|
||
import SortFilterProxyModel 0.2
|
||
|
||
|
||
QObject {
|
||
id: root
|
||
|
||
// Controller providing information about visibility and order defined
|
||
// by a user (token management)
|
||
required property ManageTokensController controller
|
||
|
||
/**
|
||
Expected model structure:
|
||
|
||
Tokens related part:
|
||
|
||
tokensKey [string] - unique identifier of a token, e.g "0x3234235"
|
||
symbol [string] - token's symbol e.g. "ETH" or "SNT"
|
||
name [string] - token's name e.g. "Ether" or "Dai"
|
||
image [url] - token's icon for custom tokens
|
||
decimals [int] - number of decimal places, e.g. 18 for ETH
|
||
balances [model] - submodel of balances per chain/account
|
||
chainId [string] - unique identifier of a chain
|
||
account [string] - unique identifier of an account
|
||
balance [string] - balance in basic unit as big integer string
|
||
marketDetails [object] - object holding market details
|
||
changePct24hour [double] - percentage change of fiat price in last day
|
||
currencyPrice [object] - object holding fiat price details
|
||
amount [double] - fiat prace of 1 logical unit of cryptocurrency
|
||
detailsLoading [bool] - indicatator if market details are ready to use
|
||
|
||
Community related part (relevant for community minted assets, empty otherwise):
|
||
|
||
communityId [string] - unique identifier of a community, e.g. "0x6734235"
|
||
communityName [string] - name of a community e.g. "Crypto Kitties"
|
||
communityImage [url] - community's icon url
|
||
**/
|
||
property var tokensModel
|
||
|
||
// function formatting tokens balance expressed in a commonly used units,
|
||
// e.g. 1.2 for 1.2 ETH, according to rules specific for given symbol
|
||
property var formatBalance:
|
||
(balance, symbol) => `${balance.toLocaleString(Qt.locale())} ${symbol}`
|
||
|
||
// function providing error message per token depending on used chains,
|
||
// should return empty string if no error found
|
||
property var chainsError: chains => ""
|
||
|
||
// list of chain identifiers used for balance calculation
|
||
property var chains: []
|
||
|
||
// list of accounts used for balance calculation
|
||
property var accounts: []
|
||
|
||
// threshold below which the token is omitted from the output model
|
||
property double marketValueThreshold
|
||
|
||
/**
|
||
Model structure:
|
||
|
||
All roles from the source model are passed directly to the output model,
|
||
additionally:
|
||
|
||
key [string] - renamed from tokensKey
|
||
icon [url] - from image or fetched by symbol for well-known tokens
|
||
balance [double] - tokens balance is the commonly used unit, e.g. 1.2 for 1.2 ETH,
|
||
computed from balances according to provided criteria
|
||
balanceText [string] - formatted and localized balance
|
||
error [string] - error message related to balance
|
||
|
||
marketDetailsAvailable [bool] - specifies if market datails are available for given token
|
||
marketDetailsLoading [bool] - specifies if market datails are available for given token
|
||
marketPrice [double] - specifies market price in currently used currency
|
||
marketChangePct24hour [double] - percentage price change in last 24 hours, e.g. 0.5 for 0.5% of price change
|
||
|
||
position [int] - if custom order available, display position fetched from ManageTokensController
|
||
canBeHidden [bool] - specifies if given token can be hidden (e.g. ETH should be always visible)
|
||
|
||
communityIcon [url] - renamed from communityImage
|
||
**/
|
||
readonly property alias model: sfpm
|
||
|
||
ObjectProxyModel {
|
||
id: proxyModel
|
||
|
||
sourceModel: root.tokensModel ?? null
|
||
|
||
delegate: QObject {
|
||
readonly property var rootModel: model
|
||
readonly property bool hasCommunityId: !!model.communityId
|
||
readonly property var marketDetails: model.marketDetails
|
||
|
||
// Read-only roles exposed to the model:
|
||
|
||
readonly property string key: model.tokensKey
|
||
|
||
readonly property string error:
|
||
root.chainsError(chainsAggregator.uniqueChains)
|
||
|
||
readonly property double balance:
|
||
AmountsArithmetic.toNumber(totalBalanceAggregator.value, model.decimals)
|
||
readonly property string balanceText: root.formatBalance(balance, model.symbol)
|
||
|
||
readonly property bool marketDetailsAvailable: !hasCommunityId
|
||
readonly property bool marketDetailsLoading: model.detailsLoading
|
||
readonly property real marketPrice: marketDetails.currencyPrice.amount ?? 0
|
||
readonly property real marketChangePct24hour: marketDetails.changePct24hour ?? 0
|
||
|
||
readonly property int position: {
|
||
controller.revision
|
||
return controller.order(model.symbol)
|
||
}
|
||
|
||
readonly property bool visible: {
|
||
root.controller.revision
|
||
|
||
if (!root.controller.filterAcceptsSymbol(model.symbol))
|
||
return false
|
||
|
||
if (hasCommunityId)
|
||
return true
|
||
|
||
return balance * marketPrice >= root.marketValueThreshold
|
||
}
|
||
|
||
readonly property url icon:
|
||
!!model.image ? model.image
|
||
: Constants.tokenIcon(model.symbol, false)
|
||
|
||
readonly property url communityIcon: model.communityImage ?? ""
|
||
|
||
readonly property bool canBeHidden: model.symbol !== Constants.ethToken
|
||
|
||
SortFilterProxyModel {
|
||
id: filteredBalances
|
||
|
||
sourceModel: rootModel.balances
|
||
|
||
filters: [
|
||
FastExpressionFilter {
|
||
expression: root.chains.includes(model.chainId)
|
||
expectedRoles: ["chainId"]
|
||
},
|
||
FastExpressionFilter {
|
||
expression: root.accounts.includes(model.account)
|
||
expectedRoles: ["account"]
|
||
}
|
||
]
|
||
}
|
||
|
||
FunctionAggregator {
|
||
id: totalBalanceAggregator
|
||
|
||
model: filteredBalances
|
||
initialValue: "0"
|
||
roleName: "balance"
|
||
|
||
aggregateFunction: (aggr, value) => AmountsArithmetic.sum(
|
||
AmountsArithmetic.fromString(aggr),
|
||
AmountsArithmetic.fromString(value)).toString()
|
||
}
|
||
|
||
FunctionAggregator {
|
||
id: chainsAggregator
|
||
|
||
readonly property var uniqueChains: [...new Set(value).values()]
|
||
|
||
model: filteredBalances
|
||
initialValue: []
|
||
roleName: "chainId"
|
||
|
||
aggregateFunction: (aggr, value) => [...aggr, value]
|
||
}
|
||
}
|
||
|
||
expectedRoles:
|
||
["tokensKey", "symbol", "image", "balances", "decimals",
|
||
"detailsLoading", "marketDetails", "communityId", "communityImage"]
|
||
exposedRoles:
|
||
["key", "error", "balance", "balanceText", "position", "icon",
|
||
"visible", "canBeHidden", "marketDetailsAvailable", "marketDetailsLoading",
|
||
"marketPrice", "marketChangePct24hour", "communityIcon"]
|
||
}
|
||
|
||
SortFilterProxyModel {
|
||
id: sfpm
|
||
|
||
sourceModel: proxyModel
|
||
|
||
filters: ValueFilter {
|
||
roleName: "visible"
|
||
value: true
|
||
}
|
||
}
|
||
}
|