From 158bb87b4ae08435f3aaa6f03bc6808f01aa5344 Mon Sep 17 00:00:00 2001 From: Cuteivist Date: Tue, 3 Oct 2023 14:15:11 +0200 Subject: [PATCH] @bug(wallet/activity): Implemented collectibles model (#12294) --- .../activity/collectibles_item.nim | 61 +++++ .../activity/collectibles_model.nim | 219 ++++++++++++++++++ .../wallet_section/activity/controller.nim | 43 ++++ .../activity/events_handler.nim | 3 + .../main/wallet_section/activity/status.nim | 7 + src/backend/activity.nim | 62 +++++ .../Wallet/panels/ActivityFilterPanel.qml | 9 +- .../Wallet/popups/ActivityFilterMenu.qml | 2 + .../ActivityTokensFilterSubMenu.qml | 8 +- .../Wallet/stores/ActivityFiltersStore.qml | 9 +- ui/app/AppLayouts/Wallet/stores/RootStore.qml | 2 +- .../Wallet/views/TransactionDetailView.qml | 1 + ui/imports/shared/views/HistoryView.qml | 6 + vendor/status-go | 2 +- 14 files changed, 421 insertions(+), 13 deletions(-) create mode 100644 src/app/modules/main/wallet_section/activity/collectibles_item.nim create mode 100644 src/app/modules/main/wallet_section/activity/collectibles_model.nim diff --git a/src/app/modules/main/wallet_section/activity/collectibles_item.nim b/src/app/modules/main/wallet_section/activity/collectibles_item.nim new file mode 100644 index 0000000000..044c3ff504 --- /dev/null +++ b/src/app/modules/main/wallet_section/activity/collectibles_item.nim @@ -0,0 +1,61 @@ +import strformat, stint +import backend/activity as backend + +type + CollectibleItem* = object + chainId: int + contractAddress: string + tokenId: UInt256 + name: string + imageUrl: string + +proc initItem*( + chainId: int, + contractAddress: string, + tokenId: UInt256, + name: string, + imageUrl: string +): CollectibleItem = + result.chainId = chainId + result.contractAddress = contractAddress + result.tokenId = tokenId + result.name = if (name != ""): name else: ("#" & tokenId.toString()) + result.imageUrl = imageUrl + +proc collectibleToItem*(c: backend.CollectibleHeader) : CollectibleItem = + return initItem( + c.id.contractID.chainID, + c.id.contractID.address, + c.id.tokenID, + c.name, + c.imageUrl + ) + +proc `$`*(self: CollectibleItem): string = + result = fmt"""Collectibles( + chainId: {self.chainId}, + contractAddress: {self.contractAddress}, + tokenId: {self.tokenId}, + name: {self.name}, + imageUrl: {self.imageUrl} + ]""" + +proc getChainId*(self: CollectibleItem): int = + return self.chainId + +proc getContractAddress*(self: CollectibleItem): string = + return self.contractAddress + +proc getTokenId*(self: CollectibleItem): UInt256 = + return self.tokenId + +# Unique ID to identify collectible, generated by us +proc getId*(self: CollectibleItem): string = + return fmt"{self.getChainId}+{self.getContractAddress}+{self.getTokenID}" + +proc getName*(self: CollectibleItem): string = + return self.name + +proc getImageUrl*(self: CollectibleItem): string = + return self.imageUrl + diff --git a/src/app/modules/main/wallet_section/activity/collectibles_model.nim b/src/app/modules/main/wallet_section/activity/collectibles_model.nim new file mode 100644 index 0000000000..0115901fd3 --- /dev/null +++ b/src/app/modules/main/wallet_section/activity/collectibles_model.nim @@ -0,0 +1,219 @@ +import NimQml, Tables, strutils, strformat, sequtils, stint +import logging + +import ./collectibles_item +import web3/ethtypes as eth +import backend/activity as backend_activity + +type + CollectibleRole* {.pure.} = enum + Uid = UserRole + 1, + ChainId + ContractAddress + TokenId + Name + ImageUrl + +QtObject: + type + CollectiblesModel* = ref object of QAbstractListModel + items: seq[CollectibleItem] + hasMore: bool + + proc delete(self: CollectiblesModel) = + self.items = @[] + self.QAbstractListModel.delete + + proc setup(self: CollectiblesModel) = + self.QAbstractListModel.setup + + proc newCollectiblesModel*(): CollectiblesModel = + new(result, delete) + result.setup + result.items = @[] + result.hasMore = true + + proc `$`*(self: CollectiblesModel): string = + for i in 0 ..< self.items.len: + result &= fmt"""[{i}]:({$self.items[i]})""" + + proc getCollectiblesCount*(self: CollectiblesModel): int = + return self.items.len + + proc countChanged(self: CollectiblesModel) {.signal.} + proc getCount*(self: CollectiblesModel): int {.slot.} = + return self.items.len + + QtProperty[int] count: + read = getCount + notify = countChanged + + proc hasMoreChanged*(self: CollectiblesModel) {.signal.} + proc getHasMore*(self: CollectiblesModel): bool {.slot.} = + self.hasMore + QtProperty[bool] hasMore: + read = getHasMore + notify = hasMoreChanged + + proc setHasMore(self: CollectiblesModel, hasMore: bool) = + if hasMore == self.hasMore: + return + self.hasMore = hasMore + self.hasMoreChanged() + + method canFetchMore*(self: CollectiblesModel, parent: QModelIndex): bool = + return self.hasMore + + proc loadMoreItems(self: CollectiblesModel) {.signal.} + + proc loadMore*(self: CollectiblesModel) {.slot.} = + self.loadMoreItems() + + method fetchMore*(self: CollectiblesModel, parent: QModelIndex) = + self.loadMore() + + method rowCount*(self: CollectiblesModel, index: QModelIndex = nil): int = + return self.getCount() + + method roleNames(self: CollectiblesModel): Table[int, string] = + { + CollectibleRole.Uid.int:"uid", + CollectibleRole.ChainId.int:"chainId", + CollectibleRole.ContractAddress.int:"contractAddress", + CollectibleRole.TokenId.int:"tokenId", + CollectibleRole.Name.int:"name", + CollectibleRole.ImageUrl.int:"imageUrl", + }.toTable + + method data(self: CollectiblesModel, index: QModelIndex, role: int): QVariant = + if (not index.isValid): + return + + if (index.row < 0 or index.row >= self.getCount()): + return + + let enumRole = role.CollectibleRole + + if index.row < self.items.len: + let item = self.items[index.row] + case enumRole: + of CollectibleRole.Uid: + result = newQVariant(item.getId()) + of CollectibleRole.ChainId: + result = newQVariant(item.getChainId()) + of CollectibleRole.ContractAddress: + result = newQVariant(item.getContractAddress()) + of CollectibleRole.TokenId: + result = newQVariant(item.getTokenId().toString()) + of CollectibleRole.Name: + result = newQVariant(item.getName()) + of CollectibleRole.ImageUrl: + result = newQVariant(item.getImageUrl()) + else: + error "Invalid role for loading item" + result = newQVariant() + + proc rowData(self: CollectiblesModel, index: int, column: string): string {.slot.} = + if (index >= self.items.len): + return + let item = self.items[index] + case column: + of "uid": result = item.getId() + of "chainId": result = $item.getChainId() + of "contractAddress": result = item.getContractAddress() + of "tokenId": result = item.getTokenId().toString() + of "name": result = item.getName() + of "imageUrl": result = item.getImageUrl() + + proc appendCollectibleItems(self: CollectiblesModel, newItems: seq[CollectibleItem]) = + if len(newItems) == 0: + return + + let parentModelIndex = newQModelIndex() + defer: parentModelIndex.delete + + # Start after the current last real item + let startIdx = self.items.len + # End at the new last real item + let endIdx = startIdx + newItems.len - 1 + + self.beginInsertRows(parentModelIndex, startIdx, endIdx) + self.items.insert(newItems, startIdx) + self.endInsertRows() + self.countChanged() + + proc removeCollectibleItems(self: CollectiblesModel) = + if self.items.len <= 0: + return + + let parentModelIndex = newQModelIndex() + defer: parentModelIndex.delete + + # Start from the beginning + let startIdx = 0 + # End at the last real item + let endIdx = startIdx + self.items.len - 1 + + self.beginRemoveRows(parentModelIndex, startIdx, endIdx) + self.items = @[] + self.endRemoveRows() + self.countChanged() + + proc getItems*(self: CollectiblesModel): seq[CollectibleItem] = + return self.items + + proc setItems*(self: CollectiblesModel, newItems: seq[CollectibleItem], offset: int, hasMore: bool) = + if offset == 0: + self.removeCollectibleItems() + elif offset != self.getCollectiblesCount(): + error "invalid offset" + return + + self.appendCollectibleItems(newItems) + self.setHasMore(hasMore) + + proc getImageUrl*(self: CollectiblesModel, id: string): string {.slot.} = + for item in self.items: + if(cmpIgnoreCase(item.getId(), id) == 0): + return item.getImageUrl() + return "" + + proc getName*(self: CollectiblesModel, id: string): string {.slot.} = + for item in self.items: + if(cmpIgnoreCase(item.getId(), id) == 0): + return item.getName() + return "" + + proc getActivityToken*(self: CollectiblesModel, id: string): backend_activity.Token = + for item in self.items: + if(cmpIgnoreCase(item.getId(), id) == 0): + result.tokenType = backend_activity.TokenType.Erc721 + result.chainId = backend_activity.ChainId(item.getChainId()) + var contract = item.getContractAddress() + if len(contract) > 0: + var address: eth.Address + address = eth.fromHex(eth.Address, contract) + result.address = some(address) + var tokenId = item.getTokenId() + if tokenId > 0: + result.tokenId = some(backend_activity.TokenId("0x" & stint.toHex(tokenId))) + return result + + # Fallback, use data from id + var parts = id.split("+") + if len(parts) == 3: + result.chainId = backend_activity.ChainId(parseInt(parts[0])) + result.address = some(eth.fromHex(eth.Address, parts[1])) + var tokenIdInt = u256(parseInt(parts[2])) + result.tokenId = some(backend_activity.TokenId("0x" & stint.toHex(tokenIdInt))) + + return result + + proc getUidForData*(self: CollectiblesModel, tokenId: string, tokenAddress: string, chainId: int): string {.slot.} = + for item in self.items: + if(cmpIgnoreCase(item.getTokenId().toString(), tokenId) == 0 and cmpIgnoreCase(item.getContractAddress(), tokenAddress) == 0): + return item.getId() + # Fallback, create uid from data, because it still might not be fetched + if chainId > 0 and len(tokenAddress) > 0 and len(tokenId) > 0: + return $chainId & "+" & tokenAddress & "+" & tokenId + return "" \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/activity/controller.nim b/src/app/modules/main/wallet_section/activity/controller.nim index c96b5fbaf3..abef26a418 100644 --- a/src/app/modules/main/wallet_section/activity/controller.nim +++ b/src/app/modules/main/wallet_section/activity/controller.nim @@ -5,6 +5,8 @@ import model import entry import entry_details import recipients_model +import collectibles_model +import collectibles_item import events_handler import status @@ -29,6 +31,7 @@ proc toRef*[T](obj: T): ref T = const FETCH_BATCH_COUNT_DEFAULT = 10 const FETCH_RECIPIENTS_BATCH_COUNT_DEFAULT = 2000 +const FETCH_COLLECTIBLES_BATCH_COUNT_DEFAULT = 2000 type CollectiblesToTokenConverter* = proc (id: string): backend_activity.Token @@ -39,6 +42,7 @@ QtObject: model: Model recipientsModel: RecipientsModel + collectiblesModel: CollectiblesModel currentActivityFilter: backend_activity.ActivityFilter currencyService: currency_service.Service tokenService: token_service.Service @@ -77,6 +81,12 @@ QtObject: QtProperty[QVariant] recipientsModel: read = getRecipientsModel + proc getCollectiblesModel*(self: Controller): QVariant {.slot.} = + return newQVariant(self.collectiblesModel) + + QtProperty[QVariant] collectiblesModel: + read = getCollectiblesModel + proc buildMultiTransactionExtraData(self: Controller, metadata: backend_activity.ActivityEntry): ExtraData = if metadata.symbolIn.isSome(): result.inAmount = self.currencyService.parseCurrencyValue(metadata.symbolIn.get(), metadata.amountIn) @@ -170,6 +180,22 @@ QtObject: error "error fetching activity entries: ", response.error return + proc updateCollectiblesModel*(self: Controller) {.slot.} = + self.status.setLoadingCollectibles(true) + let res = backend_activity.getActivityCollectiblesAsync(self.requestId, self.chainIds, self.addresses, 0, FETCH_COLLECTIBLES_BATCH_COUNT_DEFAULT) + if res.error != nil: + self.status.setLoadingCollectibles(false) + error "error fetching collectibles: ", res.error + return + + proc loadMoreCollectibles*(self: Controller) {.slot.} = + self.status.setLoadingCollectibles(true) + let res = backend_activity.getActivityCollectiblesAsync(self.requestId, self.chainIds, self.addresses, self.collectiblesModel.getCount(), FETCH_COLLECTIBLES_BATCH_COUNT_DEFAULT) + if res.error != nil: + self.status.setLoadingCollectibles(false) + error "error fetching collectibles: ", res.error + return + proc setFilterTime*(self: Controller, startTimestamp: int, endTimestamp: int) {.slot.} = self.currentActivityFilter.period = backend_activity.newPeriod(startTimestamp, endTimestamp) @@ -234,6 +260,21 @@ QtObject: self.status.setStartTimestamp(res.timestamp) ) + self.eventsHandler.onGetCollectiblesDone(proc (jsonObj: JsonNode) = + defer: self.status.setLoadingCollectibles(false) + let res = fromJson(jsonObj, backend_activity.GetCollectiblesResponse) + + if res.errorCode != ErrorCodeSuccess: + error "error fetching collectibles: ", res.errorCode + return + + try: + let items = res.collectibles.map(header => collectibleToItem(header)) + self.collectiblesModel.setItems(items, res.offset, res.hasMore) + except Exception as e: + error "Error converting activity entries: ", e.msg + ) + self.eventsHandler.onNewDataAvailable(proc () = self.status.setNewDataAvailable(true) ) @@ -248,6 +289,7 @@ QtObject: result.requestId = requestId result.model = newModel() result.recipientsModel = newRecipientsModel() + result.collectiblesModel = newCollectiblesModel() result.tokenService = tokenService result.currentActivityFilter = backend_activity.getIncludeAllActivityFilter() @@ -364,6 +406,7 @@ QtObject: proc setFilterChains*(self: Controller, chainIds: seq[int], allEnabled: bool) = self.chainIds = chainIds self.status.setIsFilterDirty(true) + self.status.emitFilterChainsChanged() self.status.emitFilterChainsChanged() self.updateAssetsIdentities() diff --git a/src/app/modules/main/wallet_section/activity/events_handler.nim b/src/app/modules/main/wallet_section/activity/events_handler.nim index deaf63fa39..cd3e20fca6 100644 --- a/src/app/modules/main/wallet_section/activity/events_handler.nim +++ b/src/app/modules/main/wallet_section/activity/events_handler.nim @@ -46,6 +46,9 @@ QtObject: proc onGetOldestTimestampDone*(self: EventsHandler, handler: EventCallbackProc) = self.eventHandlers[backend_activity.eventActivityGetOldestTimestampDone] = handler + proc onGetCollectiblesDone*(self: EventsHandler, handler: EventCallbackProc) = + self.eventHandlers[backend_activity.eventActivityGetCollectiblesDone] = handler + proc onNewDataAvailable*(self: EventsHandler, handler: proc()) = self.newDataAvailableFn = handler diff --git a/src/app/modules/main/wallet_section/activity/status.nim b/src/app/modules/main/wallet_section/activity/status.nim index 9891c751d7..6566bb184d 100644 --- a/src/app/modules/main/wallet_section/activity/status.nim +++ b/src/app/modules/main/wallet_section/activity/status.nim @@ -13,6 +13,7 @@ QtObject: errorCode: backend_activity.ErrorCode loadingRecipients: Atomic[int] + loadingCollectibles: Atomic[int] loadingStartTimestamp: Atomic[int] startTimestamp: int @@ -44,6 +45,12 @@ QtObject: discard fetchAdd(self.loadingRecipients, if loadingData: 1 else: -1) self.loadingRecipientsChanged() + proc loadingCollectiblesChanged*(self: Status) {.signal.} + + proc setLoadingCollectibles*(self: Status, loadingData: bool) = + discard fetchAdd(self.loadingCollectibles, if loadingData: 1 else: -1) + self.loadingCollectiblesChanged() + proc loadingStartTimestampChanged*(self: Status) {.signal.} proc setLoadingStartTimestamp*(self: Status, loadingData: bool) = diff --git a/src/backend/activity.nim b/src/backend/activity.nim index f074880745..a0536b8e83 100644 --- a/src/backend/activity.nim +++ b/src/backend/activity.nim @@ -20,6 +20,7 @@ const eventActivityFilteringUpdate*: string = "wallet-activity-filtering-entries const eventActivityGetRecipientsDone*: string = "wallet-activity-get-recipients-result" const eventActivityGetOldestTimestampDone*: string = "wallet-activity-get-oldest-timestamp-result" const eventActivityFetchTransactionDetails*: string = "wallet-activity-fetch-transaction-details-result" +const eventActivityGetCollectiblesDone*: string = "wallet-activity-get-collectibles" type Period* = object @@ -527,6 +528,67 @@ rpc(getOldestActivityTimestampAsync, "wallet"): requestId: int32 addresses: seq[string] +type + # Mirrors services/wallet/thirdparty/collectible_types.go ContractID + ContractID* = ref object of RootObj + chainID*: int + address*: string + + # Mirrors services/wallet/thirdparty/collectible_types.go CollectibleUniqueID + CollectibleUniqueID* = ref object of RootObj + contractID*: ContractID + tokenID*: UInt256 + + # see services/wallet/activity/service.go CollectibleHeader + CollectibleHeader* = object + id* : CollectibleUniqueID + name*: string + imageUrl*: string + + # see services/wallet/activity/service.go CollectiblesResponse + GetCollectiblesResponse* = object + collectibles*: seq[CollectibleHeader] + offset*: int + hasMore*: bool + errorCode*: ErrorCode + +proc fromJson*(t: JsonNode, T: typedesc[ContractID]): ContractID {.inline.} = + result = ContractID() + result.chainID = t["chainID"].getInt() + result.address = t["address"].getStr() + +proc fromJson*(t: JsonNode, T: typedesc[CollectibleUniqueID]): CollectibleUniqueID {.inline.} = + result = CollectibleUniqueID() + result.contractID = fromJson(t["contractID"], ContractID) + result.tokenID = stint.parse(t["tokenID"].getStr(), UInt256) + +proc fromJson*(t: JsonNode, T: typedesc[CollectibleHeader]): CollectibleHeader {.inline.} = + result = CollectibleHeader() + result.id = fromJson(t["id"], CollectibleUniqueID) + result.name = t["name"].getStr() + result.imageUrl = t["image_url"].getStr() + +proc fromJson*(e: JsonNode, T: typedesc[GetCollectiblesResponse]): GetCollectiblesResponse {.inline.} = + var collectibles: seq[CollectibleHeader] = @[] + if e.hasKey("collectibles"): + let jsonCollectibles = e["collectibles"] + for item in jsonCollectibles.getElems(): + collectibles.add(fromJson(item, CollectibleHeader)) + + result = T( + collectibles: collectibles, + hasMore: e["hasMore"].getBool(), + offset: e["offset"].getInt(), + errorCode: ErrorCode(e["errorCode"].getInt()) + ) + +rpc(getActivityCollectiblesAsync, "wallet"): + requestId: int32 + chainIDs: seq[int] + addresses: seq[string] + offset: int + limit: int + rpc(getMultiTxDetails, "wallet"): id: int diff --git a/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml b/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml index 69e9dc9063..87da2cd2fc 100644 --- a/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/ActivityFilterPanel.qml @@ -178,11 +178,11 @@ Column { onClosed: activityFilterStore.toggleCollectibles(uid) Connections { - // Collectibles model is fetched asynchronousl, so data might not be available - target: activityFilterStore.collectiblesList + // Collectibles model is fetched asynchronously, so data might not be available + target: activityFilterStore enabled: !collectibleTag.isValid - function onIsFetchingChanged() { - if (activityFilterStore.collectiblesList.isFetching || !activityFilterStore.collectiblesList.hasMore) + function onLoadingCollectiblesChanged() { + if (activityFilterStore.loadingCollectibles || !activityFilterStore.collectiblesList.hasMore) return collectibleTag.uid = "" collectibleTag.uid = modelData @@ -262,6 +262,7 @@ Column { store: root.store recentsList: activityFilterStore.recentsList loadingRecipients: activityFilterStore.loadingRecipients + loadingCollectibles: activityFilterStore.loadingCollectibles recentsFilters: activityFilterStore.recentsFilters savedAddressList: activityFilterStore.savedAddressList savedAddressFilters: activityFilterStore.savedAddressFilters diff --git a/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml b/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml index 929a6e7b80..dd0bbbf41a 100644 --- a/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml +++ b/ui/app/AppLayouts/Wallet/popups/ActivityFilterMenu.qml @@ -33,6 +33,7 @@ StatusMenu { // Collectibles filter property var collectiblesList: [] property var collectiblesFilter: [] + property bool loadingCollectibles: false readonly property bool allCollectiblesChecked: tokensMenu.allCollectiblesChecked signal updateCollectiblesFilter(string uid) @@ -96,6 +97,7 @@ StatusMenu { tokensFilter: root.tokensFilter collectiblesList: root.collectiblesList collectiblesFilter: root.collectiblesFilter + loadingCollectibles: root.loadingCollectibles onTokenToggled: updateTokensFilter(tokenSymbol) onCollectibleToggled: updateCollectiblesFilter(uid) closePolicy: root.closePolicy diff --git a/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTokensFilterSubMenu.qml b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTokensFilterSubMenu.qml index 2dde47a261..190f352134 100644 --- a/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTokensFilterSubMenu.qml +++ b/ui/app/AppLayouts/Wallet/popups/filterSubMenus/ActivityTokensFilterSubMenu.qml @@ -20,6 +20,7 @@ StatusMenu { property var tokensList: [] readonly property bool allTokensChecked: tokensFilter.length === 0 + property bool loadingCollectibles: false property var collectiblesList: [] property var collectiblesFilter: [] readonly property bool allCollectiblesChecked: collectiblesFilter.length === 0 @@ -37,11 +38,6 @@ StatusMenu { collectiblesSearchBox.reset() } - QtObject { - id: d - readonly property bool isFetching: root.collectiblesList.isFetching - } - contentItem: ColumnLayout { spacing: 12 MenuBackButton { @@ -186,7 +182,7 @@ StatusMenu { allChecked: root.allCollectiblesChecked checked: !loading && (root.allCollectiblesChecked || root.collectiblesFilter.includes(model.uid)) onActionTriggered: root.collectibleToggled(model.uid) - loading: d.isFetching + loading: root.loadingCollectibles } } } diff --git a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml index 2f7114936e..01c02106aa 100644 --- a/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/ActivityFiltersStore.qml @@ -193,8 +193,15 @@ QtObject { } // Collectibles Filters - property var collectiblesList: walletSection.collectiblesController.model + property var collectiblesList: activityController.collectiblesModel property var collectiblesFilter: [] + property bool loadingCollectibles: activityController.status.loadingCollectibles + function updateCollectiblesModel() { + activityController.updateCollectiblesModel() + } + function loadMoreCollectibles() { + activityController.loadMoreCollectibles() + } function toggleCollectibles(uid) { // update filters collectiblesFilter = d.toggleFilterState(collectiblesFilter, uid, collectiblesList.count) diff --git a/ui/app/AppLayouts/Wallet/stores/RootStore.qml b/ui/app/AppLayouts/Wallet/stores/RootStore.qml index 48cc2f5c84..75f7cba4d4 100644 --- a/ui/app/AppLayouts/Wallet/stores/RootStore.qml +++ b/ui/app/AppLayouts/Wallet/stores/RootStore.qml @@ -275,7 +275,7 @@ QtObject { } function isTxRepeatable(tx) { - if (tx.txType !== Constants.TransactionType.Send) + if (!tx || tx.txType !== Constants.TransactionType.Send) return false let res = root.lookupAddressObject(tx.sender) diff --git a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml b/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml index b7aded2c93..589a124134 100644 --- a/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml +++ b/ui/app/AppLayouts/Wallet/views/TransactionDetailView.qml @@ -12,6 +12,7 @@ import StatusQ.Popups 0.1 import shared.controls 1.0 import shared.panels 1.0 +import shared.stores 1.0 import utils 1.0 import shared.popups.send 1.0 diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml index 164eecb7d9..27e75be95b 100644 --- a/ui/imports/shared/views/HistoryView.qml +++ b/ui/imports/shared/views/HistoryView.qml @@ -48,6 +48,7 @@ ColumnLayout { WalletStores.RootStore.currentActivityFiltersStore.applyAllFilters() } + WalletStores.RootStore.currentActivityFiltersStore.updateCollectiblesModel() WalletStores.RootStore.currentActivityFiltersStore.updateRecipientsModel() } @@ -58,10 +59,15 @@ ColumnLayout { RootStore.updateTransactionFilter() } function onFilterChainsChanged() { + WalletStores.RootStore.currentActivityFiltersStore.updateCollectiblesModel() WalletStores.RootStore.currentActivityFiltersStore.updateRecipientsModel() } } + Connections { + enabled: root.visible + } + QtObject { id: d readonly property bool isInitialLoading: RootStore.loadingHistoryTransactions && transactionListRoot.count === 0 diff --git a/vendor/status-go b/vendor/status-go index cff96f99e0..ecc8b4cb55 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit cff96f99e0997b3f3197eecf7b568f7c2e42cac1 +Subproject commit ecc8b4cb5513ed29deb4fdc85eaeed5e96d1e562