From 68a903e3f094a11548742358416f1238960b2584 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Mon, 24 Aug 2020 16:50:49 -0400 Subject: [PATCH] feat: add error management to the collectibles plus reload button (cherry picked from commit 718f806557ffb041263e035845a21c2f7126807c) --- src/app/wallet/view.nim | 52 ++++++++- src/app/wallet/views/collectibles_list.nim | 30 ++++- src/status/wallet/collectibles.nim | 42 ++++--- ui/app/AppLayouts/Wallet/CollectiblesTab.qml | 7 ++ .../CollectiblesContainer.qml | 14 ++- .../CollectiblesContent.qml | 110 +++++++++++++----- .../CollectiblesHeader.qml | 2 +- 7 files changed, 199 insertions(+), 58 deletions(-) diff --git a/src/app/wallet/view.nim b/src/app/wallet/view.nim index a980ad26e3..4ec209aafe 100644 --- a/src/app/wallet/view.nim +++ b/src/app/wallet/view.nim @@ -285,37 +285,79 @@ QtObject: $(%*{ "address": address, "collectibleType": status_collectibles.CRYPTOKITTY, - "collectibles": status_collectibles.getCryptoKitties(address) + "collectiblesOrError": status_collectibles.getCryptoKitties(address) }) spawnAndSend(self, "setCollectiblesResult") do: $(%*{ "address": address, "collectibleType": status_collectibles.KUDO, - "collectibles": status_collectibles.getKudos(address) + "collectiblesOrError": status_collectibles.getKudos(address) }) spawnAndSend(self, "setCollectiblesResult") do: $(%*{ "address": address, "collectibleType": status_collectibles.ETHERMON, - "collectibles": status_collectibles.getEthermons(address) + "collectiblesOrError": status_collectibles.getEthermons(address) }) proc setCollectiblesResult(self: WalletView, collectiblesJSON: string) {.slot.} = let collectibleData = parseJson(collectiblesJSON) let address = collectibleData["address"].getStr + var collectibles: JSONNode + try: + collectibles = parseJson(collectibleData["collectiblesOrError"].getStr) + except Exception as e: + # We failed parsing, this means the result is an error string + self.currentCollectiblesLists.setErrorByType( + collectibleData["collectibleType"].getStr, + $collectibleData["collectiblesOrError"] + ) + return + # TODO Add the collectibleData to the Wallet account # let index = self.accounts.getAccountindexByAddress(address) # if index == -1: return # self.accounts.getAccount(index).collectiblesLists = collectiblesList if address == self.currentAccount.address: # Add CollectibleListJSON to the right list - # TODO check if instead we need to set an error self.currentCollectiblesLists.setCollectiblesJSONByType( collectibleData["collectibleType"].getStr, - $collectibleData["collectibles"] + $collectibles ) + proc reloadCollectible*(self: WalletView, collectibleType: string) {.slot.} = + let address = self.currentAccount.address + # TODO find a cooler way to do this + case collectibleType: + of CRYPTOKITTY: + spawnAndSend(self, "setCollectiblesResult") do: + $(%*{ + "address": address, + "collectibleType": status_collectibles.CRYPTOKITTY, + "collectiblesOrError": status_collectibles.getCryptoKitties(address) + }) + of KUDO: + spawnAndSend(self, "setCollectiblesResult") do: + $(%*{ + "address": address, + "collectibleType": status_collectibles.KUDO, + "collectiblesOrError": status_collectibles.getKudos(address) + }) + of ETHERMON: + spawnAndSend(self, "setCollectiblesResult") do: + $(%*{ + "address": address, + "collectibleType": status_collectibles.ETHERMON, + "collectiblesOrError": status_collectibles.getEthermons(address) + }) + else: + error "Unrecognized collectible" + return + + self.currentCollectiblesLists.setLoadingByType(collectibleType, 1) + + proc loadingTrxHistory*(self: WalletView, isLoading: bool) {.signal.} proc loadTransactionsForAccount*(self: WalletView, address: string) {.slot.} = diff --git a/src/app/wallet/views/collectibles_list.nim b/src/app/wallet/views/collectibles_list.nim index 138eeabc1c..334e07268c 100644 --- a/src/app/wallet/views/collectibles_list.nim +++ b/src/app/wallet/views/collectibles_list.nim @@ -27,13 +27,41 @@ QtObject: result.collectibleLists = @[] result.setup + proc setLoadingByType*(self: CollectiblesList, collectibleType: string, loading: int) = + var i = 0 + for collectibleList in self.collectibleLists: + if collectibleList.collectibleType == collectibleType: + collectibleList.loading = loading + let topLeft = self.createIndex(i, 0, nil) + let bottomRight = self.createIndex(i, 0, nil) + self.dataChanged(topLeft, bottomRight, @[CollectiblesRoles.Loading.int]) + break + i = i + 1 + proc setCollectiblesJSONByType*(self: CollectiblesList, collectibleType: string, collectiblesJSON: string) = + var i = 0 for collectibleList in self.collectibleLists: if collectibleList.collectibleType == collectibleType: collectibleList.collectiblesJSON = collectiblesJSON collectibleList.loading = 0 - self.forceUpdate() + collectibleList.error = "" + let topLeft = self.createIndex(i, 0, nil) + let bottomRight = self.createIndex(i, 0, nil) + self.dataChanged(topLeft, bottomRight, @[CollectiblesRoles.Loading.int, CollectiblesRoles.CollectiblesJSON.int, CollectiblesRoles.Error.int]) break + i = i + 1 + + proc setErrorByType*(self: CollectiblesList, collectibleType: string, error: string) = + var i = 0 + for collectibleList in self.collectibleLists: + if collectibleList.collectibleType == collectibleType: + collectibleList.error = error + collectibleList.loading = 0 + let topLeft = self.createIndex(i, 0, nil) + let bottomRight = self.createIndex(i, 0, nil) + self.dataChanged(topLeft, bottomRight, @[CollectiblesRoles.Loading.int, CollectiblesRoles.Error.int]) + break + i = i + 1 method rowCount(self: CollectiblesList, index: QModelIndex = nil): int = return self.collectibleLists.len diff --git a/src/status/wallet/collectibles.nim b/src/status/wallet/collectibles.nim index cd7d2eea7e..f9db3f7a87 100644 --- a/src/status/wallet/collectibles.nim +++ b/src/status/wallet/collectibles.nim @@ -58,8 +58,9 @@ proc tokensOfOwnerByIndex(contract: Contract, address: EthAddress): seq[int] = result.add(token) index = index + 1 -proc getCryptoKitties*(address: EthAddress): seq[Collectible] = - result = @[] +proc getCryptoKitties*(address: EthAddress): string = + var cryptokitties: seq[Collectible] + cryptokitties = @[] try: # TODO handle testnet -- does this API exist in testnet?? # TODO handle offset (recursive method?) @@ -80,7 +81,7 @@ proc getCryptoKitties*(address: EthAddress): seq[Collectible] = finalId = $id if (not (name.kind == JNull)): finalName = $name - result.add(Collectible(id: finalId, + cryptokitties.add(Collectible(id: finalId, name: finalName, image: kitty["image_url_png"].str, collectibleType: CRYPTOKITTY, @@ -90,21 +91,25 @@ proc getCryptoKitties*(address: EthAddress): seq[Collectible] = error "Error with this individual cat", msg = e2.msg, cat = kitty except Exception as e: error "Error getting Cryptokitties", msg = e.msg + return e.msg + + return $(%*cryptokitties) -proc getCryptoKitties*(address: string): seq[Collectible] = +proc getCryptoKitties*(address: string): string = let eth_address = parseAddress(address) result = getCryptoKitties(eth_address) -proc getEthermons*(address: EthAddress): seq[Collectible] = - result = @[] +proc getEthermons*(address: EthAddress): string = try: + var ethermons: seq[Collectible] + ethermons = @[] let contract = getContract("ethermon") if contract == nil: return let tokens = tokensOfOwnerByIndex(contract, address) if (tokens.len == 0): - return result + return $(%*ethermons) let tokensJoined = strutils.join(tokens, ",") let url = fmt"https://www.ethermon.io/api/monster/get_data?monster_ids={tokensJoined}" @@ -116,36 +121,40 @@ proc getEthermons*(address: EthAddress): seq[Collectible] = var i = 0 for monsterKey in json.keys(monsters): let monster = monsters[monsterKey] - result.add(Collectible(id: $tokens[i], + ethermons.add(Collectible(id: $tokens[i], name: monster["class_name"].str, image: monster["image"].str, collectibleType: ETHERMON, description: "", externalUrl: "")) i = i + 1 + + return $(%*ethermons) except Exception as e: error "Error getting Ethermons", msg = e.msg + result = e.msg -proc getEthermons*(address: string): seq[Collectible] = +proc getEthermons*(address: string): string = let eth_address = parseAddress(address) result = getEthermons(eth_address) -proc getKudos*(address: EthAddress): seq[Collectible] = - result = @[] +proc getKudos*(address: EthAddress): string = try: + var kudos: seq[Collectible] + kudos = @[] let contract = getContract("kudos") if contract == nil: return let tokens = tokensOfOwnerByIndex(contract, address) if (tokens.len == 0): - return result + return $(%*kudos) for token in tokens: let url = getTokenUri(contract, token.u256) if (url == ""): - return result + return $(%*kudos) let client = newHttpClient() client.headers = newHttpHeaders({ "Content-Type": "application/json" }) @@ -153,15 +162,18 @@ proc getKudos*(address: EthAddress): seq[Collectible] = let response = client.request(url) let kudo = parseJson(response.body) - result.add(Collectible(id: $token, + kudos.add(Collectible(id: $token, name: kudo["name"].str, image: kudo["image"].str, collectibleType: KUDO, description: kudo["description"].str, externalUrl: kudo["external_url"].str)) + + return $(%*kudos) except Exception as e: error "Error getting Kudos", msg = e.msg + result = e.msg -proc getKudos*(address: string): seq[Collectible] = +proc getKudos*(address: string): string = let eth_address = parseAddress(address) result = getKudos(eth_address) diff --git a/ui/app/AppLayouts/Wallet/CollectiblesTab.qml b/ui/app/AppLayouts/Wallet/CollectiblesTab.qml index 84298a569d..da9948ac6a 100644 --- a/ui/app/AppLayouts/Wallet/CollectiblesTab.qml +++ b/ui/app/AppLayouts/Wallet/CollectiblesTab.qml @@ -60,6 +60,13 @@ Item { } } } + + Connections { + target: walletModel.collectiblesLists + onDataChanged: { + checkCollectiblesVisibility() + } + } } /*##^## diff --git a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContainer.qml b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContainer.qml index 7c3a004ec0..c9dee4a0ce 100644 --- a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContainer.qml +++ b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContainer.qml @@ -6,14 +6,21 @@ import "../../../../../shared" Item { property url collectibleIconSource: "../../../../img/collectibles/CryptoKitties.png" property string collectibleName: "CryptoKitties" - property string collectibleType: "cryptokitty" property bool collectiblesOpened: false property var collectiblesModal property string buttonText: "View in Cryptokitties" property var getLink: function () {} property var collectibles: { + if (error) { + return [] + } + try { - return JSON.parse(collectiblesJSON) + var result = JSON.parse(collectiblesJSON) + if (typeof result === "string") { + return JSON.parse(result) + } + return result } catch (e) { console.error('Error parsing collectibles for:', collectibleName) console.error('JSON:', collectiblesJSON) @@ -22,7 +29,7 @@ Item { } } // Adding active instead of just using visible, because visible counts as false when the parent is not visible - property bool active: !!loading || collectibles.length > 0 + property bool active: !!loading || !!error || collectibles.length > 0 id: root visible: active @@ -44,7 +51,6 @@ Item { id: collectiblesContent visible: root.collectiblesOpened collectiblesModal: root.collectiblesModal - collectibleType: root.collectibleType buttonText: root.buttonText getLink: root.getLink anchors.top: collectiblesHeader.bottom diff --git a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContent.qml b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContent.qml index 13d9c01b78..5f25729420 100644 --- a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContent.qml +++ b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesContent.qml @@ -7,55 +7,101 @@ import "../../../../../shared" ScrollView { readonly property int imageSize: 164 - property string collectibleType: "cryptokitty" property var collectiblesModal property string buttonText: "View in Cryptokitties" property var getLink: function () {} property var collectibles: [] id: root - height: visible ? contentRow.height : 0 + height: visible ? contentLoader.item.height : 0 width: parent.width ScrollBar.vertical.policy: ScrollBar.AlwaysOff ScrollBar.horizontal.policy: ScrollBar.AsNeeded clip: true - Row { - id: contentRow - bottomPadding: Style.current.padding - spacing: Style.current.padding + Loader { + id: contentLoader + active: true + width: parent.width + height: root.imageSize + sourceComponent: !!error ? errorComponent : collectiblesContentComponent + } - Repeater { - model: collectibles + Component { + id: errorComponent - Rectangle { - radius: 16 - border.width: 1 - border.color: Style.current.border - color: Style.current.background - width: collectibleImage.width - height: collectibleImage.height + Item { + width: parent.width + height: root.imageSize - Image { - id: collectibleImage - width: root.imageSize - height: root.imageSize - source: modelData.image - fillMode: Image.PreserveAspectCrop + Item { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + height: childrenRect.height + width: somethingWentWrongText.width + + StyledText { + id: somethingWentWrongText + text: qsTr("Something went wrong") + anchors.horizontalCenter: parent.horizontalCenter + color: Style.current.secondaryText + font.pixelSize: 13 } - MouseArea { - cursorShape: Qt.PointingHandCursor - anchors.fill: parent + StyledButton { + label: qsTr("Reload") + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: somethingWentWrongText.bottom + anchors.topMargin: Style.current.halfPadding onClicked: { - collectiblesModal.openModal({ - name: modelData.name, - id: modelData.id, - description: modelData.description, - buttonText: root.buttonText, - link: root.getLink(modelData.id, modelData.externalUrl), - image: modelData.image - }) + walletModel.reloadCollectible(collectibleType) + } + } + } + } + + } + + Component { + id: collectiblesContentComponent + + Row { + id: contentRow + bottomPadding: Style.current.padding + spacing: Style.current.padding + + Repeater { + model: collectibles + + Rectangle { + radius: 16 + border.width: 1 + border.color: Style.current.border + color: Style.current.background + width: collectibleImage.width + height: collectibleImage.height + + Image { + id: collectibleImage + width: root.imageSize + height: root.imageSize + source: modelData.image + fillMode: Image.PreserveAspectCrop + } + + MouseArea { + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + onClicked: { + collectiblesModal.openModal({ + name: modelData.name, + id: modelData.id, + description: modelData.description, + buttonText: root.buttonText, + link: root.getLink(modelData.id, modelData.externalUrl), + image: modelData.image + }) + } } } } diff --git a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesHeader.qml b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesHeader.qml index 4dafa8e35d..677eda9240 100644 --- a/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesHeader.qml +++ b/ui/app/AppLayouts/Wallet/components/collectiblesComponents/CollectiblesHeader.qml @@ -60,7 +60,7 @@ Rectangle { StyledText { id: numberCollectibleText color: Style.current.secondaryText - text: collectibleHeader.collectiblesQty + text: !!error ? "-" : collectibleHeader.collectiblesQty font.pixelSize: 15 anchors.verticalCenter: parent.verticalCenter }