From bad497cc902d998c28a2f6ef5662477e1047ca7e Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Mon, 4 Sep 2023 06:24:14 -0300 Subject: [PATCH] feat(@desktop/wallet): implement nested collectibles model Part of #12072 --- .../wallet/accounts/module.nim | 8 +- .../modules/main/wallet_section/module.nim | 6 +- .../main/wallet_section/send/io_interface.nim | 8 + .../main/wallet_section/send/module.nim | 34 +++- .../modules/main/wallet_section/send/view.nim | 24 +++ .../shared_models/collectibles_item.nim | 20 ++- .../shared_models/collectibles_model.nim | 31 ++++ .../collectibles_nested_item.nim | 60 +++++++ .../collectibles_nested_model.nim | 166 ++++++++++++++++++ .../collectibles_nested_utils.nim | 25 +++ .../shared_models/collectibles_utils.nim | 2 + .../collectibles/controller.nim | 61 ++++--- src/backend/collectibles.nim | 2 +- src/backend/collectibles_types.nim | 10 +- 14 files changed, 423 insertions(+), 34 deletions(-) create mode 100644 src/app/modules/shared_models/collectibles_nested_item.nim create mode 100644 src/app/modules/shared_models/collectibles_nested_model.nim create mode 100644 src/app/modules/shared_models/collectibles_nested_utils.nim diff --git a/src/app/modules/main/profile_section/wallet/accounts/module.nim b/src/app/modules/main/profile_section/wallet/accounts/module.nim index 85446372ad..8f32a38b25 100644 --- a/src/app/modules/main/profile_section/wallet/accounts/module.nim +++ b/src/app/modules/main/profile_section/wallet/accounts/module.nim @@ -42,7 +42,11 @@ proc newModule*( result.view = newView(result) result.viewVariant = newQVariant(result.view) result.controller = accountsc.newController(result, walletAccountService) - result.collectiblesController = collectiblesc.newController(int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), events) + result.collectiblesController = collectiblesc.newController( + requestId = int32(backend_collectibles.CollectiblesRequestID.ProfileShowcase), + autofetch = false, + events = events + ) result.moduleLoaded = false ## Forward declarations @@ -58,7 +62,7 @@ method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant method getCollectiblesModel*(self: Module): QVariant = - return self.collectiblesController.getModel() + return self.collectiblesController.getModelAsVariant() method convertWalletAccountDtoToKeyPairAccountItem(self: Module, account: WalletAccountDto): KeyPairAccountItem = result = newKeyPairAccountItem( diff --git a/src/app/modules/main/wallet_section/module.nim b/src/app/modules/main/wallet_section/module.nim index a0a8a83fef..094ce3e790 100644 --- a/src/app/modules/main/wallet_section/module.nim +++ b/src/app/modules/main/wallet_section/module.nim @@ -122,7 +122,11 @@ proc newModule*( result.transactionService = transactionService result.activityController = activityc.newController(int32(ActivityID.History), currencyService, tokenService, events) result.tmpActivityController = activityc.newController(int32(ActivityID.Temporary), currencyService, tokenService, events) - result.collectiblesController = collectiblesc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), events) + result.collectiblesController = collectiblesc.newController( + requestId = int32(backend_collectibles.CollectiblesRequestID.WalletAccount), + autofetch = false, + events = events + ) result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events) result.filter = initFilter(result.controller) diff --git a/src/app/modules/main/wallet_section/send/io_interface.nim b/src/app/modules/main/wallet_section/send/io_interface.nim index 65e9bd0d24..c7203d7f4a 100644 --- a/src/app/modules/main/wallet_section/send/io_interface.nim +++ b/src/app/modules/main/wallet_section/send/io_interface.nim @@ -1,6 +1,8 @@ import stint import ../../../shared_models/currency_amount import app_service/service/transaction/dto +import app/modules/shared_models/collectibles_model as collectibles +import app/modules/shared_models/collectibles_nested_model as nested_collectibles type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -57,3 +59,9 @@ method setSelectedReceiveAccountIndex*(self: AccessInterface, index: int) = method filterChanged*(self: AccessInterface, addresses: seq[string], chainIds: seq[int]) = raise newException(ValueError, "No implementation available") + +method getCollectiblesModel*(self: AccessInterface): collectibles.Model = + raise newException(ValueError, "No implementation available") + +method getNestedCollectiblesModel*(self: AccessInterface): nested_collectibles.Model = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/wallet_section/send/module.nim b/src/app/modules/main/wallet_section/send/module.nim index e920003a68..bda1c77da5 100644 --- a/src/app/modules/main/wallet_section/send/module.nim +++ b/src/app/modules/main/wallet_section/send/module.nim @@ -13,6 +13,11 @@ import app/modules/shared/wallet_utils import app_service/service/transaction/dto import app/modules/shared_models/currency_amount +import app/modules/shared_modules/collectibles/controller as collectiblesc +import app/modules/shared_models/collectibles_model as collectibles +import app/modules/shared_models/collectibles_nested_model as nested_collectibles +import backend/collectibles as backend_collectibles + export io_interface const cancelledRequest* = "cancelled" @@ -31,7 +36,10 @@ type delegate: delegate_interface.AccessInterface events: EventEmitter view: View - controller: Controller + controller: controller.Controller + # Get the list of owned collectibles by the currently selected account + collectiblesController: collectiblesc.Controller + nestedCollectiblesModel: nested_collectibles.Model moduleLoaded: bool tmpSendTransactionDetails: TmpSendTransactionDetails senderCurrentAccountIndex: int @@ -52,8 +60,15 @@ proc newModule*( result = Module() result.delegate = delegate result.events = events - result.view = newView(result) result.controller = controller.newController(result, events, walletAccountService, networkService, currencyService, transactionService) + result.collectiblesController = collectiblesc.newController( + requestId = int32(backend_collectibles.CollectiblesRequestID.WalletSend), + autofetch = true, + events = events + ) + result.nestedCollectiblesModel = nested_collectibles.newModel(result.collectiblesController.getModel()) + result.view = newView(result) + result.moduleLoaded = false result.senderCurrentAccountIndex = 0 result.receiveCurrentAccountIndex = 0 @@ -61,6 +76,8 @@ proc newModule*( method delete*(self: Module) = self.view.delete self.controller.delete + self.nestedCollectiblesModel.delete + self.collectiblesController.delete method convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkItem = result = initNetworkItem( @@ -297,8 +314,21 @@ method filterChanged*(self: Module, addresses: seq[string], chainIds: seq[int]) self.view.switchSenderAccountByAddress(addresses[0]) self.view.switchReceiveAccountByAddress(addresses[0]) +proc updateCollectiblesFilter*(self: Module) = + let addresses = @[self.view.getSenderAddressByIndex(self.senderCurrentAccountIndex)] + let chainIds = self.controller.getChainIds() + self.collectiblesController.globalFilterChanged(addresses, chainIds) + method setSelectedSenderAccountIndex*(self: Module, index: int) = self.senderCurrentAccountIndex = index + self.updateCollectiblesFilter() method setSelectedReceiveAccountIndex*(self: Module, index: int) = self.receiveCurrentAccountIndex = index + +method getCollectiblesModel*(self: Module): collectibles.Model = + return self.collectiblesController.getModel() + +method getNestedCollectiblesModel*(self: Module): nested_collectibles.Model = + return self.nestedCollectiblesModel + diff --git a/src/app/modules/main/wallet_section/send/view.nim b/src/app/modules/main/wallet_section/send/view.nim index 12d42c566b..306934d55a 100644 --- a/src/app/modules/main/wallet_section/send/view.nim +++ b/src/app/modules/main/wallet_section/send/view.nim @@ -2,6 +2,8 @@ import NimQml, sequtils, strutils, stint, sugar import ./io_interface, ./accounts_model, ./account_item, ./network_model, ./network_item, ./suggested_route_item, ./transaction_routes import app/modules/shared_models/token_model +import app/modules/shared_models/collectibles_model as collectibles +import app/modules/shared_models/collectibles_nested_model as nested_collectibles QtObject: type @@ -10,6 +12,9 @@ QtObject: accounts: AccountsModel # this one doesn't include watch accounts and its what the user switches when using the sendModal senderAccounts: AccountsModel + # list of collectibles owned by the selected sender account + collectiblesModel: collectibles.Model + nestedCollectiblesModel: nested_collectibles.Model # for send modal selectedSenderAccount: AccountItem fromNetworksModel: NetworkModel @@ -43,6 +48,8 @@ QtObject: result.fromNetworksModel = newNetworkModel() result.toNetworksModel = newNetworkModel() result.transactionRoutes = newTransactionRoutes() + result.collectiblesModel = delegate.getCollectiblesModel() + result.nestedCollectiblesModel = delegate.getNestedCollectiblesModel() proc load*(self: View) = self.delegate.viewDidLoad() @@ -61,6 +68,20 @@ QtObject: read = getSenderAccounts notify = senderAccountsChanged + proc collectiblesModelChanged*(self: View) {.signal.} + proc getCollectiblesModel(self: View): QVariant {.slot.} = + return newQVariant(self.collectiblesModel) + QtProperty[QVariant] collectiblesModel: + read = getCollectiblesModel + notify = collectiblesModelChanged + + proc nestedCollectiblesModelChanged*(self: View) {.signal.} + proc getNestedCollectiblesModel(self: View): QVariant {.slot.} = + return newQVariant(self.nestedCollectiblesModel) + QtProperty[QVariant] nestedCollectiblesModel: + read = getNestedCollectiblesModel + notify = nestedCollectiblesModelChanged + proc selectedSenderAccountChanged*(self: View) {.signal.} proc getSelectedSenderAccount(self: View): QVariant {.slot.} = return newQVariant(self.selectedSenderAccount) @@ -72,6 +93,9 @@ QtObject: read = getSelectedSenderAccount notify = selectedSenderAccountChanged + proc getSenderAddressByIndex*(self: View, index: int): string {.slot.} = + return self.senderAccounts.getItemByIndex(index).address() + proc selectedReceiveAccountChanged*(self: View) {.signal.} proc getSelectedReceiveAccount(self: View): QVariant {.slot.} = return newQVariant(self.selectedReceiveAccount) diff --git a/src/app/modules/shared_models/collectibles_item.nim b/src/app/modules/shared_models/collectibles_item.nim index 968ca1d1be..38c2b1d07d 100644 --- a/src/app/modules/shared_models/collectibles_item.nim +++ b/src/app/modules/shared_models/collectibles_item.nim @@ -11,6 +11,8 @@ type imageUrl: string backgroundColor: string collectionName: string + collectionSlug: string + collectionImageUrl: string isLoading: bool isPinned: bool @@ -24,6 +26,8 @@ proc initItem*( imageUrl: string, backgroundColor: string, collectionName: string, + collectionSlug: string, + collectionImageUrl: string, isPinned: bool ): Item = result.chainId = chainId @@ -35,11 +39,13 @@ proc initItem*( result.imageUrl = imageUrl result.backgroundColor = if (backgroundColor == ""): "transparent" else: ("#" & backgroundColor) result.collectionName = collectionName + result.collectionSlug = collectionSlug + result.collectionImageUrl = collectionImageUrl result.isLoading = false result.isPinned = isPinned proc initItem*: Item = - result = initItem(0, "", u256(0), "", "", "", "", "transparent", "Collectibles", false) + result = initItem(0, "", u256(0), "", "", "", "", "transparent", "Collectibles", "", "", false) proc initLoadingItem*: Item = result = initItem() @@ -56,6 +62,8 @@ proc `$`*(self: Item): string = imageUrl: {self.imageUrl}, backgroundColor: {self.backgroundColor}, collectionName: {self.collectionName}, + collectionSlug: {self.collectionSlug}, + collectionImageUrl: {self.collectionImageUrl}, isLoading: {self.isLoading}, isPinned: {self.isPinned}, ]""" @@ -88,9 +96,19 @@ proc getImageUrl*(self: Item): string = proc getBackgroundColor*(self: Item): string = return self.backgroundColor +# Unique ID to identify collection, generated by us +proc getCollectionId*(self: Item): string = + return fmt"{self.getChainId}+{self.getContractAddress}" + 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 diff --git a/src/app/modules/shared_models/collectibles_model.nim b/src/app/modules/shared_models/collectibles_model.nim index 858e8acf30..a453b6e97b 100644 --- a/src/app/modules/shared_models/collectibles_model.nim +++ b/src/app/modules/shared_models/collectibles_model.nim @@ -14,7 +14,9 @@ type MediaUrl MediaType BackgroundColor + CollectionUid CollectionName + CollectionSlug IsLoading IsPinned @@ -145,7 +147,9 @@ QtObject: CollectibleRole.MediaType.int:"mediaType", CollectibleRole.ImageUrl.int:"imageUrl", CollectibleRole.BackgroundColor.int:"backgroundColor", + CollectibleRole.CollectionUid.int:"collectionUid", CollectibleRole.CollectionName.int:"collectionName", + CollectibleRole.CollectionSlug.int:"collectionSlug", CollectibleRole.IsLoading.int:"isLoading", CollectibleRole.IsPinned.int:"isPinned", }.toTable @@ -180,8 +184,12 @@ QtObject: result = newQVariant(item.getImageUrl()) of CollectibleRole.BackgroundColor: result = newQVariant(item.getBackgroundColor()) + of CollectibleRole.CollectionUid: + result = newQVariant(item.getCollectionId()) of CollectibleRole.CollectionName: result = newQVariant(item.getCollectionName()) + of CollectibleRole.CollectionSlug: + result = newQVariant(item.getCollectionSlug()) of CollectibleRole.IsLoading: result = newQVariant(false) of CollectibleRole.IsPinned: @@ -195,6 +203,26 @@ QtObject: error "Invalid role for loading item" result = newQVariant() + proc rowData(self: Model, index: int, column: string): string {.slot.} = + if (index >= self.items.len): + return + let item = self.items[index] + case column: + of "uid": result = item.getId() + of "chainId": result = $item.getChainId() + of "contractAddress": result = item.getContractAddress() + of "tokenId": result = item.getTokenId().toString() + of "name": result = item.getName() + of "mediaUrl": result = item.getMediaUrl() + of "mediaType": result = item.getMediaType() + of "imageUrl": result = item.getImageUrl() + of "backgroundColor": result = item.getBackgroundColor() + of "collectionUid": result = item.getCollectionId() + of "collectionName": result = item.getCollectionName() + of "collectionSlug": result = item.getCollectionSlug() + of "isLoading": result = $false + of "isPinned": result = $item.getIsPinned() + proc appendCollectibleItems(self: Model, newItems: seq[Item]) = if len(newItems) == 0: return @@ -271,6 +299,9 @@ QtObject: else: self.removeLoadingItems() + proc getItems*(self: Model): seq[Item] = + return self.items + proc setItems*(self: Model, newItems: seq[Item], offset: int, hasMore: bool) = if offset == 0: self.removeCollectibleItems() diff --git a/src/app/modules/shared_models/collectibles_nested_item.nim b/src/app/modules/shared_models/collectibles_nested_item.nim new file mode 100644 index 0000000000..0f70a35cfb --- /dev/null +++ b/src/app/modules/shared_models/collectibles_nested_item.nim @@ -0,0 +1,60 @@ +import strformat, stint + +type + Item* = object + id: string # Collectible ID if isCollection=false, Collection Slug otherwise + chainId: int + name: string + iconUrl: string + collectionId: string + collectionName: string + isCollection: bool + +proc initItem*( + id: string, + chainId: int, + name: string, + iconUrl: string, + collectionId: string, + collectionName: string, + isCollection: bool +): Item = + result.id = id + result.chainId = chainId + result.name = name + result.iconUrl = iconUrl + result.collectionId = collectionId + result.collectionName = collectionName + result.isCollection = isCollection + +proc `$`*(self: Item): string = + result = fmt"""CollectiblesNestedEntry( + id: {self.id}, + chainId: {self.chainId}, + name: {self.name}, + iconUrl: {self.iconUrl}, + collectionId: {self.collectionId}, + collectionName: {self.collectionName}, + isCollection: {self.isCollection}, + ]""" + +proc getId*(self: Item): string = + return self.id + +proc getChainId*(self: Item): int = + return self.chainId + +proc getName*(self: Item): string = + return self.name + +proc getIconUrl*(self: Item): string = + return self.iconUrl + +proc getCollectionId*(self: Item): string = + return self.collectionId + +proc getCollectionName*(self: Item): string = + return self.collectionName + +proc getIsCollection*(self: Item): bool = + return self.isCollection diff --git a/src/app/modules/shared_models/collectibles_nested_model.nim b/src/app/modules/shared_models/collectibles_nested_model.nim new file mode 100644 index 0000000000..5e7e722b09 --- /dev/null +++ b/src/app/modules/shared_models/collectibles_nested_model.nim @@ -0,0 +1,166 @@ +import NimQml, Tables, strutils, strformat, sequtils, logging + +import ./collectibles_model as flat_model +import ./collectibles_item as flat_item +import ./collectibles_nested_item as nested_item + +import ./collectibles_nested_utils + +type + CollectiblesNestedRole {.pure.} = enum + Uid = UserRole + 1, + ChainId + Name + IconUrl + CollectionUid + CollectionName + IsCollection + +QtObject: + type + Model* = ref object of QAbstractListModel + flatModel: flat_model.Model + items: seq[nested_item.Item] + currentCollectionUid: string + + proc delete(self: Model) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: Model) = + self.QAbstractListModel.setup + + proc newModel*(flatModel: flat_model.Model): Model = + new(result, delete) + result.flatModel = flatModel + result.items = @[] + result.currentCollectionUid = "" + result.setup + + signalConnect(result.flatModel, "countChanged()", result, "refreshItems()") + + # Forward declaration + proc refreshItems*(self: Model) + + proc `$`*(self: Model): string = + result = fmt"""CollectiblesNestedModel( + flatModel: {self.flatModel}, + currentCollectionUid: {self.currentCollectionUid}, + ]""" + + proc countChanged(self: Model) {.signal.} + proc getCount*(self: Model): int {.slot.} = + self.items.len + QtProperty[int] count: + read = getCount + notify = countChanged + + proc getCurrentCollectionUid*(self: Model): string {.slot.} = + result = self.currentCollectionUid + proc currentCollectionUidChanged(self: Model) {.signal.} + proc setCurrentCollectionUid(self: Model, currentCollectionUid: string) {.slot.} = + self.currentCollectionUid = currentCollectionUid + self.currentCollectionUidChanged() + self.refreshItems() + QtProperty[string] currentCollectionUid: + read = getCurrentCollectionUid + write = setCurrentCollectionUid + notify = currentCollectionUidChanged + + method rowCount(self: Model, index: QModelIndex = nil): int = + return self.items.len + + method roleNames(self: Model): Table[int, string] = + { + CollectiblesNestedRole.Uid.int:"uid", + CollectiblesNestedRole.ChainId.int:"chainId", + CollectiblesNestedRole.Name.int:"name", + CollectiblesNestedRole.IconUrl.int:"iconUrl", + CollectiblesNestedRole.CollectionUid.int:"collectionUid", + CollectiblesNestedRole.CollectionName.int:"collectionName", + CollectiblesNestedRole.IsCollection.int:"isCollection", + }.toTable + + 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 item = self.items[index.row] + let enumRole = role.CollectiblesNestedRole + + case enumRole: + of CollectiblesNestedRole.Uid: + result = newQVariant(item.getId()) + of CollectiblesNestedRole.ChainId: + result = newQVariant(item.getChainId()) + of CollectiblesNestedRole.Name: + result = newQVariant(item.getName()) + of CollectiblesNestedRole.IconUrl: + result = newQVariant(item.getIconUrl()) + of CollectiblesNestedRole.CollectionUid: + result = newQVariant(item.getCollectionId()) + of CollectiblesNestedRole.CollectionName: + result = newQVariant(item.getCollectionName()) + of CollectiblesNestedRole.IsCollection: + result = newQVariant(item.getIsCollection()) + + proc rowData(self: Model, index: int, column: string): string {.slot.} = + if (index >= self.items.len): + return + let item = self.items[index] + case column: + of "uid": result = item.getId() + of "chainId": result = $item.getChainId() + of "name": result = item.getName() + of "iconUrl": result = item.getIconUrl() + of "collectionUid": result = item.getCollectionId() + of "collectionName": result = item.getCollectionName() + of "isCollection": result = $item.getIsCollection() + + proc getCollectiblesPerCollectionId(items: seq[flat_item.Item]): Table[string, seq[flat_item.Item]] = + var collectiblesPerCollection = initTable[string, seq[flat_item.Item]]() + + for item in items: + let collectionId = item.getCollectionId() + if not collectiblesPerCollection.hasKey(collectionId): + collectiblesPerCollection[collectionId] = @[] + collectiblesPerCollection[collectionId].add(item) + + return collectiblesPerCollection + + proc refreshItems*(self: Model) {.slot.} = + self.beginResetModel() + self.items = @[] + + var collectiblesPerCollection = getCollectiblesPerCollectionId(self.flatModel.getItems()) + for collectionId, collectionCollectibles in collectiblesPerCollection.pairs: + if self.currentCollectionUid == "": + # No collection selected + # If the collection contains more than 1 collectible, we add a single collection item + # Otherwise, we add the collectible + if collectionCollectibles.len > 1: + let collectionItem = collectibleToCollectionNestedItem(collectionCollectibles[0]) + self.items.add(collectionItem) + else: + for collectible in collectionCollectibles: + let collectibleItem = collectibleToCollectibleNestedItem(collectible) + self.items.add(collectibleItem) + else: + if self.currentCollectionUid == collectionId: + for collectible in collectionCollectibles: + let collectibleItem = collectibleToCollectibleNestedItem(collectible) + self.items.add(collectibleItem) + # No need to keep looking + break + + self.endResetModel() + self.countChanged() + + proc resetModel*(self: Model) = + self.beginResetModel() + self.items = @[] + self.endResetModel() + self.countChanged() \ No newline at end of file diff --git a/src/app/modules/shared_models/collectibles_nested_utils.nim b/src/app/modules/shared_models/collectibles_nested_utils.nim new file mode 100644 index 0000000000..67584340b1 --- /dev/null +++ b/src/app/modules/shared_models/collectibles_nested_utils.nim @@ -0,0 +1,25 @@ +import sequtils, sugar, times +import collectibles_item as flat_item +import collectibles_nested_item as nested_item + +proc collectibleToCollectibleNestedItem*(flatItem: flat_item.Item): nested_item.Item = + return nested_item.initItem( + flatItem.getId(), + flatItem.getChainId(), + flatItem.getName(), + flatItem.getImageUrl(), + flatItem.getCollectionId(), + flatItem.getCollectionName(), + false + ) + +proc collectibleToCollectionNestedItem*(flatItem: flat_item.Item): nested_item.Item = + return nested_item.initItem( + flatItem.getCollectionId(), + flatItem.getChainId(), + flatItem.getCollectionName(), + flatItem.getCollectionImageUrl(), + flatItem.getCollectionId(), + flatItem.getCollectionName(), + true + ) diff --git a/src/app/modules/shared_models/collectibles_utils.nim b/src/app/modules/shared_models/collectibles_utils.nim index c142372322..8597cb4fb7 100644 --- a/src/app/modules/shared_models/collectibles_utils.nim +++ b/src/app/modules/shared_models/collectibles_utils.nim @@ -19,5 +19,7 @@ proc collectibleToItem*(c: backend.CollectibleHeader, isPinned: bool = false) : c.imageUrl, c.backgroundColor, c.collectionName, + c.collectionSlug, + c.collectionImageUrl, isPinned ) diff --git a/src/app/modules/shared_modules/collectibles/controller.nim b/src/app/modules/shared_modules/collectibles/controller.nim index eb72701c87..b19d19bbe0 100644 --- a/src/app/modules/shared_modules/collectibles/controller.nim +++ b/src/app/modules/shared_modules/collectibles/controller.nim @@ -23,6 +23,7 @@ QtObject: chainIds: seq[int] requestId: int32 + autofetch: bool proc setup(self: Controller) = self.QObject.setup @@ -30,33 +31,15 @@ QtObject: proc delete*(self: Controller) = self.QObject.delete - proc getModel*(self: Controller): QVariant {.slot.} = + proc getModel*(self: Controller): Model = + return self.model + + proc getModelAsVariant*(self: Controller): QVariant {.slot.} = return newQVariant(self.model) QtProperty[QVariant] model: - read = getModel + read = getModelAsVariant - proc processFilterOwnedCollectiblesResponse(self: Controller, response: JsonNode) = - defer: self.model.setIsFetching(false) - - let res = fromJson(response, backend_collectibles.FilterOwnedCollectiblesResponse) - - let isError = res.errorCode != ErrorCodeSuccess - defer: self.model.setIsError(isError) - - if isError: - error "error fetching collectibles entries: ", res.errorCode - return - - try: - let items = res.collectibles.map(header => collectibleToItem(header)) - self.model.setItems(items, res.offset, res.hasMore) - except Exception as e: - error "Error converting activity entries: ", e.msg - - proc resetModel*(self: Controller) {.slot.} = - self.model.setItems(@[], 0, true) - self.fetchFromStart = true proc loadMoreItems(self: Controller) {.slot.} = if self.model.getIsFetching(): @@ -77,6 +60,33 @@ QtObject: self.fetchFromStart = true error "error fetching collectibles entries: ", response.error + proc processFilterOwnedCollectiblesResponse(self: Controller, response: JsonNode) = + defer: self.model.setIsFetching(false) + + let res = fromJson(response, backend_collectibles.FilterOwnedCollectiblesResponse) + + let isError = res.errorCode != ErrorCodeSuccess + defer: self.model.setIsError(isError) + + if isError: + error "error fetching collectibles entries: ", res.errorCode + return + + try: + let items = res.collectibles.map(header => collectibleToItem(header)) + self.model.setItems(items, res.offset, res.hasMore) + except Exception as e: + error "Error converting activity entries: ", e.msg + + if self.autofetch and res.hasMore: + self.loadMoreItems() + + proc resetModel*(self: Controller) {.slot.} = + self.model.setItems(@[], 0, true) + self.fetchFromStart = true + if self.autofetch: + self.loadMoreItems() + proc setupEventHandlers(self: Controller) = self.eventsHandler.onOwnedCollectiblesFilteringDone(proc (jsonObj: JsonNode) = self.processFilterOwnedCollectiblesResponse(jsonObj) @@ -87,14 +97,15 @@ QtObject: ) self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc () = - self.resetModel() self.model.setIsUpdating(false) + self.resetModel() ) - proc newController*(requestId: int32, events: EventEmitter): Controller = + proc newController*(requestId: int32, autofetch: bool, events: EventEmitter): Controller = new(result, delete) result.requestId = requestId + result.autofetch = autofetch result.model = newModel() result.fetchFromStart = true diff --git a/src/backend/collectibles.nim b/src/backend/collectibles.nim index fbee5845e1..3c44f4394e 100644 --- a/src/backend/collectibles.nim +++ b/src/backend/collectibles.nim @@ -12,6 +12,7 @@ type CollectiblesRequestID* = enum WalletAccount ProfileShowcase + WalletSend # Declared in services/wallet/collectibles/service.go const eventCollectiblesOwnershipUpdateStarted*: string = "wallet-collectibles-ownership-update-started" @@ -40,7 +41,6 @@ type collectibles*: seq[CollectibleDetails] errorCode*: ErrorCode - # Responses proc fromJson*(e: JsonNode, T: typedesc[FilterOwnedCollectiblesResponse]): FilterOwnedCollectiblesResponse {.inline.} = var collectibles: seq[CollectibleHeader] diff --git a/src/backend/collectibles_types.nim b/src/backend/collectibles_types.nim index 1c947cf17c..f00eadcc34 100644 --- a/src/backend/collectibles_types.nim +++ b/src/backend/collectibles_types.nim @@ -54,6 +54,8 @@ type animationMediaType*: string backgroundColor*: string collectionName*: string + collectionSlug*: string + collectionImageUrl*: string # Mirrors services/wallet/collectibles/types.go CollectibleDetails CollectibleDetails* = ref object of RootObj @@ -250,7 +252,9 @@ proc `$`*(self: CollectibleHeader): string = animationUrl:{self.animationUrl}, animationMediaType:{self.animationMediaType}, backgroundColor:{self.backgroundColor}, - collectionName:{self.collectionName} + collectionName:{self.collectionName}, + collectionSlug:{self.collectionSlug}, + collectionImageUrl:{self.collectionImageUrl} )""" proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader {.inline.} = @@ -262,6 +266,8 @@ proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader { result.animationMediaType = t["animation_media_type"].getStr() result.backgroundColor = t["background_color"].getStr() result.collectionName = t["collection_name"].getStr() + result.collectionSlug = t["collection_slug"].getStr() + result.collectionImageUrl = t["collection_image_url"].getStr() # CollectibleDetails proc `$`*(self: CollectibleDetails): string = @@ -276,7 +282,7 @@ proc `$`*(self: CollectibleDetails): string = backgroundColor:{self.backgroundColor}, collectionName:{self.collectionName}, collectionSlug:{self.collectionSlug}, - collectionImageUrl:{self.collectionImageUrl}, + collectionImageUrl:{self.collectionImageUrl} )""" proc fromJson*(t: JsonNode, T: typedesc[CollectibleDetails]): CollectibleDetails {.inline.} =