feat(@desktop/wallet): add pagination to collectibles view

Fixes #9754
This commit is contained in:
Dario Gabriel Lipicar 2023-03-06 13:46:32 -03:00 committed by dlipicar
parent 6ec562c6b2
commit 30294f97fe
27 changed files with 454 additions and 837 deletions

View File

@ -30,23 +30,14 @@ proc newController*(
proc delete*(self: Controller) =
discard
proc refreshCollections*(self: Controller, chainId: int, address: string) =
let collections = self.collectibleService.getOwnedCollections(chainId, address)
self.delegate.setCollections(collections)
proc refreshCollectibles*(self: Controller, chainId: int, address: string) =
let collectibles = self.collectibleService.getOwnedCollectibles(chainId, address)
self.delegate.refreshCollectibles(chainId, address, collectibles)
proc refreshCollectibles*(self: Controller, chainId: int, address: string, collectionSlug: string) =
let collection = self.collectibleService.getOwnedCollection(chainId, address, collectionSlug)
self.delegate.updateCollection(collection)
proc init*(self: Controller) =
self.events.on(SIGNAL_OWNED_COLLECTIONS_UPDATED) do(e:Args):
let args = OwnedCollectionsUpdateArgs(e)
self.refreshCollections(args.chainId, args.address)
self.collectibleService.fetchAllOwnedCollectibles(args.chainId, args.address)
self.events.on(SIGNAL_OWNED_COLLECTIBLES_UPDATED) do(e:Args):
proc init*(self: Controller) =
self.events.on(SIGNAL_OWNED_COLLECTIBLES_UPDATE_FINISHED) do(e:Args):
let args = OwnedCollectiblesUpdateArgs(e)
self.refreshCollectibles(args.chainId, args.address, args.collectionSlug)
self.refreshCollectibles(args.chainId, args.address)
proc getWalletAccount*(self: Controller, accountIndex: int): wallet_account_service.WalletAccountDto =
return self.walletAccountService.getWalletAccount(accountIndex)
@ -54,8 +45,14 @@ proc getWalletAccount*(self: Controller, accountIndex: int): wallet_account_serv
proc getNetwork*(self: Controller): network_service.NetworkDto =
return self.networkService.getNetworkForCollectibles()
proc fetchOwnedCollections*(self: Controller, chainId: int, address: string) =
self.collectibleService.fetchOwnedCollections(chainId, address)
proc resetOwnedCollectibles*(self: Controller, chainId: int, address: string) =
self.collectibleService.resetOwnedCollectibles(chainId, address)
proc fetchOwnedCollectibles*(self: Controller, chainId: int, address: string, collectionSlug: string) =
self.collectibleService.fetchOwnedCollectibles(chainId, address, collectionSlug)
proc fetchOwnedCollectibles*(self: Controller, chainId: int, address: string, limit: int) =
self.collectibleService.fetchOwnedCollectibles(chainId, address, limit)
proc getCollectible*(self: Controller, chainId: int, id: UniqueID) : CollectibleDto =
self.collectibleService.getCollectible(chainId, id)
proc getCollection*(self: Controller, chainId: int, slug: string) : CollectionDto =
self.collectibleService.getCollection(chainId, slug)

View File

@ -29,6 +29,7 @@ method setCurrentAddress*(self: Controller, network: network_dto.NetworkDto, add
self.network = network
self.address = address
proc update*(self: Controller, collectionSlug: string, id: int) =
let collection = self.collectibleService.getOwnedCollection(self.network.chainId, self.address, collectionSlug)
self.delegate.setData(collection.collection, collection.collectibles[id], self.network)
proc update*(self: Controller, id: collectible_service.UniqueID) =
let collectible = self.collectibleService.getCollectible(self.network.chainId, id)
let collection = self.collectibleService.getCollection(self.network.chainId, collectible.collectionSlug)
self.delegate.setData(collection, collectible, self.network)

View File

@ -1,3 +1,4 @@
import stint
import ../../../../../../app_service/service/network/dto as network_dto
import ../../../../../../app_service/service/collectible/dto as collectible_dto
@ -17,7 +18,7 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method setCurrentAddress*(self: AccessInterface, network: network_dto.NetworkDto, address: string) {.base.} =
raise newException(ValueError, "No implementation available")
method update*(self: AccessInterface, collectionSlug: string, id: int) {.base.} =
method update*(self: AccessInterface, address: string, tokenId: Uint256) {.base.} =
raise newException(ValueError, "No implementation available")
method setData*(self: AccessInterface, collection: collectible_dto.CollectionDto, collectible: collectible_dto.CollectibleDto, network: network_dto.NetworkDto) {.base.} =

View File

@ -1,4 +1,4 @@
import NimQml, sequtils, sugar
import NimQml, sequtils, sugar, stint
import ../../../../../global/global_singleton
@ -8,6 +8,9 @@ import ../../../../../../app_service/service/collectible/service as collectible_
import ../../../../../../app_service/service/collectible/dto as collectible_dto
import ../../../../../../app_service/service/network/dto as network_dto
import ../models/collectibles_item as collectibles_item
import ../models/collectibles_utils
export io_interface
type
@ -45,8 +48,13 @@ method viewDidLoad*(self: Module) =
method setCurrentAddress*(self: Module, network: network_dto.NetworkDto, address: string) =
self.controller.setCurrentAddress(network, address)
method update*(self: Module, collectionSlug: string, id: int) =
self.controller.update(collectionSlug, id)
method update*(self: Module, address: string, tokenId: Uint256) =
let id = collectible_dto.UniqueID(
contractAddress: address,
tokenId: tokenId
)
self.controller.update(id)
method setData*(self: Module, collection: collectible_dto.CollectionDto, collectible: collectible_dto.CollectibleDto, network: network_dto.NetworkDto) =
self.view.setData(collection, collectible, network)
let item = collectibleToItem(collectible, collection)
self.view.setData(item, network)

View File

@ -2,7 +2,7 @@ import NimQml, sequtils, sugar, stint
import ./io_interface
import ../../../../../../app_service/service/network/dto as network_dto
import ../../../../../../app_service/service/collectible/dto as collectible_dto
import ../models/collectibles_item
import ../models/collectible_trait_item
import ../models/collectible_trait_model
@ -15,16 +15,7 @@ QtObject:
networkColor: string
networkIconUrl: string
collectionName: string
collectionImageUrl: string
name: string
id: string
tokenId: string
description: string
backgroundColor: string
imageUrl: string
permalink: string
collectible: Item
propertiesModel: TraitModel
rankingsModel: TraitModel
statsModel: TraitModel
@ -39,8 +30,7 @@ QtObject:
new(result, delete)
result.setup()
result.delegate = delegate
result.description = "Collectibles"
result.backgroundColor = "transparent"
result.collectible = initItem()
result.propertiesModel = newTraitModel()
result.rankingsModel = newTraitModel()
result.statsModel = newTraitModel()
@ -76,7 +66,7 @@ QtObject:
notify = networkIconUrlChanged
proc getName(self: View): QVariant {.slot.} =
return newQVariant(self.name)
return newQVariant(self.collectible.getName())
proc nameChanged(self: View) {.signal.}
@ -85,7 +75,7 @@ QtObject:
notify = nameChanged
proc getID(self: View): QVariant {.slot.} =
return newQVariant(self.id)
return newQVariant(self.collectible.getId())
proc idChanged(self: View) {.signal.}
@ -94,7 +84,7 @@ QtObject:
notify = idChanged
proc getTokenID(self: View): QVariant {.slot.} =
return newQVariant(self.tokenId)
return newQVariant(self.collectible.getTokenId().toString())
proc tokenIdChanged(self: View) {.signal.}
@ -103,7 +93,7 @@ QtObject:
notify = tokenIdChanged
proc getDescription(self: View): QVariant {.slot.} =
return newQVariant(self.description)
return newQVariant(self.collectible.getDescription())
proc descriptionChanged(self: View) {.signal.}
@ -112,7 +102,7 @@ QtObject:
notify = descriptionChanged
proc getBackgroundColor(self: View): QVariant {.slot.} =
return newQVariant(self.backgroundColor)
return newQVariant(self.collectible.getBackgroundColor())
proc backgroundColorChanged(self: View) {.signal.}
@ -121,7 +111,7 @@ QtObject:
notify = backgroundColorChanged
proc getImageUrl(self: View): QVariant {.slot.} =
return newQVariant(self.imageUrl)
return newQVariant(self.collectible.getImageUrl())
proc imageUrlChanged(self: View) {.signal.}
@ -130,7 +120,7 @@ QtObject:
notify = imageUrlChanged
proc getCollectionName(self: View): QVariant {.slot.} =
return newQVariant(self.collectionName)
return newQVariant(self.collectible.getCollectionName())
proc collectionNameChanged(self: View) {.signal.}
@ -139,7 +129,7 @@ QtObject:
notify = collectionNameChanged
proc getCollectionImageUrl(self: View): QVariant {.slot.} =
return newQVariant(self.collectionImageUrl)
return newQVariant(self.collectible.getCollectionImageUrl())
proc collectionImageUrlChanged(self: View) {.signal.}
@ -148,7 +138,7 @@ QtObject:
notify = collectionImageUrlChanged
proc getPermalink(self: View): QVariant {.slot.} =
return newQVariant(self.permalink)
return newQVariant(self.collectible.getPermalink())
proc permalinkChanged(self: View) {.signal.}
@ -179,14 +169,14 @@ QtObject:
proc getStats*(self: View): QVariant {.slot.} =
return newQVariant(self.statsModel)
QtProperty[QVariant] rankings:
QtProperty[QVariant] stats:
read = getStats
notify = statsChanged
proc update*(self: View, collectionSlug: string, id: int) {.slot.} =
self.delegate.update(collectionSlug, id)
proc update*(self: View, address: string, tokenId: string) {.slot.} =
self.delegate.update(address, parse(tokenId, Uint256))
proc setData*(self: View, collection: collectible_dto.CollectionDto, collectible: collectible_dto.CollectibleDto, network: network_dto.NetworkDto) =
proc setData*(self: View, collectible: Item, network: network_dto.NetworkDto) =
if (self.networkShortName != network.shortName):
self.networkShortName = network.shortName
self.networkShortNameChanged()
@ -199,46 +189,21 @@ QtObject:
self.networkIconUrl = network.iconURL
self.networkIconUrlChanged()
if (self.collectionName != collection.name):
self.collectionName = collection.name
self.collectionNameChanged()
self.collectible = collectible
self.collectionNameChanged()
self.collectionImageUrlChanged()
self.nameChanged()
self.idChanged()
self.tokenIdChanged()
self.descriptionChanged()
self.backgroundColorChanged()
self.imageUrlChanged()
if (self.collectionImageUrl != collection.imageUrl):
self.collectionImageUrl = collection.imageUrl
self.collectionImageUrlChanged()
if (self.name != collectible.name):
self.name = collectible.name
self.nameChanged()
let idString = $collectible.id
if (self.id != idString):
self.id = idString
self.idChanged()
let tokenIdString = collectible.tokenId.toString()
if (self.tokenId != tokenIdString):
self.tokenId = tokenIdString
self.tokenIdChanged()
if (self.description != collectible.description):
self.description = collectible.description
self.descriptionChanged()
let backgroundColor = if (collectible.backgroundColor == ""): "transparent" else: ("#" & collectible.backgroundColor)
if (self.backgroundColor != backgroundColor):
self.backgroundColor = backgroundColor
self.backgroundColorChanged()
if (self.imageUrl != collectible.imageUrl):
self.imageUrl = collectible.imageUrl
self.imageUrlChanged()
self.propertiesModel.setItems(collectible.properties.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)))
self.propertiesModel.setItems(collectible.getProperties())
self.propertiesChanged()
self.rankingsModel.setItems(collectible.rankings.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)))
self.rankingsModel.setItems(collectible.getRankings())
self.rankingsChanged()
self.statsModel.setItems(collectible.statistics.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)))
self.statsModel.setItems(collectible.getStats())
self.statsChanged()

View File

@ -16,16 +16,10 @@ method isLoaded*(self: AccessInterface): bool {.base.} =
method switchAccount*(self: AccessInterface, accountIndex: int) {.base.} =
raise newException(ValueError, "No implementation available")
method fetchOwnedCollections*(self: AccessInterface) {.base.} =
method fetchOwnedCollectibles*(self: AccessInterface, limit: int) {.base.} =
raise newException(ValueError, "No implementation available")
method setCollections*(self: AccessInterface, collections: CollectionsData) {.base.} =
raise newException(ValueError, "No implementation available")
method fetchOwnedCollectibles*(self: AccessInterface, collectionSlug: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateCollection*(self: AccessInterface, collection: CollectionData) {.base.} =
method refreshCollectibles*(self: AccessInterface, chainId: int, address: string, collectibles: CollectiblesData) {.base.} =
raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} =
@ -35,8 +29,5 @@ method viewDidLoad*(self: AccessInterface) {.base.} =
method collectiblesModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method collectionsModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method currentCollectibleModuleDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -1,221 +0,0 @@
import NimQml, Tables, strutils
import ./collections_model as collections_model
import ./collectibles_model as collectibles_model
type
ModelRole* {.pure.} = enum
CollectionName = UserRole + 1,
CollectionSlug
CollectionImageUrl
CollectionOwnedAssetCount
CollectionCollectiblesCount
CollectionCollectiblesLoaded
Id
Name
ImageUrl
BackgroundColor
Description
Permalink
Properties
Rankings
Stats
const COLLECTION_ROLE_TO_PROXY_ROLE = {
CollectionRole.Name: ModelRole.CollectionName,
CollectionRole.Slug: ModelRole.CollectionSlug,
CollectionRole.ImageUrl: ModelRole.CollectionImageUrl,
CollectionRole.OwnedAssetCount: ModelRole.CollectionOwnedAssetCount,
CollectionRole.CollectiblesLoaded: ModelRole.CollectionCollectiblesLoaded,
}.toTable()
const COLLECTIBLE_ROLE_TO_PROXY_ROLE = {
CollectibleRole.Id: ModelRole.Id,
CollectibleRole.Name: ModelRole.Name,
CollectibleRole.ImageUrl: ModelRole.ImageUrl,
CollectibleRole.BackgroundColor: ModelRole.BackgroundColor,
CollectibleRole.Description: ModelRole.Description,
CollectibleRole.Permalink: ModelRole.Permalink,
CollectibleRole.Properties: ModelRole.Properties,
CollectibleRole.Rankings: ModelRole.Rankings,
CollectibleRole.Stats: ModelRole.Stats,
}.toTable()
type
Index = tuple
collectionIdx: int
collectibleIdx: int
QtObject:
type
Model* = ref object of QAbstractListModel
collectionsModel: collections_model.Model
sourceIndexToRow: Table[Index, int]
collectionToRows: Table[int, (int, int)]
rowToSourceIndex: Table[int, Index]
proc delete(self: Model) =
self.collectionsModel = nil
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
proc countChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
self.sourceIndexToRow.len
QtProperty[int] count:
read = getCount
notify = countChanged
proc collectionsLoadedChanged(self: Model) {.signal.}
proc getCollectionsLoaded*(self: Model): bool {.slot.} =
self.collectionsModel.getCollectionsLoaded()
QtProperty[bool] collectionsLoaded:
read = getCollectionsLoaded
notify = collectionsLoadedChanged
proc collectionCountChanged(self: Model) {.signal.}
proc getCollectionCount*(self: Model): int {.slot.} =
self.collectionsModel.getCount()
QtProperty[int] collectionCount:
read = getCollectionCount
notify = collectionCountChanged
proc rebuildMap(self: Model) =
self.beginResetModel()
self.sourceIndexToRow.clear()
self.collectionToRows.clear()
self.rowToSourceIndex.clear()
var proxy_row = 0
for i in 0 ..< self.collectionsModel.getCount():
let collectiblesModel = self.collectionsModel.getCollectiblesModel(i)
let collectionIndexStart = proxy_row
for j in 0 ..< collectiblesModel.getCount():
let idx = (collectionIdx: i, collectibleIdx: j)
self.sourceIndexToRow[idx] = proxy_row
self.rowToSourceIndex[proxy_row] = idx
proxy_row += 1
self.collectionToRows[i] = (collectionIndexStart, proxy_row - 1)
self.endResetModel()
self.countChanged()
proc newModel*(collectionsModel: collections_model.Model): Model =
new(result, delete)
result.collectionsModel = collectionsModel
result.setup
result.rebuildMap()
signalConnect(result.collectionsModel, "collectionsLoadedChanged()", result, "onCollectionsLoadedChanged()")
signalConnect(result.collectionsModel, "countChanged()", result, "onCollectionCountChanged()")
signalConnect(result.collectionsModel, "signalDataChanged(int, int, int)", result, "onDataChanged(int, int, int)")
proc onCollectionsLoadedChanged(self: Model) {.slot.} =
self.collectionsLoadedChanged()
proc onCollectionCountChanged(self: Model) {.slot.} =
self.collectionCountChanged()
self.rebuildMap()
proc onDataChanged(self: Model,
top: int,
bottom: int,
role: int) {.slot.} =
var topRow = self.collectionToRows[top][0]
var bottomRow = self.collectionToRows[bottom][1]
let topIndex = self.createIndex(topRow, 0, nil)
let bottomIndex = self.createIndex(bottomRow, 0, nil)
if (COLLECTION_ROLE_TO_PROXY_ROLE.hasKey(role.CollectionRole)):
self.dataChanged(topIndex, bottomIndex, @[COLLECTION_ROLE_TO_PROXY_ROLE[role.CollectionRole].int])
elif role == CollectionRole.CollectiblesModel.int:
self.rebuildMap()
method rowCount*(self: Model, index: QModelIndex = nil): int =
return self.getCount()
method roleNames(self: Model): Table[int, string] =
{
ModelRole.CollectionName.int:"collectionName",
ModelRole.CollectionSlug.int:"collectionSlug",
ModelRole.CollectionImageUrl.int:"collectionImageUrl",
ModelRole.CollectionOwnedAssetCount.int:"collectionOwnedAssetCount",
ModelRole.CollectionCollectiblesCount.int:"collectionCollectiblesCount",
ModelRole.CollectionCollectiblesLoaded.int:"collectionCollectiblesLoaded",
ModelRole.Id.int:"id",
ModelRole.Name.int:"name",
ModelRole.ImageUrl.int:"imageUrl",
ModelRole.BackgroundColor.int:"backgroundColor",
ModelRole.Description.int:"description",
ModelRole.Permalink.int:"permalink",
ModelRole.Properties.int:"properties",
ModelRole.Rankings.int:"rankings",
ModelRole.Stats.int:"stats",
}.toTable
proc mapFromSource(self: Model, index: Index): QModelIndex =
if not self.sourceIndexToRow.hasKey(index):
return QModelIndex()
let proxyIndex = self.sourceIndexToRow[index]
return self.createIndex(proxyIndex, 0, nil)
proc mapToSource(self: Model, index: QModelIndex): Index =
if not self.rowToSourceIndex.hasKey(index.row):
return (collectionIdx: -1, collectibleIdx: -1)
return self.rowToSourceIndex[index.row]
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.getCount()):
return
let sourceIndex = self.mapToSource(index)
let collectionIndex = self.collectionsModel.createIndex(sourceIndex.collectionIdx, 0, nil)
let enumRole = role.ModelRole
case enumRole:
of ModelRole.CollectionName:
result = self.collectionsModel.data(collectionIndex, CollectionRole.Name.int)
of ModelRole.CollectionSlug:
result = self.collectionsModel.data(collectionIndex, CollectionRole.Slug.int)
of ModelRole.CollectionImageUrl:
result = self.collectionsModel.data(collectionIndex, CollectionRole.ImageUrl.int)
of ModelRole.CollectionOwnedAssetCount:
result = self.collectionsModel.data(collectionIndex, CollectionRole.OwnedAssetCount.int)
of ModelRole.CollectionCollectiblesLoaded:
result = self.collectionsModel.data(collectionIndex, CollectionRole.CollectiblesLoaded.int)
else:
let collectiblesModel = self.collectionsModel.getCollectiblesModel(sourceIndex.collectionIdx)
let collectibleIndex = collectiblesModel.createIndex(sourceIndex.collectibleIdx, 0, nil)
case enumRole:
of ModelRole.CollectionCollectiblesCount:
result = newQVariant(collectiblesModel.getCount())
of ModelRole.Id:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Id.int)
of ModelRole.Name:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Name.int)
of ModelRole.ImageUrl:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.ImageUrl.int)
of ModelRole.BackgroundColor:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.BackgroundColor.int)
of ModelRole.Description:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Description.int)
of ModelRole.Permalink:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Permalink.int)
of ModelRole.Properties:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Properties.int)
of ModelRole.Rankings:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Rankings.int)
of ModelRole.Stats:
result = collectiblesModel.data(collectibleIndex, CollectibleRole.Stats.int)
else:
return
proc data*(self: Model, row: int, role: ModelRole): QVariant =
return self.data(self.createIndex(row, 0, nil), role.int)

View File

@ -4,6 +4,7 @@ import ./collectible_trait_item
type
Item* = object
id: int
address: string
tokenId: UInt256
name: string
imageUrl: string
@ -13,9 +14,14 @@ type
properties: seq[CollectibleTrait]
rankings: seq[CollectibleTrait]
stats: seq[CollectibleTrait]
collectionName: string
collectionSlug: string
collectionImageUrl: string
isLoading: bool
proc initItem*(
id: int,
address: string,
tokenId: UInt256,
name: string,
imageUrl: string,
@ -24,11 +30,15 @@ proc initItem*(
permalink: string,
properties: seq[CollectibleTrait],
rankings: seq[CollectibleTrait],
stats: seq[CollectibleTrait]
stats: seq[CollectibleTrait],
collectionName: string,
collectionSlug: string,
collectionImageUrl: string
): Item =
result.id = id
result.address = address
result.tokenId = tokenId
result.name = name
result.name = if (name != ""): name else: ("#" & tokenId.toString())
result.imageUrl = imageUrl
result.backgroundColor = if (backgroundColor == ""): "transparent" else: ("#" & backgroundColor)
result.description = description
@ -36,24 +46,39 @@ proc initItem*(
result.properties = properties
result.rankings = rankings
result.stats = stats
result.collectionName = collectionName
result.collectionSlug = collectionSlug
result.collectionImageUrl = collectionImageUrl
result.isLoading = false
proc initItem*: Item =
result = initItem(-1, u256(0), "", "", "transparent", "Collectibles", "", @[], @[], @[])
result = initItem(-1, "", u256(0), "", "", "transparent", "Collectibles", "", @[], @[], @[], "", "", "")
proc initLoadingItem*: Item =
result = initItem()
result.isLoading = true
proc `$`*(self: Item): string =
result = fmt"""Collectibles(
id: {self.id},
address: {self.address},
tokenId: {self.tokenId},
name: {self.name},
imageUrl: {self.imageUrl},
backgroundColor: {self.backgroundColor},
description: {self.description},
permalink: {self.permalink},
collectionName: {self.collectionName},
collectionSlug: {self.collectionSlug},
collectionImageUrl: {self.collectionImageUrl},
]"""
proc getId*(self: Item): int =
return self.id
proc getAddress*(self: Item): string =
return self.address
proc getTokenId*(self: Item): UInt256 =
return self.tokenId
@ -80,3 +105,15 @@ proc getRankings*(self: Item): seq[CollectibleTrait] =
proc getStats*(self: Item): seq[CollectibleTrait] =
return self.stats
proc getCollectionName*(self: Item): string =
return self.collectionName
proc getCollectionSlug*(self: Item): string =
return self.collectionSlug
proc getCollectionImageUrl*(self: Item): string =
return self.collectionImageUrl
proc getIsLoading*(self: Item): bool =
return self.isLoading

View File

@ -5,6 +5,7 @@ import ./collectibles_item, ./collectible_trait_model
type
CollectibleRole* {.pure.} = enum
Id = UserRole + 1,
Address
TokenId
Name
ImageUrl
@ -14,11 +15,23 @@ type
Properties
Rankings
Stats
CollectionName
CollectionSlug
CollectionImageUrl
IsLoading
# Maximum number of owned collectibles to be fetched at a time
const ownedCollectiblesFetchLimit = 200
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[Item]
allCollectiblesLoaded: bool
isFetching: bool
proc addLoadingItems(self: Model)
proc removeLoadingItems(self: Model)
proc delete(self: Model) =
self.items = @[]
@ -27,13 +40,12 @@ QtObject:
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(items: seq[Item]): Model =
proc newModel*(): Model =
new(result, delete)
result.setup
result.items = items
proc newModel*(): Model =
return newModel(@[])
result.items = @[]
result.allCollectiblesLoaded = false
result.isFetching = true
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
@ -46,12 +58,50 @@ QtObject:
read = getCount
notify = countChanged
proc isFetchingChanged(self: Model) {.signal.}
proc getIsFetching*(self: Model): bool {.slot.} =
self.isFetching
QtProperty[bool] isFetching:
read = getIsFetching
notify = isFetchingChanged
proc setIsFetching(self: Model, value: bool) =
if value == self.isFetching:
return
if value:
self.addLoadingItems()
else:
self.removeLoadingItems()
self.isFetching = value
self.isFetchingChanged()
proc allCollectiblesLoadedChanged(self: Model) {.signal.}
proc getAllCollectiblesLoaded*(self: Model): bool {.slot.} =
self.allCollectiblesLoaded
QtProperty[bool] allCollectiblesLoaded:
read = getAllCollectiblesLoaded
notify = allCollectiblesLoadedChanged
proc setAllCollectiblesLoaded*(self: Model, value: bool) =
if value == self.allCollectiblesLoaded:
return
self.allCollectiblesLoaded = value
self.allCollectiblesLoadedChanged()
method canFetchMore*(self: Model, parent: QModelIndex): bool =
return not self.allCollectiblesLoaded and not self.isFetching
proc requestFetch(self: Model, limit: int) {.signal.}
method fetchMore*(self: Model, parent: QModelIndex) =
if not self.isFetching:
self.setIsFetching(true)
self.requestFetch(ownedCollectiblesFetchLimit)
method rowCount*(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
{
CollectibleRole.Id.int:"id",
CollectibleRole.Address.int:"address",
CollectibleRole.TokenId.int:"tokenId",
CollectibleRole.Name.int:"name",
CollectibleRole.ImageUrl.int:"imageUrl",
@ -61,6 +111,10 @@ QtObject:
CollectibleRole.Properties.int:"properties",
CollectibleRole.Rankings.int:"rankings",
CollectibleRole.Stats.int:"stats",
CollectibleRole.CollectionName.int:"collectionName",
CollectibleRole.CollectionSlug.int:"collectionSlug",
CollectibleRole.CollectionImageUrl.int:"collectionImageUrl",
CollectibleRole.IsLoading.int:"isLoading",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -76,6 +130,8 @@ QtObject:
case enumRole:
of CollectibleRole.Id:
result = newQVariant(item.getId())
of CollectibleRole.Address:
result = newQVariant(item.getAddress())
of CollectibleRole.TokenId:
result = newQVariant(item.getTokenId().toString())
of CollectibleRole.Name:
@ -100,15 +156,45 @@ QtObject:
let traits = newTraitModel()
traits.setItems(item.getStats())
result = newQVariant(traits)
of CollectibleRole.CollectionName:
result = newQVariant(item.getCollectionName())
of CollectibleRole.CollectionSlug:
result = newQVariant(item.getCollectionSlug())
of CollectibleRole.CollectionImageUrl:
result = newQVariant(item.getCollectionImageUrl())
of CollectibleRole.IsLoading:
result = newQVariant(item.getIsLoading())
proc getItem*(self: Model, index: int): Item =
return self.items[index]
proc addLoadingItems(self: Model) =
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
self.endResetModel()
let loadingItem = initLoadingItem()
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len + ownedCollectiblesFetchLimit - 1)
for i in 1..ownedCollectiblesFetchLimit:
self.items.add(loadingItem)
self.endInsertRows()
self.countChanged()
proc appendItems*(self: Model, items: seq[Item]) =
self.setItems(concat(self.items, items))
proc removeLoadingItems(self: Model) =
for i in 0 ..< self.items.len:
if self.items[i].getIsLoading():
self.beginRemoveRows(newQModelIndex(), i, self.items.len-1)
self.items.delete(i, self.items.len-1)
self.endRemoveRows()
self.countChanged()
return
proc setItems*(self: Model, items: seq[Item], append: bool) =
self.setIsFetching(false)
if append:
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
self.beginInsertRows(parentModelIndex, self.items.len, self.items.len + items.len - 1)
self.items = concat(self.items, items)
self.endInsertRows()
else:
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()

View File

@ -2,9 +2,10 @@ import sequtils, sugar
import ../../../../../../app_service/service/collectible/dto
import collectibles_item, collectible_trait_item
proc collectibleToItem*(c: CollectibleDto) : Item =
proc collectibleToItem*(c: CollectibleDto, co: CollectionDto) : Item =
return initItem(
c.id,
c.address,
c.tokenId,
c.name,
c.imageUrl,
@ -13,5 +14,8 @@ proc collectibleToItem*(c: CollectibleDto) : Item =
c.permalink,
c.properties.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)),
c.rankings.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)),
c.statistics.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue))
c.statistics.map(t => initTrait(t.traitType, t.value, t.displayType, t.maxValue)),
co.name,
co.slug,
co.imageUrl
)

View File

@ -1,51 +0,0 @@
import strformat, stint
import ./collectibles_model as collectibles_model
import ./collectibles_item as collectibles_item
type
Item* = object
name: string
slug: string
imageUrl: string
ownedAssetCount: Uint256
collectiblesLoaded*: bool
collectiblesModel: collectibles_model.Model
proc initItem*(name, slug, imageUrl: string, ownedAssetCount: Uint256, collectiblesLoaded: bool, collectibles: seq[collectibles_item.Item]): Item =
result.name = name
result.slug = slug
result.imageUrl = imageUrl
result.ownedAssetCount = ownedAssetCount
result.collectiblesLoaded = collectiblesLoaded
result.collectiblesModel = collectibles_model.newModel(collectibles)
proc initItem*(): Item =
result = initItem("", "", "", u256(0), false, @[])
proc `$`*(self: Item): string =
result = fmt"""CollectibleCollection(
name: {self.name},
slug: {self.slug},
imageUrl: {self.imageUrl},
ownedAssetCount: {self.ownedAssetCount},
collectiblesLoaded: {self.collectiblesLoaded},
collectibles: {self.collectiblesModel}
]"""
proc getName*(self: Item): string =
return self.name
proc getSlug*(self: Item): string =
return self.slug
proc getImageUrl*(self: Item): string =
return self.imageUrl
proc getOwnedAssetCount*(self: Item): Uint256 =
return self.ownedAssetCount
proc getCollectiblesLoaded*(self: Item): bool =
return self.collectiblesLoaded
proc getCollectiblesModel*(self: Item): collectibles_model.Model =
return self.collectiblesModel

View File

@ -1,131 +0,0 @@
import NimQml, Tables, strutils, strformat, stint
import ./collections_item as collections_item
import ./collectibles_model as collectibles_model
import ./collectibles_item as collectibles_item
type
CollectionRole* {.pure.} = enum
Name = UserRole + 1,
Slug
ImageUrl
OwnedAssetCount
CollectiblesLoaded
CollectiblesModel
QtObject:
type
Model* = ref object of QAbstractListModel
items: seq[collections_item.Item]
collectionsLoaded: bool
proc delete(self: Model) =
self.items = @[]
self.QAbstractListModel.delete
proc setup(self: Model) =
self.QAbstractListModel.setup
self.collectionsLoaded = false
proc newModel*(): Model =
new(result, delete)
result.setup
proc `$`*(self: Model): string =
for i in 0 ..< self.items.len:
result &= fmt"""[{i}]:({$self.items[i]})"""
proc countChanged(self: Model) {.signal.}
proc getCount*(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
proc collectionsLoadedChanged(self: Model) {.signal.}
proc getCollectionsLoaded*(self: Model): bool {.slot.} =
self.collectionsLoaded
QtProperty[bool] collectionsLoaded:
read = getCollectionsLoaded
notify = collectionsLoadedChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
{
CollectionRole.Name.int:"name",
CollectionRole.Slug.int:"slug",
CollectionRole.ImageUrl.int:"imageUrl",
CollectionRole.OwnedAssetCount.int:"ownedAssetCount",
CollectionRole.CollectiblesLoaded.int:"collectiblesLoaded",
CollectionRole.CollectiblesModel.int:"collectiblesModel"
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
if (not index.isValid):
return
if (index.row < 0 or index.row >= self.items.len):
return
let item = self.items[index.row]
let enumRole = role.CollectionRole
case enumRole:
of CollectionRole.Name:
result = newQVariant(item.getName())
of CollectionRole.Slug:
result = newQVariant(item.getSlug())
of CollectionRole.ImageUrl:
result = newQVariant(item.getImageUrl())
of CollectionRole.OwnedAssetCount:
result = newQVariant(item.getOwnedAssetCount().toString())
of CollectionRole.CollectiblesLoaded:
result = newQVariant(item.getCollectiblesLoaded())
of CollectionRole.CollectiblesModel:
result = newQVariant(item.getCollectiblesModel())
proc setCollections*(self: Model, items: seq[collections_item.Item], collectionsLoaded: bool) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
if self.collectionsLoaded != collectionsLoaded:
self.collectionsLoaded = collectionsLoaded
self.collectionsLoadedChanged()
proc getCollectionItem*(self: Model, index: int) : collections_item.Item =
return self.items[index]
proc getCollectiblesModel*(self: Model, index: int) : collectibles_model.Model =
if index < self.items.len:
return self.items[index].getCollectiblesModel()
echo "getCollectiblesModel: Invalid index ", index, " with len ", self.items.len
return collectibles_model.newModel()
proc findIndexBySlug(self: Model, slug: string): int =
for i in 0 ..< self.items.len:
if self.items[i].getSlug() == slug:
return i
return -1
proc signalDataChanged(self: Model, top: int, bottom: int, roles: int) {.signal.}
proc emitDataChanged(self: Model, top: int, bottom: int, role: int) =
let topIndex = self.createIndex(top, 0, nil)
let bottomIndex = self.createIndex(bottom, 0, nil)
self.dataChanged(topIndex, bottomIndex, @[role])
self.signalDataChanged(top, bottom, role)
proc updateCollectionCollectibles*(self: Model, slug: string, collectibles: seq[collectibles_item.Item], collectiblesLoaded: bool) =
let idx = self.findIndexBySlug(slug)
if idx > -1:
let collectiblesModel = self.items[idx].getCollectiblesModel()
collectiblesModel.setItems(collectibles)
self.emitDataChanged(idx, idx, CollectionRole.CollectiblesModel.int)
if self.items[idx].getCollectiblesLoaded() != collectiblesLoaded:
self.items[idx].collectiblesLoaded = collectiblesLoaded
self.emitDataChanged(idx, idx, CollectionRole.CollectiblesLoaded.int)

View File

@ -1,13 +0,0 @@
import sequtils, sugar, Tables
import ../../../../../../app_service/service/collectible/service
import collections_item, collectibles_utils
proc collectionToItem*(collection: CollectionData) : Item =
return initItem(
collection.collection.name,
collection.collection.slug,
collection.collection.imageUrl,
collection.collection.ownedAssetCount,
collection.collectiblesLoaded,
toSeq(collection.collectibles.values).map(c => collectibleToItem(c))
)

View File

@ -11,8 +11,6 @@ import ../../../../../app_service/service/network/service as network_service
import ./current_collectible/module as current_collectible_module
import ./models/collections_item as collections_item
import ./models/collections_utils
import ./models/collectibles_item as collectibles_item
import ./models/collectible_trait_item as collectible_trait_item
import ./models/collectibles_utils
@ -45,7 +43,6 @@ proc newModule*(
result.moduleLoaded = false
result.currentCollectibleModule = currentCollectibleModule.newModule(result, collectibleService)
method delete*(self: Module) =
self.view.delete
self.currentCollectibleModule.delete
@ -76,6 +73,9 @@ method viewDidLoad*(self: Module) =
method currentCollectibleModuleDidLoad*(self: Module) =
self.checkIfModuleDidLoad()
method fetchOwnedCollectibles*(self: Module, limit: int) =
self.controller.fetchOwnedCollectibles(self.chainId, self.address, limit)
method switchAccount*(self: Module, accountIndex: int) =
let network = self.controller.getNetwork()
let account = self.controller.getWalletAccount(accountIndex)
@ -83,40 +83,30 @@ method switchAccount*(self: Module, accountIndex: int) =
self.chainId = network.chainId
self.address = account.address
self.controller.refreshCollections(self.chainId, self.address)
self.controller.fetchOwnedCollections(self.chainId, self.address)
# TODO: Implement a way to reduce the number of full re-fetches. It could be only
# when NFT activity was detected for the given account, or if a certain amount of
# time has passed. For now, we fetch every time we select the account.
self.controller.resetOwnedCollectibles(self.chainId, self.address)
self.controller.refreshCollectibles(self.chainId, self.address)
self.currentCollectibleModule.setCurrentAddress(network, self.address)
proc collectionToItem(self: Module, collection: CollectionData) : collections_item.Item =
var item = collectionToItem(collection)
#[ Skeleton items are disabled until problem with OpenSea API is researched.
OpenSea is telling us the address owns a certain amount of NFTs from a certain collection, but
it doesn't give us the NFTs from that collection when trying to fetch them.
# Append skeleton collectibles if not yet fetched
let model = item.getCollectiblesModel()
let unfetchedCollectiblesCount = item.getOwnedAssetCount() - model.getCount()
if unfetchedCollectiblesCount > 0:
echo "unfetchedCollectiblesCount = ", unfetchedCollectiblesCount, " ", item.getSlug()
let skeletonItems = newSeqWith(unfetchedCollectiblesCount, collectibles_item.initItem())
model.appendItems(skeletonItems)
]#
return item
method refreshCollectibles*(self: Module, chainId: int, address: string, collectibles: CollectiblesData) =
if self.chainId == chainId and self.address == address:
var idsToAdd = newSeq[UniqueID]()
let append = not collectibles.lastLoadWasFromStart
method setCollections*(self: Module, collections: CollectionsData) =
self.view.setCollections(
toSeq(collections.collections.values).map(c => self.collectionToItem(c)),
collections.collectionsLoaded
)
var startIdx = 0
if append:
for i in collectibles.ids.len - collectibles.lastLoadCount ..< collectibles.ids.len:
idsToAdd.add(collectibles.ids[i])
else:
idsToAdd = collectibles.ids
method updateCollection*(self: Module, collection: CollectionData) =
self.view.setCollectibles(collection.collection.slug,
toSeq(collection.collectibles.values).map(c => collectibleToItem(c)),
collection.collectiblesLoaded
)
method fetchOwnedCollections*(self: Module) =
self.controller.fetchOwnedCollections(self.chainId, self.address)
method fetchOwnedCollectibles*(self: Module, collectionSlug: string) =
self.controller.fetchOwnedCollectibles(self.chainId, self.address, collectionSlug)
var newCollectibles = idsToAdd.map(id => (block:
let c = self.controller.getCollectible(self.chainId, id)
let co = self.controller.getCollection(self.chainId, c.collectionSlug)
return collectibleToItem(c, co)
))
self.view.setCollectibles(newCollectibles, append, collectibles.allLoaded)

View File

@ -1,20 +1,16 @@
import NimQml
import ./models/collections_model as collections_model
import ./models/collectibles_flat_proxy_model as flat_model
import ./models/collections_item as collections_item
import ./models/collectibles_item as collectibles_item
import ./models/collectibles_model
import ./models/collectibles_item
import ./io_interface
QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
model: collections_model.Model
flatModel: flat_model.Model
model: Model
proc delete*(self: View) =
self.flatModel.delete
self.model.delete
self.QObject.delete
@ -23,7 +19,7 @@ QtObject:
result.QObject.setup
result.delegate = delegate
result.model = newModel()
result.flatModel = flat_model.newModel(result.model)
signalConnect(result.model, "requestFetch(int)", result, "fetchMoreOwnedCollectibles(int)")
proc load*(self: View) =
self.delegate.viewDidLoad()
@ -35,21 +31,9 @@ QtObject:
read = getModel
notify = modelChanged
proc flatModelChanged*(self: View) {.signal.}
proc getFlatModel(self: View): QVariant {.slot.} =
return newQVariant(self.flatModel)
QtProperty[QVariant] flatModel:
read = getFlatModel
notify = flatModelChanged
proc fetchMoreOwnedCollectibles*(self: View, limit: int) {.slot.} =
self.delegate.fetchOwnedCollectibles(limit)
proc fetchOwnedCollections*(self: View) {.slot.} =
self.delegate.fetchOwnedCollections()
proc fetchOwnedCollectibles*(self: View, collectionSlug: string) {.slot.} =
self.delegate.fetchOwnedCollectibles(collectionSlug)
proc setCollections*(self: View, collections: seq[collections_item.Item], collectionsLoaded: bool) =
self.model.setCollections(collections, collectionsLoaded)
proc setCollectibles*(self: View, collectionsSlug: string, collectibles: seq[collectibles_item.Item], collectiblesLoaded: bool) =
self.model.updateCollectionCollectibles(collectionsSlug, collectibles, collectiblesLoaded)
proc setCollectibles*(self: View, collectibles: seq[Item], append: bool, allLoaded: bool) =
self.model.setItems(collectibles, append)
self.model.setAllCollectiblesLoaded(allLoaded)

View File

@ -1,28 +1,8 @@
type
FetchOwnedCollectionsTaskArg = ref object of QObjectTaskArg
chainId*: int
address*: string
const fetchOwnedCollectionsTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[FetchOwnedCollectionsTaskArg](argEncoded)
let output = %* {
"chainId": arg.chainId,
"address": arg.address,
"collections": ""
}
try:
let response = collectibles.getOpenseaCollectionsByOwner(arg.chainId, arg.address)
output["collections"] = response.result
except Exception as e:
let errDesription = e.msg
error "error fetchOwnedCollectionsTaskArg: ", errDesription
arg.finish(output)
type
FetchOwnedCollectiblesTaskArg = ref object of QObjectTaskArg
chainId*: int
address*: string
collectionSlug: string
cursor: string
limit: int
const fetchOwnedCollectiblesTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
@ -30,11 +10,11 @@ const fetchOwnedCollectiblesTaskArg: Task = proc(argEncoded: string) {.gcsafe, n
let output = %* {
"chainId": arg.chainId,
"address": arg.address,
"collectionSlug": arg.collectionSlug,
"cursor": arg.cursor,
"collectibles": ""
}
try:
let response = collectibles.getOpenseaAssetsByOwnerAndCollection(arg.chainId, arg.address, arg.collectionSlug, arg.limit)
let response = collectibles.getOpenseaAssetsByOwnerWithCursor(arg.chainId, arg.address, arg.cursor, arg.limit)
output["collectibles"] = response.result
except Exception as e:
let errDesription = e.msg

View File

@ -1,5 +1,10 @@
import json, Tables, stint, strformat, strutils
# Unique identifier for collectible on a specific chain
type
UniqueID* = object
contractAddress*: string
tokenId*: UInt256
type CollectibleTraitType* {.pure.} = enum
Properties = 0,
@ -11,7 +16,6 @@ type CollectionTrait* = ref object
type CollectionDto* = ref object
name*, slug*, imageUrl*: string
ownedAssetCount*: Uint256
trait*: Table[string, CollectionTrait]
type CollectibleTrait* = ref object
@ -20,7 +24,7 @@ type CollectibleTrait* = ref object
type CollectibleDto* = ref object
id*: int
tokenId*: Uint256
name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, address*, backgroundColor*: string
address*, collectionSlug*, name*, description*, permalink*, imageThumbnailUrl*, imageUrl*, backgroundColor*: string
properties*, rankings*, statistics*: seq[CollectibleTrait]
proc newCollectibleDto*: CollectibleDto =
@ -31,6 +35,14 @@ proc newCollectibleDto*: CollectibleDto =
proc isValid*(self: CollectibleDto): bool =
return self.id >= 0
proc newCollectionDto*: CollectionDto =
return CollectionDto(
slug: ""
)
proc isValid*(self: CollectionDto): bool =
return self.slug != ""
proc isNumeric(s: string): bool =
try:
discard s.parseFloat()
@ -39,14 +51,14 @@ proc isNumeric(s: string): bool =
result = false
proc `$`*(self: CollectionDto): string =
return fmt"CollectionDto(name:{self.name}, slug:{self.slug}, owned asset count:{self.ownedAssetCount})"
return fmt"CollectionDto(name:{self.name}, slug:{self.slug})"
proc `$`*(self: CollectibleDto): string =
return fmt"CollectibleDto(id:{self.id}, token_id:{self.tokenId}, name:{self.name}, description:{self.description}, permalink:{self.permalink}, address:{self.address}, imageUrl: {self.imageUrl}, imageThumbnailUrl: {self.imageThumbnailUrl}, backgroundColor: {self.backgroundColor})"
return fmt"CollectibleDto(id:{self.id}, address:{self.address}, tokenId:{self.tokenId}, collectionSlug:{self.collectionSlug}, name:{self.name}, description:{self.description}, permalink:{self.permalink}, imageUrl: {self.imageUrl}, imageThumbnailUrl: {self.imageThumbnailUrl}, backgroundColor: {self.backgroundColor})"
proc getCollectionTraits*(jsonCollection: JsonNode): Table[string, CollectionTrait] =
var traitList: Table[string, CollectionTrait] = initTable[string, CollectionTrait]()
for key, value in jsonCollection{"traits"}:
for key, value in jsonCollection{"traits"}.getFields():
traitList[key] = CollectionTrait(min: value{"min"}.getFloat, max: value{"max"}.getFloat)
return traitList
@ -55,7 +67,6 @@ proc toCollectionDto*(jsonCollection: JsonNode): CollectionDto =
name: jsonCollection{"name"}.getStr,
slug: jsonCollection{"slug"}.getStr,
imageUrl: jsonCollection{"image_url"}.getStr,
ownedAssetCount: stint.parse(jsonCollection{"owned_asset_count"}.getStr, Uint256),
trait: getCollectionTraits(jsonCollection)
)
@ -79,13 +90,14 @@ proc getTrait*(jsonAsset: JsonNode, traitType: CollectibleTraitType): seq[Collec
proc toCollectibleDto*(jsonAsset: JsonNode): CollectibleDto =
return CollectibleDto(
id: jsonAsset{"id"}.getInt,
address: jsonAsset{"asset_contract"}{"address"}.getStr,
tokenId: stint.parse(jsonAsset{"token_id"}.getStr, Uint256),
collectionSlug: jsonAsset{"collection"}{"slug"}.getStr,
name: jsonAsset{"name"}.getStr,
description: jsonAsset{"description"}.getStr,
permalink: jsonAsset{"permalink"}.getStr,
imageThumbnailUrl: jsonAsset{"image_thumbnail_url"}.getStr,
imageUrl: jsonAsset{"image_url"}.getStr,
address: jsonAsset{"asset_contract"}{"address"}.getStr,
backgroundColor: jsonAsset{"background_color"}.getStr,
properties: getTrait(jsonAsset, CollectibleTraitType.Properties),
rankings: getTrait(jsonAsset, CollectibleTraitType.Rankings),

View File

@ -1,4 +1,4 @@
import NimQml, Tables, chronicles, sequtils, json, sugar, stint, hashes
import NimQml, Tables, chronicles, sequtils, json, sugar, stint, hashes, strformat, times
import ../../../app/core/eventemitter
import ../../../app/core/tasks/[qt, threadpool]
@ -16,29 +16,14 @@ logScope:
topics = "collectible-service"
# Signals which may be emitted by this service:
const SIGNAL_OWNED_COLLECTIONS_UPDATED* = "ownedCollectionsUpdated"
const SIGNAL_OWNED_COLLECTIBLES_UPDATED* = "ownedCollectiblesUpdated"
const SIGNAL_OWNED_COLLECTIBLES_UPDATE_STARTED* = "ownedCollectiblesUpdateStarted"
const SIGNAL_OWNED_COLLECTIBLES_UPDATE_FINISHED* = "ownedCollectiblesUpdateFinished"
const SIGNAL_COLLECTIBLES_UPDATED* = "collectiblesUpdated"
# Maximum number of collectibles to be fetched at a time
const limit = 200
# Unique identifier for collectible in a specific chain
type
UniqueID* = object
contractAddress*: string
tokenId*: UInt256
type
OwnedCollectionsUpdateArgs* = ref object of Args
chainId*: int
address*: string
type
OwnedCollectiblesUpdateArgs* = ref object of Args
chainId*: int
address*: string
collectionSlug*: string
type
CollectiblesUpdateArgs* = ref object of Args
@ -46,32 +31,47 @@ type
ids*: seq[UniqueID]
type
CollectionData* = ref object
collection*: CollectionDto
collectiblesLoaded*: bool
collectibles*: OrderedTableRef[int, CollectibleDto] # [collectibleId, CollectibleDto]
proc newCollectionData*(collection: CollectionDto): CollectionData =
new(result)
result.collection = collection
result.collectiblesLoaded = false
result.collectibles = newOrderedTable[int, CollectibleDto]()
type
CollectionsData* = ref object
collectionsLoaded*: bool
collections*: OrderedTableRef[string, CollectionData] # [collectionSlug, CollectionData]
CollectiblesData* = ref object
isFetching*: bool
allLoaded*: bool
lastLoadWasFromStart*: bool
lastLoadFromStartTimestamp*: DateTime
lastLoadCount*: int
previousCursor*: string
nextCursor*: string
ids*: seq[UniqueID]
proc newCollectionsData*(): CollectionsData =
proc newCollectiblesData*(): CollectiblesData =
new(result)
result.collectionsLoaded = false
result.collections = newOrderedTable[string, CollectionData]()
result.isFetching = false
result.allLoaded = false
result.lastLoadWasFromStart = false
result.lastLoadFromStartTimestamp = now() - initDuration(weeks = 1)
result.lastLoadCount = 0
result.previousCursor = ""
result.nextCursor = ""
result.ids = @[]
proc `$`*(self: CollectiblesData): string =
return fmt"""CollectiblesData(
isFetching:{self.isFetching},
allLoaded:{self.allLoaded},
lastLoadWasFromStart:{self.lastLoadWasFromStart},
lastLoadFromStartTimestamp:{self.lastLoadFromStartTimestamp},
lastLoadCount:{self.lastLoadCount},
previousCursor:{self.previousCursor},
nextCursor:{self.nextCursor},
ids:{self.ids}
)"""
type
AdressesData* = TableRef[string, CollectionsData] # [address, CollectionsData]
AdressesData = TableRef[string, CollectiblesData] # [address, CollectiblesData]
type
ChainsData* = TableRef[int, AdressesData] # [chainId, AdressesData]
ChainsData = TableRef[int, AdressesData] # [chainId, AdressesData]
type
CollectiblesResult = tuple[success: bool, collectibles: seq[CollectibleDto], collections: seq[CollectionDto], previousCursor: string, nextCursor: string]
proc hash(x: UniqueID): Hash =
result = x.contractAddress.hash !& x.tokenId.hash
@ -84,7 +84,8 @@ QtObject:
threadpool: ThreadPool
networkService: network_service.Service
ownershipData: ChainsData
data: TableRef[int, TableRef[UniqueID, CollectibleDto]] # [chainId, [UniqueID, CollectibleDto]]
collectibles: TableRef[int, TableRef[UniqueID, CollectibleDto]] # [chainId, [UniqueID, CollectibleDto]]
collections: TableRef[int, TableRef[string, CollectionDto]] # [chainId, [slug, CollectionDto]]
proc delete*(self: Service) =
self.QObject.delete
@ -100,115 +101,126 @@ QtObject:
result.threadpool = threadpool
result.networkService = networkService
result.ownershipData = newTable[int, AdressesData]()
result.data = newTable[int, TableRef[UniqueID, CollectibleDto]]()
result.collectibles = newTable[int, TableRef[UniqueID, CollectibleDto]]()
result.collections = newTable[int, TableRef[string, CollectionDto]]()
proc init*(self: Service) =
discard
proc insertAddressIfNeeded*(self: Service, chainId: int, address: string) =
proc prepareOwnershipData(self: Service, chainId: int, address: string, reset: bool = false) =
if not self.ownershipData.hasKey(chainId):
self.ownershipData[chainId] = newTable[string, CollectionsData]()
self.ownershipData[chainId] = newTable[string, CollectiblesData]()
let chainData = self.ownershipData[chainId]
if not chainData.hasKey(address):
chainData[address] = newCollectionsData()
if reset or not chainData.hasKey(address):
chainData[address] = newCollectiblesData()
proc updateOwnedCollectionsCache*(self: Service, chainId: int, address: string, collections: seq[CollectionDto]) =
let addressData = self.ownershipData[chainId][address]
addressData.lastLoadWasFromStart = reset
if reset:
addressData.lastLoadFromStartTimestamp = now()
proc updateOwnedCollectibles(self: Service, chainId: int, address: string, previousCursor: string, nextCursor: string, collectibles: seq[CollectibleDto]) =
try:
let oldAddressData = self.ownershipData[chainId][address]
# Start with empty object. Only add newly received collections, so removed ones are discarded
let newAddressData = newCollectionsData()
for collection in collections:
newAddressData.collections[collection.slug] = newCollectionData(collection)
if oldAddressData.collections.hasKey(collection.slug):
let oldCollection = oldAddressData.collections[collection.slug]
let newCollection = newAddressData.collections[collection.slug]
# Take collectibles from old collection
newCollection.collectiblesLoaded = oldCollection.collectiblesLoaded
newCollection.collectibles = oldCollection.collectibles
newAddressData.collectionsLoaded = true
self.ownershipData[chainId][address] = newAddressData
var data = OwnedCollectionsUpdateArgs()
data.chainId = chainId
data.address = address
self.events.emit(SIGNAL_OWNED_COLLECTIONS_UPDATED, data)
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
proc updateOwnedCollectiblesCache*(self: Service, chainId: int, address: string, collectionSlug: string, collectibles: seq[CollectibleDto]) =
try:
let collection = self.ownershipData[chainId][address].collections[collectionSlug]
collection.collectibles.clear()
let collectiblesData = self.ownershipData[chainId][address]
collectiblesData.previousCursor = previousCursor
collectiblesData.nextCursor = nextCursor
collectiblesData.allLoaded = (nextCursor == "")
var count = 0
for collectible in collectibles:
collection.collectibles[collectible.id] = collectible
collection.collectiblesLoaded = true
var data = OwnedCollectiblesUpdateArgs()
data.chainId = chainId
data.address = address
data.collectionSlug = collectionSlug
self.events.emit(SIGNAL_OWNED_COLLECTIBLES_UPDATED, data)
let newId = UniqueID(
contractAddress: collectible.address,
tokenId: collectible.tokenId
)
if not collectiblesData.ids.any(id => newId == id):
collectiblesData.ids.add(newId)
count = count + 1
collectiblesData.lastLoadCount = count
except Exception as e:
let errDesription = e.msg
error "error: ", errDesription
proc updateCollectiblesCache*(self: Service, chainId: int, collectibles: seq[CollectibleDto]) =
if not self.data.hasKey(chainId):
self.data[chainId] = newTable[UniqueID, CollectibleDto]()
proc updateCollectiblesCache*(self: Service, chainId: int, collectibles: seq[CollectibleDto], collections: seq[CollectionDto]) =
if not self.collectibles.hasKey(chainId):
self.collectibles[chainId] = newTable[UniqueID, CollectibleDto]()
if not self.collections.hasKey(chainId):
self.collections[chainId] = newTable[string, CollectionDto]()
var data = CollectiblesUpdateArgs()
data.chainId = chainId
for collection in collections:
let slug = collection.slug
self.collections[chainId][slug] = collection
for collectible in collectibles:
let id = UniqueID(
contractAddress: collectible.address,
tokenId: collectible.tokenId
)
self.data[chainId][id] = collectible
self.collectibles[chainId][id] = collectible
data.ids.add(id)
self.events.emit(SIGNAL_COLLECTIBLES_UPDATED, data)
proc getOwnedCollections*(self: Service, chainId: int, address: string) : CollectionsData =
proc getOwnedCollectibles*(self: Service, chainId: int, address: string) : CollectiblesData =
try:
return self.ownershipData[chainId][address]
except:
discard
return newCollectionsData()
proc getOwnedCollection*(self: Service, chainId: int, address: string, collectionSlug: string) : CollectionData =
try:
return self.ownershipData[chainId][address].collections[collectionSlug]
except:
discard
return newCollectionData(CollectionDto())
return newCollectiblesData()
proc getCollectible*(self: Service, chainId: int, id: UniqueID) : CollectibleDto =
try:
return self.data[chainId][id]
return self.collectibles[chainId][id]
except:
discard
return newCollectibleDto()
proc onRxCollectibles*(self: Service, response: string) {.slot.} =
proc getCollection*(self: Service, chainId: int, slug: string) : CollectionDto =
try:
return self.collections[chainId][slug]
except:
discard
return newCollectionDto()
proc processCollectiblesResult(responseObj: JsonNode) : CollectiblesResult =
result.success = false
let collectiblesContainerJson = responseObj["collectibles"]
if collectiblesContainerJson.kind == JObject:
let previousCursorJson = collectiblesContainerJson["previous"]
let nextCursorJson = collectiblesContainerJson["next"]
let collectiblesJson = collectiblesContainerJson["assets"]
if previousCursorJson.kind == JString and nextCursorJson.kind == JString:
result.previousCursor = previousCursorJson.getStr()
result.nextCursor = nextCursorJson.getStr()
for collectibleJson in collectiblesJson.getElems():
if collectibleJson.kind == JObject:
result.collectibles.add(collectibleJson.toCollectibleDto())
let collectionJson = collectibleJson["collection"]
if collectionJson.kind == JObject:
result.collections.add(collectionJson.toCollectionDto())
else:
return
else:
return
result.success = true
proc onRxCollectibles(self: Service, response: string) {.slot.} =
try:
let responseObj = response.parseJson
if (responseObj.kind == JObject):
let chainIdJson = responseObj["chainId"]
let collectiblesJson = responseObj["collectibles"]
if (chainIdJson.kind == JInt and
collectiblesJson.kind == JArray):
if chainIdJson.kind == JInt:
let chainId = chainIdJson.getInt()
let collectibles = map(collectiblesJson.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto())
self.updateCollectiblesCache(chainId, collectibles)
let (success, collectibles, collections, _, _) = processCollectiblesResult(responseObj)
if success:
self.updateCollectiblesCache(chainId, collectibles, collections)
except Exception as e:
let errDescription = e.msg
error "error onRxCollectibles: ", errDescription
@ -223,95 +235,63 @@ QtObject:
contractAddress: id.contractAddress,
tokenID: id.tokenId.toString()
)),
limit: limit
)
self.threadpool.start(arg)
proc onRxOwnedCollections*(self: Service, response: string) {.slot.} =
try:
let responseObj = response.parseJson
if (responseObj.kind == JObject):
let chainIdJson = responseObj["chainId"]
let addressJson = responseObj["address"]
let validAccount = (chainIdJson.kind == JInt and
addressJson.kind == JString)
if (validAccount):
let chainId = chainIdJson.getInt()
let address = addressJson.getStr()
var collections: seq[CollectionDto]
let collectionsJson = responseObj["collections"]
if (collectionsJson.kind == JArray):
collections = map(collectionsJson.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto())
self.updateOwnedCollectionsCache(chainId, address, collections)
except Exception as e:
let errDescription = e.msg
error "error onRxOwnedCollections: ", errDescription
proc fetchOwnedCollections*(self: Service, chainId: int, address: string) =
self.insertAddressIfNeeded(chainId, address)
let arg = FetchOwnedCollectionsTaskArg(
tptr: cast[ByteAddress](fetchOwnedCollectionsTaskArg),
vptr: cast[ByteAddress](self.vptr),
slot: "onRxOwnedCollections",
chainId: chainId,
address: address,
limit: len(ids)
)
self.threadpool.start(arg)
proc onRxOwnedCollectibles*(self: Service, response: string) {.slot.} =
proc onRxOwnedCollectibles(self: Service, response: string) {.slot.} =
var data = OwnedCollectiblesUpdateArgs()
try:
let responseObj = response.parseJson
if (responseObj.kind == JObject):
let chainIdJson = responseObj["chainId"]
let addressJson = responseObj["address"]
let collectionSlugJson = responseObj["collectionSlug"]
let validCollection = (chainIdJson.kind == JInt and
addressJson.kind == JString and
collectionSlugJson.kind == JString)
if (validCollection):
let chainId = chainIdJson.getInt()
let address = addressJson.getStr()
let collectionSlug = collectionSlugJson.getStr()
var collectibles: seq[CollectibleDto]
let collectiblesJson = responseObj["collectibles"]
if (collectiblesJson.kind == JArray):
collectibles = map(collectiblesJson.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto())
self.updateOwnedCollectiblesCache(chainId, address, collectionSlug, collectibles)
self.updateCollectiblesCache(data.chainId, collectibles)
if (chainIdJson.kind == JInt and
addressJson.kind == JString):
data.chainId = chainIdJson.getInt()
data.address = addressJson.getStr()
self.ownershipData[data.chainId][data.address].isFetching = false
let (success, collectibles, collections, prevCursor, nextCursor) = processCollectiblesResult(responseObj)
if success:
self.updateCollectiblesCache(data.chainId, collectibles, collections)
self.updateOwnedCollectibles(data.chainId, data.address, prevCursor, nextCursor, collectibles)
except Exception as e:
let errDescription = e.msg
error "error onRxOwnedCollectibles: ", errDescription
self.events.emit(SIGNAL_OWNED_COLLECTIBLES_UPDATE_FINISHED, data)
proc fetchOwnedCollectibles*(self: Service, chainId: int, address: string, collectionSlug: string) =
self.insertAddressIfNeeded(chainId, address)
let collections = self.ownershipData[chainId][address].collections
proc resetOwnedCollectibles*(self: Service, chainId: int, address: string) =
self.prepareOwnershipData(chainId, address, true)
var data = OwnedCollectiblesUpdateArgs()
data.chainId = chainId
data.address = address
self.events.emit(SIGNAL_OWNED_COLLECTIBLES_UPDATE_FINISHED, data)
if not collections.hasKey(collectionSlug):
error "error fetchOwnedCollectibles: Attempting to fetch collectibles from unknown collection: ", collectionSlug
proc fetchOwnedCollectibles*(self: Service, chainId: int, address: string, limit: int) =
self.prepareOwnershipData(chainId, address, false)
let collectiblesData = self.ownershipData[chainId][address]
if collectiblesData.isFetching:
return
if collectiblesData.allLoaded:
return
collectiblesData.isFetching = true
var data = OwnedCollectiblesUpdateArgs()
data.chainId = chainId
data.address = address
self.events.emit(SIGNAL_OWNED_COLLECTIBLES_UPDATE_STARTED, data)
let arg = FetchOwnedCollectiblesTaskArg(
tptr: cast[ByteAddress](fetchOwnedCollectiblesTaskArg),
vptr: cast[ByteAddress](self.vptr),
slot: "onRxOwnedCollectibles",
chainId: chainId,
address: address,
collectionSlug: collectionSlug,
cursor: collectiblesData.nextCursor,
limit: limit
)
self.threadpool.start(arg)
proc fetchAllOwnedCollectibles*(self: Service, chainId: int, address: string) =
try:
for collectionSlug, _ in self.ownershipData[chainId][address].collections:
self.fetchOwnedCollectibles(chainId, address, collectionSlug)
except Exception as e:
let errDescription = e.msg
error "error fetchAllOwnedCollectibles: ", errDescription

View File

@ -217,8 +217,12 @@ QtObject:
for tx in historyData["history"].getElems():
transactions.add(tx.toTransactionDto())
for c in historyData["collectibles"].getElems():
collectibles.add(c.toCollectibleDto())
let collectiblesContainerJson = historyData["collectibles"]
if collectiblesContainerJson.kind == JObject:
let collectiblesJson = collectiblesContainerJson["assets"]
if collectiblesJson.kind == JArray:
for c in collectiblesJson.getElems():
collectibles.add(c.toCollectibleDto())
if self.allTxLoaded.hasKey(address):
self.allTxLoaded[address] = self.allTxLoaded[address] and allTxLoaded

View File

@ -18,14 +18,10 @@ proc `==`*(a, b: NFTUniqueID): bool =
result = a.contractAddress == b.contractAddress and
a.tokenID == b.tokenID
rpc(getOpenseaCollectionsByOwner, "wallet"):
rpc(getOpenseaAssetsByOwnerWithCursor, "wallet"):
chainId: int
address: string
rpc(getOpenseaAssetsByOwnerAndCollection, "wallet"):
chainId: int
address: string
collectionSlug: string
cursor: string
limit: int
rpc(getOpenseaAssetsByNFTUniqueID, "wallet"):

View File

@ -33,6 +33,7 @@ ColumnLayout {
font.pixelSize: isNarrowMode ? 15 : 22
lineHeight: isNarrowMode ? 22 : 30
lineHeightMode: Text.FixedHeight
elide: Text.ElideRight
color: Theme.palette.baseColor1
}
}
@ -57,6 +58,7 @@ ColumnLayout {
id: collectibleIdTopRow
sourceComponent: collectibleIdComponent
visible: !root.isNarrowMode
Layout.fillWidth: true
Binding {
target: collectibleIdTopRow.item
@ -74,6 +76,7 @@ ColumnLayout {
id: collectibleIdBottomRow
sourceComponent: collectibleIdComponent
visible: root.isNarrowMode
Layout.maximumWidth: root.width - parent.spacing - networkTag.width
Binding {
target: collectibleIdBottomRow.item

View File

@ -28,8 +28,7 @@ QtObject {
property string signingPhrase: walletSection.signingPhrase
property string mnemonicBackedUp: walletSection.isMnemonicBackedUp
property var collections: walletSectionCollectibles.model
property var flatCollectibles: walletSectionCollectibles.flatModel
property var flatCollectibles: walletSectionCollectibles.model
property var currentCollectible: walletSectionCurrentCollectible
property var savedAddresses: SortFilterProxyModel {
@ -185,10 +184,6 @@ QtObject {
return globalUtils.hex2Dec(value)
}
function fetchOwnedCollectibles(slug) {
walletSectionCollectibles.fetchOwnedCollectibles(slug)
}
function getCollectionMaxValue(traitType, value, maxValue, collectionIndex) {
// Not Refactored Yet
// if(maxValue !== "")
@ -198,8 +193,8 @@ QtObject {
// walletModelV2Inst.collectiblesView.collections.getCollectionTraitMaxValue(collectionIndex, traitType).toString();
}
function selectCollectible(slug, id) {
walletSectionCurrentCollectible.update(slug, id)
function selectCollectible(address, tokenId) {
walletSectionCurrentCollectible.update(address, tokenId)
}
function getNameForSavedWalletAddress(address) {

View File

@ -4,6 +4,7 @@ import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import shared.panels 1.0
import utils 1.0
@ -15,9 +16,7 @@ Item {
property var collectiblesModel
width: parent.width
signal collectibleClicked(string collectionSlug, int collectibleId)
readonly property bool areCollectionsLoaded: root.collectiblesModel.collectionsLoaded
signal collectibleClicked(string address, string tokenId)
Loader {
id: contentLoader
@ -25,7 +24,7 @@ Item {
height: parent.height
sourceComponent: {
if (root.areCollectionsLoaded && root.collectiblesModel.collectionCount === 0)
if (root.collectiblesModel.allCollectiblesLoaded && root.collectiblesModel.count === 0)
return empty;
return loaded;
}
@ -49,18 +48,19 @@ Item {
StatusGridView {
id: gridView
anchors.fill: parent
model: root.areCollectionsLoaded ? root.collectiblesModel : Constants.dummyModelItems
model: root.collectiblesModel
cellHeight: 229
cellWidth: 176
delegate: CollectibleView {
height: gridView.cellHeight
width: gridView.cellWidth
collectibleModel: root.areCollectionsLoaded ? model : undefined
isLoadingDelegate: !root.areCollectionsLoaded
collectibleModel: model
onCollectibleClicked: {
root.collectibleClicked(slug, collectibleId);
root.collectibleClicked(address, tokenId);
}
}
ScrollBar.vertical: StatusScrollBar {}
}
}
}

View File

@ -99,7 +99,7 @@ Item {
CollectiblesView {
collectiblesModel: RootStore.flatCollectibles
onCollectibleClicked: {
RootStore.selectCollectible(collectionSlug, collectibleId)
RootStore.selectCollectible(address, tokenId)
stack.currentIndex = 1
}
}

View File

@ -5,6 +5,7 @@ import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
import utils 1.0
import shared.controls 1.0
@ -26,7 +27,7 @@ Item {
asset.name: currentCollectible.collectionImageUrl
asset.isImage: true
primaryText: currentCollectible.collectionName
secondaryText: currentCollectible.id
secondaryText: "#" + currentCollectible.tokenId
isNarrowMode: root.isNarrowMode
networkShortName: currentCollectible.networkShortName
networkColor: currentCollectible.networkColor

View File

@ -15,14 +15,12 @@ Item {
id: root
property var collectibleModel
property bool isLoadingDelegate
signal collectibleClicked(string slug, int collectibleId)
signal collectibleClicked(string address, string tokenId)
QtObject {
id: d
readonly property bool modeDataValid: !!root.collectibleModel && root.collectibleModel !== undefined
readonly property bool isLoaded: modeDataValid ? root.collectibleModel.collectionCollectiblesLoaded : false
readonly property bool modeDataValid: !!root.collectibleModel && root.collectibleModel !== undefined && root.collectibleModel.id >= 0
}
implicitHeight: 225
@ -48,7 +46,7 @@ Item {
color: d.modeDataValid ? root.collectibleModel.backgroundColor : "transparent"
Loader {
anchors.fill: parent
active: root.isLoadingDelegate
active: root.collectibleModel.isLoading
sourceComponent: LoadingComponent {radius: image.radius}
}
}
@ -57,7 +55,7 @@ Item {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.leftMargin: 8
Layout.topMargin: 9
Layout.preferredWidth: isLoadingDelegate ? 134 : 144
Layout.preferredWidth: root.collectibleModel.isLoading ? 134 : 144
Layout.preferredHeight: 21
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
@ -65,22 +63,22 @@ Item {
customColor: Theme.palette.directColor1
font.weight: Font.DemiBold
elide: Text.ElideRight
text: isLoadingDelegate ? Constants.dummyText : d.isLoaded && d.modeDataValid ? root.collectibleModel.name : "..."
loading: root.isLoadingDelegate
text: root.collectibleModel.isLoading ? Constants.dummyText : d.modeDataValid ? root.collectibleModel.name : "..."
loading: root.collectibleModel.isLoading
}
StatusTextWithLoadingState {
id: collectionLabel
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.leftMargin: 8
Layout.preferredWidth: isLoadingDelegate ? 88 : 144
Layout.preferredWidth: root.collectibleModel.isLoading ? 88 : 144
Layout.preferredHeight: 18
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
customColor: Theme.palette.baseColor1
elide: Text.ElideRight
text: isLoadingDelegate ? Constants.dummyText : d.modeDataValid ? root.collectibleModel.collectionName : ""
loading: root.isLoadingDelegate
text: root.collectibleModel.isLoading ? Constants.dummyText : d.modeDataValid ? root.collectibleModel.collectionName : "..."
loading: root.collectibleModel.isLoading
}
}
@ -90,15 +88,15 @@ Item {
border.width: 1
border.color: Theme.palette.primaryColor1
color: Theme.palette.indirectColor3
visible: d.isLoaded && mouse.containsMouse
visible: !root.collectibleModel.isLoading && mouse.containsMouse
}
MouseArea {
id: mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (d.isLoaded) {
root.collectibleClicked(root.collectibleModel.collectionSlug, root.collectibleModel.id);
if (d.modeDataValid && !root.collectibleModel.isLoading) {
root.collectibleClicked(root.collectibleModel.address, root.collectibleModel.tokenId);
}
}
}

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit f60716412259aece88d899d09fc71de4c4ba5d2e
Subproject commit 5ecb7b68eefada3725c360f68fba7ac92b612c82