status-desktop/ui/imports/shared/popups/send/models/SendModalAssetsAdaptor.qml

200 lines
8.1 KiB
QML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
property bool showCommunityAssets: false
property string assetSearchString: ""
/**
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
addressPerChain [model] - submodel of addresses per chain
chainId [string] - unique identifier of a chain
address [string] - address of a token contract
Community related part (relevant for community minted assets, empty otherwise):
communityId [string] - unique identifier of a community, e.g. "0x6734235"
**/
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}`
// account used for balance calculation
property string account: ""
// 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
currentbalance [double] - tokens balance is the commonly used unit, e.g. 1.2 for 1.2 ETH,
computed from balances according to provided criteria
currentBalanceText [string] - formatted and localized balance
currentCurrencyBalance [double] - tokens fiat balance computed from balance and market price
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
balancesModel [model] - filtered balances model by selected account
**/
readonly property alias model: sfpm
ObjectProxyModel {
id: proxyModel
sourceModel: root.tokensModel ?? null
delegate: QObject {
readonly property var rootModel: model
readonly property bool isCommunityAsset: !!model.communityId
readonly property var marketDetails: model.marketDetails
// Read-only roles exposed to the model:
readonly property string key: model.tokensKey
readonly property double currentBalance: AmountsArithmetic.toNumber(totalBalanceAggregator.value, model.decimals)
readonly property double currentCurrencyBalance: currentBalance * marketPrice
readonly property string currentBalanceText: root.formatBalance(currentBalance, model.symbol)
readonly property bool marketDetailsAvailable: !isCommunityAsset
readonly property bool marketDetailsLoading: model.detailsLoading
readonly property real marketPrice: marketDetails.currencyPrice.amount ?? 0
readonly property real marketChangePct24hour: marketDetails.changePct24hour ?? 0
readonly property bool visible: {
root.controller.revision
if (!root.controller.filterAcceptsSymbol(model.symbol))
return false
if (isCommunityAsset) {
return root.showCommunityAssets
}
return currentCurrencyBalance >= root.marketValueThreshold
}
readonly property url icon: !!model.image ? model.image : Constants.tokenIcon(model.symbol, false)
readonly property var balancesModel: filteredBalances
SortFilterProxyModel {
id: filteredBalances
sourceModel: rootModel.balances
filters: [
FastExpressionFilter {
expression: root.account === 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()
}
}
expectedRoles:
["tokensKey", "symbol", "image", "balances", "decimals",
"detailsLoading", "marketDetails", "communityId", "addressPerChain"]
exposedRoles:
["key", "error", "currentBalance", "currentCurrencyBalance", "currentBalanceText",
"icon", "visible", "marketDetailsAvailable", "marketDetailsLoading",
"marketPrice", "marketChangePct24hour", "isCommunityAsset", "balancesModel"]
/* Internal function to search token address */
function __searchAddressInList(addressPerChain, searchString) {
const uppercaseSearchString = searchString.toUpperCase()
let addressFound = false
let tokenAddresses = ModelUtils.modelToFlatArray(addressPerChain, "address")
for (let i =0; i< tokenAddresses.length; i++){
if(tokenAddresses[i].toUpperCase().startsWith(uppercaseSearchString)) {
addressFound = true
break;
}
}
return addressFound
}
}
SortFilterProxyModel {
id: sfpm
sourceModel: proxyModel
objectName: "SendModalAssetsAdaptorModel"
filters: [
FastExpressionFilter {
function search(symbol, name, addressPerChain, searchString) {
const uppercaseSearchString = searchString.toUpperCase()
return (
symbol.toUpperCase().startsWith(uppercaseSearchString) ||
name.toUpperCase().startsWith(uppercaseSearchString) || proxyModel.__searchAddressInList(addressPerChain, searchString)
)
}
expression: search(symbol, name, addressPerChain, root.assetSearchString)
expectedRoles: ["symbol", "name", "addressPerChain"]
},
ValueFilter {
roleName: "visible"
value: true
}
]
sorters: RoleSorter {
roleName: "isCommunityAsset"
}
}
}