feat(@desktop/wallet): implement new collectibles view

Fixes #8810
This commit is contained in:
Dario Gabriel Lipicar 2023-01-19 21:44:35 -03:00 committed by Anthony Laibe
parent 45adf0f411
commit 20733272f2
15 changed files with 513 additions and 278 deletions

View File

@ -42,6 +42,7 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_COLLECTIONS_UPDATED) do(e:Args):
let args = CollectionsUpdateArgs(e)
self.refreshCollections(args.chainId, args.address)
self.collectibleService.fetchAllCollectibles(args.chainId, args.address)
self.events.on(SIGNAL_COLLECTIBLES_UPDATED) do(e:Args):
let args = CollectiblesUpdateArgs(e)

View File

@ -0,0 +1,221 @@
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

@ -1,9 +1,9 @@
import NimQml, Tables, strutils, strformat
import NimQml, Tables, strutils, strformat, sequtils
import ./collectibles_item, ./collectible_trait_model
type
ModelRole {.pure.} = enum
CollectibleRole* {.pure.} = enum
Id = UserRole + 1,
Name
ImageUrl
@ -26,37 +26,39 @@ QtObject:
proc setup(self: Model) =
self.QAbstractListModel.setup
proc newModel*(): Model =
proc newModel*(items: seq[Item]): Model =
new(result, delete)
result.setup
result.items = items
proc newModel*(): Model =
return newModel(@[])
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.} =
proc getCount*(self: Model): int {.slot.} =
self.items.len
QtProperty[int] count:
read = getCount
notify = countChanged
method rowCount(self: Model, index: QModelIndex = nil): int =
method rowCount*(self: Model, index: QModelIndex = nil): int =
return self.items.len
method roleNames(self: Model): Table[int, string] =
{
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",
CollectibleRole.Id.int:"id",
CollectibleRole.Name.int:"name",
CollectibleRole.ImageUrl.int:"imageUrl",
CollectibleRole.BackgroundColor.int:"backgroundColor",
CollectibleRole.Description.int:"description",
CollectibleRole.Permalink.int:"permalink",
CollectibleRole.Properties.int:"properties",
CollectibleRole.Rankings.int:"rankings",
CollectibleRole.Stats.int:"stats",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -67,36 +69,42 @@ QtObject:
return
let item = self.items[index.row]
let enumRole = role.ModelRole
let enumRole = role.CollectibleRole
case enumRole:
of ModelRole.Id:
of CollectibleRole.Id:
result = newQVariant(item.getId())
of ModelRole.Name:
of CollectibleRole.Name:
result = newQVariant(item.getName())
of ModelRole.ImageUrl:
of CollectibleRole.ImageUrl:
result = newQVariant(item.getImageUrl())
of ModelRole.BackgroundColor:
of CollectibleRole.BackgroundColor:
result = newQVariant(item.getBackgroundColor())
of ModelRole.Description:
of CollectibleRole.Description:
result = newQVariant(item.getDescription())
of ModelRole.Permalink:
of CollectibleRole.Permalink:
result = newQVariant(item.getPermalink())
of ModelRole.Properties:
of CollectibleRole.Properties:
let traits = newTraitModel()
traits.setItems(item.getProperties())
result = newQVariant(traits)
of ModelRole.Rankings:
of CollectibleRole.Rankings:
let traits = newTraitModel()
traits.setItems(item.getRankings())
result = newQVariant(traits)
of ModelRole.Stats:
of CollectibleRole.Stats:
let traits = newTraitModel()
traits.setItems(item.getStats())
result = newQVariant(traits)
proc getItem*(self: Model, index: int): Item =
return self.items[index]
proc setItems*(self: Model, items: seq[Item]) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
proc appendItems*(self: Model, items: seq[Item]) =
self.setItems(concat(self.items, items))

View File

@ -0,0 +1,16 @@
import sequtils, sugar
import ../../../../../../app_service/service/collectible/dto
import collectibles_item, collectible_trait_item
proc collectibleToItem*(c: CollectibleDto) : Item =
return initItem(
c.id,
c.name,
c.imageUrl,
c.backgroundColor,
c.description,
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))
)

View File

@ -17,8 +17,7 @@ proc initItem*(name, slug, imageUrl: string, ownedAssetCount: int, collectiblesL
result.imageUrl = imageUrl
result.ownedAssetCount = ownedAssetCount
result.collectiblesLoaded = collectiblesLoaded
result.collectiblesModel = collectibles_model.newModel()
result.collectiblesModel.setItems(collectibles)
result.collectiblesModel = collectibles_model.newModel(collectibles)
proc initItem*(): Item =
result = initItem("", "", "", 0, false, @[])

View File

@ -4,8 +4,9 @@ import ./collections_item as collections_item
import ./collectibles_model as collectibles_model
import ./collectibles_item as collectibles_item
type
ModelRole {.pure.} = enum
CollectionRole* {.pure.} = enum
Name = UserRole + 1,
Slug
ImageUrl
@ -36,34 +37,30 @@ QtObject:
result &= fmt"""[{i}]:({$self.items[i]})"""
proc countChanged(self: Model) {.signal.}
proc getCount(self: Model): int {.slot.} =
proc getCount*(self: Model): int {.slot.} =
self.items.len
QtProperty[int] collectionsLoaded:
read = getCollectionsLoaded
notify = collectionsLoadedChanged
proc collectionsLoadedChanged(self: Model) {.signal.}
proc getCollectionsLoaded(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] =
{
ModelRole.Name.int:"name",
ModelRole.Slug.int:"slug",
ModelRole.ImageUrl.int:"imageUrl",
ModelRole.OwnedAssetCount.int:"ownedAssetCount",
ModelRole.CollectiblesLoaded.int:"collectiblesLoaded",
ModelRole.CollectiblesModel.int:"collectiblesModel"
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 =
@ -74,29 +71,39 @@ QtObject:
return
let item = self.items[index.row]
let enumRole = role.ModelRole
let enumRole = role.CollectionRole
case enumRole:
of ModelRole.Name:
of CollectionRole.Name:
result = newQVariant(item.getName())
of ModelRole.Slug:
of CollectionRole.Slug:
result = newQVariant(item.getSlug())
of ModelRole.ImageUrl:
of CollectionRole.ImageUrl:
result = newQVariant(item.getImageUrl())
of ModelRole.OwnedAssetCount:
of CollectionRole.OwnedAssetCount:
result = newQVariant(item.getOwnedAssetCount())
of ModelRole.CollectiblesLoaded:
of CollectionRole.CollectiblesLoaded:
result = newQVariant(item.getCollectiblesLoaded())
of ModelRole.CollectiblesModel:
of CollectionRole.CollectiblesModel:
result = newQVariant(item.getCollectiblesModel())
proc setItems*(self: Model, items: seq[collections_item.Item]) =
proc setCollections*(self: Model, items: seq[collections_item.Item], collectionsLoaded: bool) =
self.beginResetModel()
self.items = items
self.endResetModel()
self.countChanged()
self.collectionsLoaded = true
self.collectionsLoadedChanged()
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:
@ -104,15 +111,21 @@ QtObject:
return i
return -1
proc updateCollectionCollectibles*(self: Model, slug: string, collectibles: seq[collectibles_item.Item]) =
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 index = self.createIndex(idx, 0, nil)
let collectiblesModel = self.items[idx].getCollectiblesModel()
collectiblesModel.setItems(collectibles)
self.dataChanged(index, index, @[ModelRole.CollectiblesModel.int])
self.emitDataChanged(idx, idx, CollectionRole.CollectiblesModel.int)
if not self.items[idx].getCollectiblesLoaded():
self.items[idx].collectiblesLoaded = true
self.dataChanged(index, index, @[ModelRole.CollectiblesLoaded.int])
if self.items[idx].getCollectiblesLoaded() != collectiblesLoaded:
self.items[idx].collectiblesLoaded = collectiblesLoaded
self.emitDataChanged(idx, idx, CollectionRole.CollectiblesLoaded.int)

View File

@ -0,0 +1,13 @@
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

@ -6,15 +6,17 @@ import ../../../../core/eventemitter
import ./io_interface, ./view, ./controller
import ../io_interface as delegate_interface
import ../../../../../app_service/service/collectible/service as collectible_service
import ../../../../../app_service/service/collectible/service as collectible_dto
import ../../../../../app_service/service/wallet_account/service as wallet_account_service
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/collections_item as collections_item
import ./models/collectibles_utils
import ./models/collectibles_model as collectibles_model
export io_interface
@ -86,37 +88,31 @@ method switchAccount*(self: Module, accountIndex: int) =
self.currentCollectibleModule.setCurrentAddress(network, self.address)
proc collectibleToItem(c: collectible_dto.CollectibleDto) : collectibles_item.Item =
return collectibles_item.initItem(
c.id,
c.name,
c.imageUrl,
c.backgroundColor,
c.description,
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))
)
proc collectionToItem(c: CollectionData) : collections_item.Item =
return collections_item.initItem(
c.collection.name,
c.collection.slug,
c.collection.imageUrl,
c.collection.ownedAssetCount,
c.collectiblesLoaded,
toSeq(c.collectibles.values).map(c => collectibleToItem(c))
)
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 setCollections*(self: Module, collections: CollectionsData) =
self.view.setCollections(
toSeq(collections.collections.values).map(c => collectionToItem(c))
toSeq(collections.collections.values).map(c => self.collectionToItem(c)),
collections.collectionsLoaded
)
method updateCollection*(self: Module, collection: CollectionData) =
self.view.setCollectibles(collection.collection.slug,
toSeq(collection.collectibles.values).map(c => collectibleToItem(c))
toSeq(collection.collectibles.values).map(c => collectibleToItem(c)),
collection.collectiblesLoaded
)
method fetchCollections*(self: Module) =

View File

@ -1,6 +1,7 @@
import NimQml
import ./models/collections_model
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 ./io_interface
@ -9,12 +10,12 @@ QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
model: Model
modelVariant: QVariant
model: collections_model.Model
flatModel: flat_model.Model
proc delete*(self: View) =
self.flatModel.delete
self.model.delete
self.modelVariant.delete
self.QObject.delete
proc newView*(delegate: io_interface.AccessInterface): View =
@ -22,28 +23,33 @@ QtObject:
result.QObject.setup
result.delegate = delegate
result.model = newModel()
result.modelVariant = newQVariant(result.model)
result.flatModel = flat_model.newModel(result.model)
proc load*(self: View) =
self.delegate.viewDidLoad()
proc modelChanged*(self: View) {.signal.}
proc getModel(self: View): QVariant {.slot.} =
return self.modelVariant
return newQVariant(self.model)
QtProperty[QVariant] model:
read = getModel
notify = modelChanged
proc setCollections*(self: View, collections: seq[collections_item.Item]) =
self.model.setItems(collections)
proc setCollectibles*(self: View, collectionsSlug: string, collectibles: seq[collectibles_item.Item]) =
self.model.updateCollectionCollectibles(collectionsSlug, collectibles)
proc flatModelChanged*(self: View) {.signal.}
proc getFlatModel(self: View): QVariant {.slot.} =
return newQVariant(self.flatModel)
QtProperty[QVariant] flatModel:
read = getFlatModel
notify = flatModelChanged
proc fetchCollections*(self: View) {.slot.} =
self.delegate.fetchCollections()
proc fetchCollectibles*(self: View, collectionSlug: string) {.slot.} =
self.delegate.fetchCollectibles(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)

View File

@ -165,11 +165,12 @@ QtObject:
data.chainId = chainIdJson.getInt()
data.address = addressJson.getStr()
var collections: seq[CollectionDto]
let collectionsJson = responseObj["collections"]
if (collectionsJson.kind == JArray):
let collections = map(collectionsJson.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto())
self.setCollections(data.chainId, data.address, collections)
self.events.emit(SIGNAL_COLLECTIONS_UPDATED, data)
collections = map(collectionsJson.getElems(), proc(x: JsonNode): CollectionDto = x.toCollectionDto())
self.setCollections(data.chainId, data.address, collections)
self.events.emit(SIGNAL_COLLECTIONS_UPDATED, data)
except Exception as e:
let errDescription = e.msg
error "error onRxCollections: ", errDescription
@ -208,11 +209,12 @@ QtObject:
data.address = addressJson.getStr()
data.collectionSlug = collectionSlugJson.getStr()
var collectibles: seq[CollectibleDto]
let collectiblesJson = responseObj["collectibles"]
if (collectiblesJson.kind == JArray):
let collectibles = map(collectiblesJson.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto())
self.setCollectibles(data.chainId, data.address, data.collectionSlug, collectibles)
self.events.emit(SIGNAL_COLLECTIBLES_UPDATED, data)
collectibles = map(collectiblesJson.getElems(), proc(x: JsonNode): CollectibleDto = x.toCollectibleDto())
self.setCollectibles(data.chainId, data.address, data.collectionSlug, collectibles)
self.events.emit(SIGNAL_COLLECTIBLES_UPDATED, data)
except Exception as e:
let errDescription = e.msg
error "error onRxCollectibles: ", errDescription
@ -241,3 +243,11 @@ QtObject:
limit: limit
)
self.threadpool.start(arg)
proc fetchAllCollectibles*(self: Service, chainId: int, address: string) =
try:
for collectionSlug, _ in self.data[chainId][address].collections:
self.fetchCollectibles(chainId, address, collectionSlug)
except Exception as e:
let errDescription = e.msg
error "error fetchAllCollectibles: ", errDescription

View File

@ -31,6 +31,7 @@ QtObject {
property string mnemonicBackedUp: walletSection.isMnemonicBackedUp
property var collections: walletSectionCollectibles.model
property var flatCollectibles: walletSectionCollectibles.flatModel
property var currentCollectible: walletSectionCurrentCollectible
property var savedAddresses: walletSectionSavedAddresses.model

View File

@ -1,34 +1,35 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import utils 1.0
import shared 1.0
import shared.panels 1.0
import "../stores"
import "../popups"
import "collectibles"
Item {
id: root
property var collectiblesModel
width: parent.width
signal collectibleClicked(string collectionSlug, int collectibleId)
readonly property bool areCollectionsLoaded: root.collectiblesModel.collectionsLoaded
Loader {
id: contentLoader
width: parent.width
height: parent.height
sourceComponent: {
if (!RootStore.collections.collectionsLoaded)
if (!root.areCollectionsLoaded)
{
return loading
} else if (RootStore.collections.count === 0) {
} else if (root.collectiblesModel.collectionCount === 0) {
return empty;
} else if (root.collectiblesModel.count === 0) {
return loading
}
return loaded;
}
@ -64,42 +65,21 @@ Item {
Component {
id: loaded
StatusScrollView {
id: scrollView
Column {
id: collectiblesSection
width: root.width
Repeater {
objectName: "collectionsRepeater"
id: collectionsRepeater
model: RootStore.collections
delegate: StatusExpandableItem {
id: collectionDelegate
anchors.left: parent.left
anchors.right: parent.right
primaryText: model.name
asset.name: model.imageUrl
asset.isImage: true
type: StatusExpandableItem.Type.Secondary
expandableComponent: CollectibleCollectionView {
collectionImageUrl: model.imageUrl
collectiblesLoaded: model.collectiblesLoaded
collectiblesModel: model.collectiblesModel
anchors.left: parent.left
anchors.right: parent.right
onCollectibleClicked: {
RootStore.selectCollectible(model.slug, collectibleId)
root.collectibleClicked(model.slug, collectibleId);
}
}
onExpandedChanged: {
if(expanded) {
RootStore.fetchCollectibles(model.slug)
}
}
StatusGridView {
id: gridView
anchors.fill: parent
model: root.collectiblesModel
cellHeight: 229
cellWidth: 176
delegate: Item {
height: gridView.cellHeight
width: gridView.cellWidth
CollectibleView {
collectibleModel: model
anchors.fill: parent
anchors.bottomMargin: 4
onCollectibleClicked: {
root.collectibleClicked(slug, collectibleId);
}
}
}

View File

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

View File

@ -1,121 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtGraphicalEffects 1.13
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import shared.panels 1.0
import "../../stores"
import utils 1.0
Item {
id: root
property string collectionImageUrl: ""
property bool collectiblesLoaded: false
property var collectiblesModel
width: parent.width
height: contentLoader.height
signal collectibleClicked(int collectibleId)
Loader {
id: contentLoader
width: parent.width
anchors.top: parent.top
anchors.topMargin: 16
anchors.horizontalCenter: parent.horizontalCenter
sourceComponent: {
if (!root.collectiblesLoaded) {
return loading
} else if (root.collectiblesModel.count === 0) {
return empty
}
return loaded
}
}
Component {
id: loading
Item {
id: loadingIndicator
height: 164
StatusLoadingIndicator {
width: 20
height: 20
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
Component {
id: empty
Item {
id: emptyContainer
height: 164
StyledText {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
color: Style.current.secondaryText
text: qsTr("No collectibles available")
font.pixelSize: 15
}
}
}
Component {
id: loaded
Flow {
width: parent.width
bottomPadding: 16
spacing: 24
Component {
id: collectibleDelegate
StatusRoundedImage {
id: image
width: 146
height: 146
radius: 16
image.source: model.imageUrl
border.color: Theme.palette.baseColor2
border.width: 1
showLoadingIndicator: true
color: model.backgroundColor
Rectangle {
anchors.centerIn: parent
width: image.width
height: image.height
radius: image.radius
border.width: 1
border.color: Theme.palette.primaryColor1
color: Theme.palette.indirectColor3
visible: mouse.containsMouse
}
MouseArea {
id: mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
root.collectibleClicked(model.id);
}
}
}
}
Repeater {
objectName: "collectiblesRepeater"
model: root.collectiblesModel
delegate: collectibleDelegate
}
}
}
}

View File

@ -0,0 +1,90 @@
import QtQuick 2.13
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import shared.panels 1.0
Item {
id: root
property var collectibleModel
implicitHeight: 225
implicitWidth: 176
signal collectibleClicked(string slug, int collectibleId)
readonly property bool isLoaded: root.collectibleModel.collectionCollectiblesLoaded
ColumnLayout {
//Layout.fillHeight: true
//Layout.fillWidth: true
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
spacing: 0
StatusRoundedImage {
id: image
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.topMargin: 8
Layout.bottomMargin: 0
implicitWidth: 160
implicitHeight: 160
radius: 12
image.source: root.collectibleModel.imageUrl
border.color: Theme.palette.baseColor2
border.width: 1
showLoadingIndicator: true
color: root.collectibleModel.backgroundColor
}
StatusBaseText {
id: collectibleLabel
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.topMargin: 9
Layout.preferredWidth: 144
Layout.preferredHeight: 21
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 15
color: Theme.palette.directColor1
font.weight: Font.DemiBold
elide: Text.ElideRight
text: isLoaded ? root.collectibleModel.name : "..."
}
StatusBaseText {
id: collectionLabel
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.topMargin: 0
Layout.preferredWidth: 144
Layout.preferredHeight: 18
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
font.pixelSize: 13
color: Theme.palette.baseColor1
elide: Text.ElideRight
text: root.collectibleModel.collectionName
}
}
Rectangle {
anchors.fill: parent
radius: 18
border.width: 1
border.color: Theme.palette.primaryColor1
color: Theme.palette.indirectColor3
visible: root.isLoaded && mouse.containsMouse
}
MouseArea {
id: mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
if (root.isLoaded) {
root.collectibleClicked(root.collectibleModel.collectionSlug, root.collectibleModel.id);
}
}
}
}