feat: add error management to the collectibles

plus reload button

(cherry picked from commit 718f806557ffb041263e035845a21c2f7126807c)
This commit is contained in:
Jonathan Rainville 2020-08-24 16:50:49 -04:00
parent 3219b0f5f4
commit 9eaf0a2d90
7 changed files with 199 additions and 58 deletions

View File

@ -285,37 +285,79 @@ QtObject:
$(%*{ $(%*{
"address": address, "address": address,
"collectibleType": status_collectibles.CRYPTOKITTY, "collectibleType": status_collectibles.CRYPTOKITTY,
"collectibles": status_collectibles.getCryptoKitties(address) "collectiblesOrError": status_collectibles.getCryptoKitties(address)
}) })
spawnAndSend(self, "setCollectiblesResult") do: spawnAndSend(self, "setCollectiblesResult") do:
$(%*{ $(%*{
"address": address, "address": address,
"collectibleType": status_collectibles.KUDO, "collectibleType": status_collectibles.KUDO,
"collectibles": status_collectibles.getKudos(address) "collectiblesOrError": status_collectibles.getKudos(address)
}) })
spawnAndSend(self, "setCollectiblesResult") do: spawnAndSend(self, "setCollectiblesResult") do:
$(%*{ $(%*{
"address": address, "address": address,
"collectibleType": status_collectibles.ETHERMON, "collectibleType": status_collectibles.ETHERMON,
"collectibles": status_collectibles.getEthermons(address) "collectiblesOrError": status_collectibles.getEthermons(address)
}) })
proc setCollectiblesResult(self: WalletView, collectiblesJSON: string) {.slot.} = proc setCollectiblesResult(self: WalletView, collectiblesJSON: string) {.slot.} =
let collectibleData = parseJson(collectiblesJSON) let collectibleData = parseJson(collectiblesJSON)
let address = collectibleData["address"].getStr 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 # TODO Add the collectibleData to the Wallet account
# let index = self.accounts.getAccountindexByAddress(address) # let index = self.accounts.getAccountindexByAddress(address)
# if index == -1: return # if index == -1: return
# self.accounts.getAccount(index).collectiblesLists = collectiblesList # self.accounts.getAccount(index).collectiblesLists = collectiblesList
if address == self.currentAccount.address: if address == self.currentAccount.address:
# Add CollectibleListJSON to the right list # Add CollectibleListJSON to the right list
# TODO check if instead we need to set an error
self.currentCollectiblesLists.setCollectiblesJSONByType( self.currentCollectiblesLists.setCollectiblesJSONByType(
collectibleData["collectibleType"].getStr, 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 loadingTrxHistory*(self: WalletView, isLoading: bool) {.signal.}
proc loadTransactionsForAccount*(self: WalletView, address: string) {.slot.} = proc loadTransactionsForAccount*(self: WalletView, address: string) {.slot.} =

View File

@ -27,13 +27,41 @@ QtObject:
result.collectibleLists = @[] result.collectibleLists = @[]
result.setup 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) = proc setCollectiblesJSONByType*(self: CollectiblesList, collectibleType: string, collectiblesJSON: string) =
var i = 0
for collectibleList in self.collectibleLists: for collectibleList in self.collectibleLists:
if collectibleList.collectibleType == collectibleType: if collectibleList.collectibleType == collectibleType:
collectibleList.collectiblesJSON = collectiblesJSON collectibleList.collectiblesJSON = collectiblesJSON
collectibleList.loading = 0 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 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 = method rowCount(self: CollectiblesList, index: QModelIndex = nil): int =
return self.collectibleLists.len return self.collectibleLists.len

View File

@ -58,8 +58,9 @@ proc tokensOfOwnerByIndex(contract: Contract, address: EthAddress): seq[int] =
result.add(token) result.add(token)
index = index + 1 index = index + 1
proc getCryptoKitties*(address: EthAddress): seq[Collectible] = proc getCryptoKitties*(address: EthAddress): string =
result = @[] var cryptokitties: seq[Collectible]
cryptokitties = @[]
try: try:
# TODO handle testnet -- does this API exist in testnet?? # TODO handle testnet -- does this API exist in testnet??
# TODO handle offset (recursive method?) # TODO handle offset (recursive method?)
@ -80,7 +81,7 @@ proc getCryptoKitties*(address: EthAddress): seq[Collectible] =
finalId = $id finalId = $id
if (not (name.kind == JNull)): if (not (name.kind == JNull)):
finalName = $name finalName = $name
result.add(Collectible(id: finalId, cryptokitties.add(Collectible(id: finalId,
name: finalName, name: finalName,
image: kitty["image_url_png"].str, image: kitty["image_url_png"].str,
collectibleType: CRYPTOKITTY, collectibleType: CRYPTOKITTY,
@ -90,21 +91,25 @@ proc getCryptoKitties*(address: EthAddress): seq[Collectible] =
error "Error with this individual cat", msg = e2.msg, cat = kitty error "Error with this individual cat", msg = e2.msg, cat = kitty
except Exception as e: except Exception as e:
error "Error getting Cryptokitties", msg = e.msg error "Error getting Cryptokitties", msg = e.msg
return e.msg
proc getCryptoKitties*(address: string): seq[Collectible] = return $(%*cryptokitties)
proc getCryptoKitties*(address: string): string =
let eth_address = parseAddress(address) let eth_address = parseAddress(address)
result = getCryptoKitties(eth_address) result = getCryptoKitties(eth_address)
proc getEthermons*(address: EthAddress): seq[Collectible] = proc getEthermons*(address: EthAddress): string =
result = @[]
try: try:
var ethermons: seq[Collectible]
ethermons = @[]
let contract = getContract("ethermon") let contract = getContract("ethermon")
if contract == nil: return if contract == nil: return
let tokens = tokensOfOwnerByIndex(contract, address) let tokens = tokensOfOwnerByIndex(contract, address)
if (tokens.len == 0): if (tokens.len == 0):
return result return $(%*ethermons)
let tokensJoined = strutils.join(tokens, ",") let tokensJoined = strutils.join(tokens, ",")
let url = fmt"https://www.ethermon.io/api/monster/get_data?monster_ids={tokensJoined}" 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 var i = 0
for monsterKey in json.keys(monsters): for monsterKey in json.keys(monsters):
let monster = monsters[monsterKey] let monster = monsters[monsterKey]
result.add(Collectible(id: $tokens[i], ethermons.add(Collectible(id: $tokens[i],
name: monster["class_name"].str, name: monster["class_name"].str,
image: monster["image"].str, image: monster["image"].str,
collectibleType: ETHERMON, collectibleType: ETHERMON,
description: "", description: "",
externalUrl: "")) externalUrl: ""))
i = i + 1 i = i + 1
return $(%*ethermons)
except Exception as e: except Exception as e:
error "Error getting Ethermons", msg = e.msg 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) let eth_address = parseAddress(address)
result = getEthermons(eth_address) result = getEthermons(eth_address)
proc getKudos*(address: EthAddress): seq[Collectible] = proc getKudos*(address: EthAddress): string =
result = @[]
try: try:
var kudos: seq[Collectible]
kudos = @[]
let contract = getContract("kudos") let contract = getContract("kudos")
if contract == nil: return if contract == nil: return
let tokens = tokensOfOwnerByIndex(contract, address) let tokens = tokensOfOwnerByIndex(contract, address)
if (tokens.len == 0): if (tokens.len == 0):
return result return $(%*kudos)
for token in tokens: for token in tokens:
let url = getTokenUri(contract, token.u256) let url = getTokenUri(contract, token.u256)
if (url == ""): if (url == ""):
return result return $(%*kudos)
let client = newHttpClient() let client = newHttpClient()
client.headers = newHttpHeaders({ "Content-Type": "application/json" }) client.headers = newHttpHeaders({ "Content-Type": "application/json" })
@ -153,15 +162,18 @@ proc getKudos*(address: EthAddress): seq[Collectible] =
let response = client.request(url) let response = client.request(url)
let kudo = parseJson(response.body) let kudo = parseJson(response.body)
result.add(Collectible(id: $token, kudos.add(Collectible(id: $token,
name: kudo["name"].str, name: kudo["name"].str,
image: kudo["image"].str, image: kudo["image"].str,
collectibleType: KUDO, collectibleType: KUDO,
description: kudo["description"].str, description: kudo["description"].str,
externalUrl: kudo["external_url"].str)) externalUrl: kudo["external_url"].str))
return $(%*kudos)
except Exception as e: except Exception as e:
error "Error getting Kudos", msg = e.msg 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) let eth_address = parseAddress(address)
result = getKudos(eth_address) result = getKudos(eth_address)

View File

@ -60,6 +60,13 @@ Item {
} }
} }
} }
Connections {
target: walletModel.collectiblesLists
onDataChanged: {
checkCollectiblesVisibility()
}
}
} }
/*##^## /*##^##

View File

@ -6,14 +6,21 @@ import "../../../../../shared"
Item { Item {
property url collectibleIconSource: "../../../../img/collectibles/CryptoKitties.png" property url collectibleIconSource: "../../../../img/collectibles/CryptoKitties.png"
property string collectibleName: "CryptoKitties" property string collectibleName: "CryptoKitties"
property string collectibleType: "cryptokitty"
property bool collectiblesOpened: false property bool collectiblesOpened: false
property var collectiblesModal property var collectiblesModal
property string buttonText: "View in Cryptokitties" property string buttonText: "View in Cryptokitties"
property var getLink: function () {} property var getLink: function () {}
property var collectibles: { property var collectibles: {
if (error) {
return []
}
try { try {
return JSON.parse(collectiblesJSON) var result = JSON.parse(collectiblesJSON)
if (typeof result === "string") {
return JSON.parse(result)
}
return result
} catch (e) { } catch (e) {
console.error('Error parsing collectibles for:', collectibleName) console.error('Error parsing collectibles for:', collectibleName)
console.error('JSON:', collectiblesJSON) 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 // 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 id: root
visible: active visible: active
@ -44,7 +51,6 @@ Item {
id: collectiblesContent id: collectiblesContent
visible: root.collectiblesOpened visible: root.collectiblesOpened
collectiblesModal: root.collectiblesModal collectiblesModal: root.collectiblesModal
collectibleType: root.collectibleType
buttonText: root.buttonText buttonText: root.buttonText
getLink: root.getLink getLink: root.getLink
anchors.top: collectiblesHeader.bottom anchors.top: collectiblesHeader.bottom

View File

@ -7,19 +7,64 @@ import "../../../../../shared"
ScrollView { ScrollView {
readonly property int imageSize: 164 readonly property int imageSize: 164
property string collectibleType: "cryptokitty"
property var collectiblesModal property var collectiblesModal
property string buttonText: "View in Cryptokitties" property string buttonText: "View in Cryptokitties"
property var getLink: function () {} property var getLink: function () {}
property var collectibles: [] property var collectibles: []
id: root id: root
height: visible ? contentRow.height : 0 height: visible ? contentLoader.item.height : 0
width: parent.width width: parent.width
ScrollBar.vertical.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: ScrollBar.AlwaysOff
ScrollBar.horizontal.policy: ScrollBar.AsNeeded ScrollBar.horizontal.policy: ScrollBar.AsNeeded
clip: true clip: true
Loader {
id: contentLoader
active: true
width: parent.width
height: root.imageSize
sourceComponent: !!error ? errorComponent : collectiblesContentComponent
}
Component {
id: errorComponent
Item {
width: parent.width
height: root.imageSize
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
}
StyledButton {
label: qsTr("Reload")
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: somethingWentWrongText.bottom
anchors.topMargin: Style.current.halfPadding
onClicked: {
walletModel.reloadCollectible(collectibleType)
}
}
}
}
}
Component {
id: collectiblesContentComponent
Row { Row {
id: contentRow id: contentRow
bottomPadding: Style.current.padding bottomPadding: Style.current.padding
@ -61,4 +106,5 @@ ScrollView {
} }
} }
} }
}
} }

View File

@ -60,7 +60,7 @@ Rectangle {
StyledText { StyledText {
id: numberCollectibleText id: numberCollectibleText
color: Style.current.secondaryText color: Style.current.secondaryText
text: collectibleHeader.collectiblesQty text: !!error ? "-" : collectibleHeader.collectiblesQty
font.pixelSize: 15 font.pixelSize: 15
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }