chore: Remove custom rowData method from NIM's models

- Some NIM's models define additional (not part of the
QAbstractModelItem API) method rowData to allow access to model's data
on UI side
- The same job can be done relying fully on public QAbstractModelItem
API using ModelUtils utility. It gives full transparency if we need
nim's model or other like ListModel replacement in tests/storybook
- propagate `tokensStore` to unbreak the Browser's wallet menu

Fixes #14805
This commit is contained in:
Lukáš Tinkl 2024-05-20 14:18:44 +02:00 committed by Lukáš Tinkl
parent 62b7083f4c
commit a6c897929a
21 changed files with 46 additions and 222 deletions

View File

@ -67,15 +67,6 @@ QtObject:
of ModelRole.ImageUrl:
result = newQVariant(item.getImageUrl())
proc rowData(self: Model, index: int, column: string): string {.slot.} =
if (index > self.items.len - 1):
return
let bookmark = self.items[index]
case column:
of "name": result = bookmark.getName()
of "url": result = bookmark.getUrl()
of "imageUrl": result = bookmark.getImageUrl()
proc addItem*(self: Model, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete

View File

@ -63,13 +63,6 @@ QtObject:
of ModelRole.Accounts:
result = newQVariant(item.accounts)
proc rowData*(self: DappsModel, index: int, column: string): string {.slot.} =
if (index > self.items.len - 1):
return
let item = self.items[index]
case column:
of "name": result = item.name
proc addItem*(self: DappsModel, item: Item) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete

View File

@ -143,20 +143,3 @@ QtObject:
proc getFoundStickers*(self: StickerPackList): QVariant {.slot.} =
return self.foundStickers
proc rowData*(self: StickerPackList, row: int, data: string): string {.slot.} =
if row < 0 or (row > self.packs.len - 1):
return
self.packIdToRetrieve = row
let packInfo = self.packs[row]
let stickerPack = packInfo.pack
case data:
of "author": result = stickerPack.author
of "name": result = stickerPack.name
of "price": result = self.delegate.wei2Eth(stickerPack.price)
of "preview": result = stickerPack.preview
of "thumbnail": result = stickerPack.thumbnail
of "installed": result = $packInfo.installed
of "bought": result = $packInfo.bought
of "pending": result = $packInfo.pending
else: result = ""

View File

@ -114,18 +114,6 @@ QtObject:
error "Invalid role for loading item"
result = newQVariant()
proc rowData(self: CollectiblesModel, index: int, column: string): string {.slot.} =
if (index >= self.items.len):
return
let item = self.items[index]
case column:
of "uid": result = item.getId()
of "chainId": result = $item.getChainId()
of "contractAddress": result = item.getContractAddress()
of "tokenId": result = item.getTokenId().toString()
of "name": result = item.getName()
of "imageUrl": result = item.getImageUrl()
proc appendCollectibleItems(self: CollectiblesModel, newItems: seq[CollectibleItem]) =
if len(newItems) == 0:
return

View File

@ -120,29 +120,6 @@ QtObject:
of ModelRole.OriginalFallbackURL:
result = newQVariant(item.originalFallbackURL)
proc rowData*(self: Model, index: int, column: string): string {.slot.} =
if (index >= self.rowCount()):
return
let item = self.delegate.getFlatNetworksList()[index]
case column:
of "chainId": result = $item.chainId
of "nativeCurrencyDecimals": result = $item.nativeCurrencyDecimals
of "layer": result = $item.layer
of "chainName": result = $item.chainName
of "rpcURL": result = $item.rpcURL
of "blockExplorerURL": result = $item.blockExplorerURL
of "nativeCurrencyName": result = $item.nativeCurrencyName
of "nativeCurrencySymbol": result = $item.nativeCurrencySymbol
of "isTest": result = $item.isTest
of "isEnabled": result = $item.isEnabled
of "iconUrl": result = $item.iconURL
of "chainColor": result = $item.chainColor
of "shortName": result = $item.shortName
of "enabledState": result = $item.enabledState.int
of "fallbackURL": result = $item.fallbackURL
of "originalRpcURL": result = $item.originalRpcURL
of "originalFallbackURL": result = $item.originalFallbackURL
proc refreshModel*(self: Model) =
self.beginResetModel()
self.endResetModel()

View File

@ -85,18 +85,6 @@ QtObject:
of ModelRole.IsTest:
result = newQVariant(item.getIsTest())
proc rowData(self: Model, index: int, column: string): string {.slot.} =
if (index >= self.items.len):
return
let item = self.items[index]
case column:
of "name": result = $item.getName()
of "address": result = $item.getAddress()
of "ens": result = $item.getEns()
of "colorId": result = $item.getColorId()
of "chainShortNames": result = $item.getChainShortNames()
of "isTest": result = $item.getIsTest()
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
@ -119,4 +107,4 @@ QtObject:
if item.getName() == name and
(item.getIsTest() == isTest):
return true
return false
return false

View File

@ -196,27 +196,6 @@ QtObject:
of CollectibleRole.Soulbound:
result = newQVariant(item.getSoulbound())
proc rowData(self: Model, index: int, column: string): string {.slot.} =
if (index >= self.items.len):
return
let item = self.items[index]
case column:
of "uid": result = item.getIDAsString()
of "chainId": result = $item.getChainID()
of "contractAddress": result = item.getContractAddress()
of "tokenId": result = item.getTokenIDAsString()
of "name": result = item.getName()
of "mediaUrl": result = item.getMediaURL()
of "mediaType": result = item.getMediaType()
of "imageUrl": result = item.getImageURL()
of "backgroundColor": result = item.getBackgroundColor()
of "collectionUid": result = item.getCollectionIDAsString()
of "collectionName": result = item.getCollectionName()
of "collectionSlug": result = item.getCollectionSlug()
of "isLoading": result = $false
of "communityId": result = item.getCommunityID()
of "communityPrivilegesLevel": result = $item.getCommunityPrivilegesLevel()
proc resetCollectibleItems(self: Model, newItems: seq[CollectiblesEntry] = @[]) =
self.beginResetModel()
self.items = newItems

View File

@ -122,20 +122,6 @@ QtObject:
of CollectiblesNestedRole.Count:
result = newQVariant(item.getCountAsString())
proc rowData(self: Model, index: int, column: string): string {.slot.} =
if (index >= self.items.len):
return
let item = self.items[index]
case column:
of "uid": result = item.getId()
of "chainId": result = $item.getChainId()
of "name": result = item.getName()
of "iconUrl": result = item.getIconUrl()
of "groupId": result = item.getGroupId()
of "groupName": result = item.getGroupName()
of "itemType": result = $item.getItemType()
of "count": result = item.getCountAsString()
# Groups collectibles by CommunityID if available, or CollectionID otherwise.
# Returns pair (collectiblesPerCommunity, collectiblesPerCollection)
proc getCollectiblesPerGroupId(items: seq[flat_item.CollectiblesEntry]): (CollectiblesPerGroupId, CollectiblesPerGroupId) =
@ -212,4 +198,4 @@ QtObject:
proc setAddress*(self: Model, address: string) {.slot.} =
self.address = address
self.refreshItems()
self.refreshItems()

View File

@ -206,11 +206,6 @@ SplitView {
SortFilterProxyModel {
id: availableNetworks
// Simulate Nim's way of providing access to data
function rowData(index, propName) {
return get(index)[propName]
}
sourceModel: NetworksModel.flatNetworks
filters: ValueFilter { roleName: "isTest"; value: testModeCheckbox.checked; }
}

View File

@ -52,14 +52,7 @@ QtObject {
return "Custom"
}
component CustomNetworkModel: ListModel {
// Simulate Nim's way of providing access to data
function rowData(index, propName) {
return get(index)[propName]
}
}
readonly property var flatNetworks: CustomNetworkModel {
readonly property var flatNetworks: ListModel {
Component.onCompleted: append([
{
chainId: 1,
@ -148,7 +141,7 @@ QtObject {
)
}
readonly property var sendFromNetworks: CustomNetworkModel {
readonly property var sendFromNetworks: ListModel {
function updateFromNetworks(paths){
reset()
for(let i=0; i<paths.length; i++) {
@ -248,7 +241,7 @@ QtObject {
])
}
readonly property var sendToNetworks: CustomNetworkModel {
readonly property var sendToNetworks: ListModel {
function updateRoutePreferredChains(chainIds) {
for( let i=0; i<count; i++) {
get(i).isPreferred = false

View File

@ -13,7 +13,7 @@ import SortFilterProxyModel 0.2
Item {
id: root
property string label: "Choose account"
property string label: qsTr("Choose account")
property bool showAccountDetails: !!selectedAccount
property var accounts
property var selectedAccount
@ -32,7 +32,8 @@ Item {
property var assetBalanceTextFn: function (foundValue) {
return "Balance: " + (parseFloat(foundValue) === 0.0 ? "0" : Utils.stripTrailingZeros(foundValue))
return qsTr("Balance: %1").arg(parseFloat(foundValue) === 0.0 ? Qt.locale().zeroDigit
: LocaleUtils.numberToLocaleString(foundValue))
}
readonly property string watchWalletType: "watch"
@ -284,4 +285,3 @@ Item {
}
}
}

View File

@ -18,6 +18,7 @@ QtObject {
}
return returnPos;
}
function isValidAddress(inputValue) {
return inputValue !== "0x" && /^0x[a-fA-F0-9]{40}$/.test(inputValue)
}
@ -51,15 +52,16 @@ QtObject {
function findAssetByChainAndSymbol(chainIdToFind, assets, symbolToFind) {
for(var i=0; i<assets.rowCount(); i++) {
const symbol = assets.rowData(i, "symbol")
if (symbol.toLowerCase() === symbolToFind.toLowerCase() && assets.hasChain(i, parseInt(chainIdToFind))) {
const item = ModelUtils.get(assets, i)
if (item.symbol.toLowerCase() === symbolToFind.toLowerCase() &&
!!ModelUtils.getByKey(item.balances, "chainId", chainIdToFind)) {
return {
name: assets.rowData(i, "name"),
symbol,
totalBalance: assets.rowData(i, "totalBalance"),
totalCurrencyBalance: assets.rowData(i, "totalCurrencyBalance"),
fiatBalance: assets.rowData(i, "totalCurrencyBalance"),
chainId: chainIdToFind,
name: item.name,
symbol: item.symbol,
totalBalance: item.totalBalance,
totalCurrencyBalance: item.totalCurrencyBalance,
fiatBalance: item.totalCurrencyBalance,
chainId: chainIdToFind
}
}
}
@ -220,31 +222,8 @@ QtObject {
return text.replace(/<[^>]*>?/gm, '')
}
function delegateModelSort(srcGroup, dstGroup, lessThan) {
const insertPosition = (lessThan, item) => {
let lower = 0
let upper = dstGroup.count
while (lower < upper) {
const middle = Math.floor(lower + (upper - lower) / 2)
const result = lessThan(item.model, dstGroup.get(middle).model);
if (result)
upper = middle
else
lower = middle + 1
}
return lower
}
while (srcGroup.count > 0) {
const item = srcGroup.get(0)
const index = insertPosition(lessThan, item)
item.groups = dstGroup.name
dstGroup.move(item.itemsIndex, index)
}
}
function elideText(text, leftCharsCount, rightCharsCount = leftCharsCount) {
return text.substr(0, leftCharsCount) + "..." + text.substr(text.length - rightCharsCount)
return text.substr(0, leftCharsCount) + "…" + text.substr(text.length - rightCharsCount)
}
function elideAndFormatWalletAddress(address) {
@ -289,5 +268,3 @@ QtObject {
return text.replace(/http(s)?(:)?(\/\/)?|(\/\/)?(www\.)?(\/)/gim, '')
}
}

View File

@ -34,6 +34,7 @@ StatusSectionLayout {
required property TransactionStore transactionStore
required property var assetsStore
required property var currencyStore
required property var tokensStore
function openUrlInNewTab(url) {
var tab = _internal.addNewTab()
@ -434,6 +435,7 @@ StatusSectionLayout {
BrowserWalletMenu {
assetsStore: root.assetsStore
currencyStore: root.currencyStore
tokensStore: root.tokensStore
property point headerPoint: Qt.point(browserHeader.x, browserHeader.y)
x: (parent.width - width - Style.current.halfPadding)
y: (Math.abs(browserHeader.mapFromGlobal(headerPoint).y) +

View File

@ -18,6 +18,7 @@ Dialog {
required property var assetsStore
required property var currencyStore
required property var tokensStore
signal sendTriggered(var selectedAccount)
signal disconnect()
@ -209,6 +210,7 @@ Dialog {
id: assetsTab
controller: popup.assetsStore.assetsController
currencyStore: popup.currencyStore
tokensStore: popup.tokensStore
}
HistoryView {
id: historyTab

View File

@ -1,6 +1,8 @@
pragma Singleton
import QtQuick 2.13
import QtQuick 2.15
import StatusQ.Core.Utils 0.1 as SQUtils
QtObject {
id: root
@ -36,10 +38,12 @@ QtObject {
return null
}
const item = SQUtils.ModelUtils.get(bookmarkModule.model, index)
return {
url: url,
name: bookmarkModule.model.rowData(index, 'name'),
image: bookmarkModule.model.rowData(index, 'imageUrl')
name: item.name,
image: item.imageUrl
}
}
}

View File

@ -116,7 +116,8 @@ QtObject {
function initChainColors(model) {
for (let i = 0; i < model.count; i++) {
chainColors[model.rowData(i, "shortName")] = model.rowData(i, "chainColor")
const item = SQUtils.ModelUtils.get(model, i)
chainColors[item.shortName] = item.chainColor
}
}

View File

@ -1,11 +1,12 @@
import QtQuick 2.15
import StatusQ.Core.Utils 0.1 as SQUtils
/// Helper item to clone a model and alter its data without affecting the original model
/// \beware this is not a proxy model. It clones the initial state
/// and every time the instance changes and doesn't adapt when the data
/// in the source model \c allNetworksModel changes
/// \beware use it with small models and in temporary views (e.g. popups)
/// \note requires `rowData` to be implemented in the model
/// \note tried to use SortFilterProxyModel with but it complicates implementation too much
ListModel {
id: root
@ -21,10 +22,6 @@ ListModel {
Component.onCompleted: cloneModel(sourceModel)
onSourceModelChanged: cloneModel(sourceModel)
function rowData(index, roleName) {
return get(index)[roleName]
}
function findIndexForRole(roleName, value) {
for (let i = 0; i < count; i++) {
if(get(i)[roleName] === value) {
@ -44,10 +41,7 @@ ListModel {
for (let i = 0; i < model.count; i++) {
const clonedItem = new Object()
for (var propName of roles) {
if(model.rowData === undefined)
clonedItem[propName] = model.get(i, propName)
else
clonedItem[propName] = model.rowData(i, propName)
clonedItem[propName] = SQUtils.ModelUtils.get(model, i, propName)
}
for (var newProp of rolesOverride) {
clonedItem[newProp.role] = newProp.transform(clonedItem)

View File

@ -1303,6 +1303,7 @@ Item {
transactionStore: appMain.transactionStore
assetsStore: appMain.walletAssetsStore
currencyStore: appMain.currencyStore
tokensStore: appMain.tokensStore
}
// Loaders do not have access to the context, so props need to be set
// Adding a "_" to avoid a binding loop

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import utils 1.0
import shared 1.0
@ -39,14 +40,15 @@ ModalPopup {
Component.onCompleted: {
const idx = stickersModule.stickerPacks.findIndexById(packId, false);
if(idx === -1) close();
name = stickersModule.stickerPacks.rowData(idx, "name")
author = stickersModule.stickerPacks.rowData(idx, "author")
thumbnail = stickersModule.stickerPacks.rowData(idx, "thumbnail")
price = stickersModule.stickerPacks.rowData(idx, "price")
const item = SQUtils.ModelUtils.get(stickersModule.stickerPacks, idx)
name = item.name
author = item.author
thumbnail = item.thumbnail
price = item.price
stickers = stickersModule.stickerPacks.getStickers()
installed = stickersModule.stickerPacks.rowData(idx, "installed") === "true"
bought = stickersModule.stickerPacks.rowData(idx, "bought") === "true"
pending = stickersModule.stickerPacks.rowData(idx, "pending") === "true"
installed = item.installed
bought = item.bought
pending = item.pending
}
height: 472

View File

@ -75,7 +75,7 @@ ColumnLayout {
let nwFilters = root.networkFilters.split(":")
let addrFilters = root.addressFilters.split(":")
for(let i=0; i<balances.count; i++) {
let balancePerAddressPerChain = ModelUtils.get(balances, i)
let balancePerAddressPerChain = SQUtils.ModelUtils.get(balances, i)
if (nwFilters.includes(balancePerAddressPerChain.chainId+"") &&
addrFilters.includes(balancePerAddressPerChain.account)) {
totalBalance+=SQUtils.AmountsArithmetic.toNumber(balancePerAddressPerChain[key], decimals)

View File

@ -169,7 +169,6 @@ QtObject {
return isEmail || isDomain || (inputValue.startsWith("@") && inputValue.length > 1)
}
/**
* Removes trailing zeros from a string-representation of a number. Throws
* if parameter is not a string
@ -205,23 +204,6 @@ QtObject {
return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha)
}
// To-do move to Wallet Store, this should not be under Utils.
function findAssetByChainAndSymbol(chainIdToFind, assets, symbolToFind) {
for(var i=0; i<assets.rowCount(); i++) {
const symbol = assets.rowData(i, "symbol")
if (symbol.toLowerCase() === symbolToFind.toLowerCase() && assets.hasChain(i, parseInt(chainIdToFind))) {
return {
name: assets.rowData(i, "name"),
symbol,
totalBalance: assets.rowData(i, "totalBalance"),
totalCurrencyBalance: assets.rowData(i, "totalCurrencyBalance"),
fiatBalance: assets.rowData(i, "totalCurrencyBalance"),
chainId: chainIdToFind,
}
}
}
}
function isValidChannelName(channelName) {
return (/^[a-z0-9\-]+$/.test(channelName))
}
@ -662,20 +644,6 @@ QtObject {
return 34
}
function getTimerString(timeInSecs) {
let result = ""
const hour = Math.floor(timeInSecs/60/60)
const mins = Math.floor(timeInSecs/60%60)
const secs = Math.floor(timeInSecs%60)
if(hour > 0 )
result += qsTr(" %n hour(s) ", "", hour)
if(mins > 0)
result += qsTr(" %n min(s) ", "", mins)
if(secs > 0)
result += qsTr(" %n sec(s) ", "", secs)
return result
}
function appTranslation(key) {
switch(key) {
case Constants.appTranslatableConstants.loginAccountsListAddNewUser: