feat(@desktop/wallet): implement collectibles ownership state
Fixes #12159
This commit is contained in:
parent
52e6fddcab
commit
2ac484dd57
|
@ -22,7 +22,7 @@ QtObject:
|
|||
addresses: seq[string]
|
||||
chainIds: seq[int]
|
||||
|
||||
stateTable: Table[string, Table[int, bool]] # Table[address][chainID] -> isUpdating
|
||||
ownershipStatus: Table[string, Table[int, OwnershipStatus]] # Table[address][chainID] -> OwnershipStatus
|
||||
|
||||
requestId: int32
|
||||
autofetch: bool
|
||||
|
@ -42,6 +42,63 @@ QtObject:
|
|||
QtProperty[QVariant] model:
|
||||
read = getModelAsVariant
|
||||
|
||||
|
||||
proc checkModelState(self: Controller) =
|
||||
var overallState = OwnershipStateIdle
|
||||
|
||||
# If any address+chainID is error, then the whole model is error
|
||||
# Otherwise, if any address+chainID is updating, then the whole model is updating
|
||||
# Otherwise, the model is idle
|
||||
for address, statusPerChainID in self.ownershipStatus.pairs:
|
||||
for chainID, status in statusPerChainID:
|
||||
if status.state == OwnershipStateError:
|
||||
overallState = OwnershipStateError
|
||||
break
|
||||
elif status.state == OwnershipStateUpdating:
|
||||
overallState = OwnershipStateUpdating
|
||||
break
|
||||
|
||||
case overallState:
|
||||
of OwnershipStateIdle:
|
||||
self.model.setIsUpdating(false)
|
||||
self.model.setIsError(false)
|
||||
of OwnershipStateUpdating:
|
||||
self.model.setIsUpdating(true)
|
||||
self.model.setIsError(false)
|
||||
of OwnershipStateError:
|
||||
self.model.setIsUpdating(false)
|
||||
self.model.setIsError(true)
|
||||
|
||||
proc resetOwnershipStatus(self: Controller) =
|
||||
# Initialize state table
|
||||
self.ownershipStatus = initTable[string, Table[int, OwnershipStatus]]()
|
||||
for address in self.addresses:
|
||||
self.ownershipStatus[address] = initTable[int, OwnershipStatus]()
|
||||
for chainID in self.chainIds:
|
||||
self.ownershipStatus[address][chainID] = OwnershipStatus(
|
||||
state: OwnershipStateUpdating,
|
||||
timestamp: invalidTimestamp
|
||||
)
|
||||
self.model.setIsUpdating(true)
|
||||
|
||||
proc setOwnershipStatus(self: Controller, statusPerAddressAndChainID: Table[string, Table[int, OwnershipStatus]]) =
|
||||
for address, statusPerChainID in statusPerAddressAndChainID.pairs:
|
||||
if not self.ownershipStatus.hasKey(address):
|
||||
continue
|
||||
for chainID, status in statusPerChainID:
|
||||
if not self.ownershipStatus[address].hasKey(chainID):
|
||||
continue
|
||||
self.ownershipStatus[address][chainID] = status
|
||||
|
||||
self.checkModelState()
|
||||
|
||||
proc setOwnershipState(self: Controller, address: string, chainID: int, state: OwnershipState) =
|
||||
if not self.ownershipStatus.hasKey(address) or not self.ownershipStatus[address].hasKey(chainID):
|
||||
return
|
||||
self.ownershipStatus[address][chainID].state = state
|
||||
|
||||
self.checkModelState()
|
||||
|
||||
proc loadMoreItems(self: Controller) {.slot.} =
|
||||
if self.model.getIsFetching():
|
||||
return
|
||||
|
@ -67,10 +124,10 @@ QtObject:
|
|||
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
|
||||
self.model.setIsError(true)
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -79,59 +136,40 @@ QtObject:
|
|||
except Exception as e:
|
||||
error "Error converting activity entries: ", e.msg
|
||||
|
||||
self.setOwnershipStatus(res.ownershipStatus)
|
||||
|
||||
if self.autofetch and res.hasMore:
|
||||
self.loadMoreItems()
|
||||
|
||||
proc resetModel*(self: Controller) {.slot.} =
|
||||
proc resetModel(self: Controller) {.slot.} =
|
||||
self.model.setItems(@[], 0, true)
|
||||
self.fetchFromStart = true
|
||||
if self.autofetch:
|
||||
self.loadMoreItems()
|
||||
|
||||
proc resetUpdateState*(self: Controller) =
|
||||
# Initialize state table
|
||||
# We assume that ownership is initially not being updated. This will change if an
|
||||
# update starts or a partial update is received.
|
||||
# TODO: Get the update state at the time of filter switch from the backend?
|
||||
self.stateTable = initTable[string, Table[int, bool]]()
|
||||
for address in self.addresses:
|
||||
self.stateTable[address] = initTable[int, bool]()
|
||||
for chainID in self.chainIds:
|
||||
self.stateTable[address][chainID] = false
|
||||
self.model.setIsUpdating(false)
|
||||
|
||||
proc setUpdateState*(self: Controller, address: string, chainID: int, isUpdating: bool) =
|
||||
if not self.stateTable.hasKey(address) or not self.stateTable[address].hasKey(chainID):
|
||||
return
|
||||
self.stateTable[address][chainID] = isUpdating
|
||||
|
||||
# If any address+chainID is updating, then the whole model is updating
|
||||
for address, chainIDsPerAddress in self.stateTable.pairs:
|
||||
for chainID, isUpdating in chainIDsPerAddress:
|
||||
if isUpdating:
|
||||
self.model.setIsUpdating(true)
|
||||
return
|
||||
self.model.setIsUpdating(false)
|
||||
|
||||
proc setupEventHandlers(self: Controller) =
|
||||
self.eventsHandler.onOwnedCollectiblesFilteringDone(proc (jsonObj: JsonNode) =
|
||||
self.processFilterOwnedCollectiblesResponse(jsonObj)
|
||||
)
|
||||
|
||||
self.eventsHandler.onCollectiblesOwnershipUpdateStarted(proc (address: string, chainID: int) =
|
||||
self.setUpdateState(address, chainID, true)
|
||||
self.setOwnershipState(address, chainID, OwnershipStateUpdating)
|
||||
)
|
||||
|
||||
self.eventsHandler.onCollectiblesOwnershipUpdatePartial(proc (address: string, chainID: int) =
|
||||
self.setUpdateState(address, chainID, true)
|
||||
self.setOwnershipState(address, chainID, OwnershipStateUpdating)
|
||||
self.resetModel()
|
||||
)
|
||||
|
||||
self.eventsHandler.onCollectiblesOwnershipUpdateFinished(proc (address: string, chainID: int) =
|
||||
self.setUpdateState(address, chainID, false)
|
||||
self.setOwnershipState(address, chainID, OwnershipStateIdle)
|
||||
self.resetModel()
|
||||
)
|
||||
|
||||
self.eventsHandler.onCollectiblesOwnershipUpdateFinishedWithError(proc (address: string, chainID: int) =
|
||||
self.setOwnershipState(address, chainID, OwnershipStateError)
|
||||
)
|
||||
|
||||
proc newController*(requestId: int32, autofetch: bool, events: EventEmitter): Controller =
|
||||
new(result, delete)
|
||||
|
||||
|
@ -159,7 +197,7 @@ QtObject:
|
|||
self.chainIds = chainIds
|
||||
self.addresses = addresses
|
||||
|
||||
self.resetUpdateState()
|
||||
self.resetOwnershipStatus()
|
||||
|
||||
self.eventsHandler.updateSubscribedAddresses(self.addresses)
|
||||
self.eventsHandler.updateSubscribedChainIDs(self.chainIds)
|
||||
|
|
|
@ -24,6 +24,7 @@ QtObject:
|
|||
collectiblesOwnershipUpdateStartedFn: OwnershipUpdateCallbackProc
|
||||
collectiblesOwnershipUpdatePartialFn: OwnershipUpdateCallbackProc
|
||||
collectiblesOwnershipUpdateFinishedFn: OwnershipUpdateCallbackProc
|
||||
collectiblesOwnershipUpdateFinishedWithErrorFn: OwnershipUpdateCallbackProc
|
||||
|
||||
requestId: int32
|
||||
|
||||
|
@ -45,6 +46,9 @@ QtObject:
|
|||
proc onCollectiblesOwnershipUpdateFinished*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) =
|
||||
self.collectiblesOwnershipUpdateFinishedFn = handler
|
||||
|
||||
proc onCollectiblesOwnershipUpdateFinishedWithError*(self: EventsHandler, handler: OwnershipUpdateCallbackProc) =
|
||||
self.collectiblesOwnershipUpdateFinishedWithErrorFn = handler
|
||||
|
||||
proc handleApiEvents(self: EventsHandler, e: Args) =
|
||||
var data = WalletSignal(e)
|
||||
|
||||
|
@ -89,6 +93,11 @@ QtObject:
|
|||
return
|
||||
self.collectiblesOwnershipUpdateFinishedFn(data.accounts[0], data.chainID)
|
||||
|
||||
self.walletEventHandlers[backend_collectibles.eventCollectiblesOwnershipUpdateFinishedWithError] = proc (data: WalletSignal) =
|
||||
if self.collectiblesOwnershipUpdateFinishedWithErrorFn == nil or self.shouldIgnoreEvent(data):
|
||||
return
|
||||
self.collectiblesOwnershipUpdateFinishedWithErrorFn(data.accounts[0], data.chainID)
|
||||
|
||||
proc newEventsHandler*(requestId: int32, events: EventEmitter): EventsHandler =
|
||||
new(result, delete)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import json, json_serialization, strformat
|
||||
import stint, Tables
|
||||
import stint, Tables, strutils
|
||||
import core
|
||||
import response_type, collectibles_types
|
||||
|
||||
|
@ -23,6 +23,8 @@ const eventCollectiblesOwnershipUpdateFinishedWithError*: string = "wallet-colle
|
|||
const eventOwnedCollectiblesFilteringDone*: string = "wallet-owned-collectibles-filtering-done"
|
||||
const eventGetCollectiblesDetailsDone*: string = "wallet-get-collectibles-details-done"
|
||||
|
||||
const invalidTimestamp*: int = -1
|
||||
|
||||
type
|
||||
# Mirrors services/wallet/collectibles/service.go ErrorCode
|
||||
ErrorCode* = enum
|
||||
|
@ -30,11 +32,23 @@ type
|
|||
ErrorCodeTaskCanceled,
|
||||
ErrorCodeFailed
|
||||
|
||||
# Mirrors services/wallet/collectibles/service.go OwnershipState
|
||||
OwnershipState* = enum
|
||||
OwnershipStateIdle = 1,
|
||||
OwnershipStateUpdating,
|
||||
OwnershipStateError
|
||||
|
||||
# Mirrors services/wallet/collectibles/service.go OwnershipState
|
||||
OwnershipStatus* = ref object
|
||||
state*: OwnershipState
|
||||
timestamp*: int
|
||||
|
||||
# Mirrors services/wallet/collectibles/service.go FilterOwnedCollectiblesResponse
|
||||
FilterOwnedCollectiblesResponse* = object
|
||||
collectibles*: seq[CollectibleHeader]
|
||||
offset*: int
|
||||
hasMore*: bool
|
||||
ownershipStatus*: Table[string, Table[int, OwnershipStatus]]
|
||||
errorCode*: ErrorCode
|
||||
|
||||
# Mirrors services/wallet/collectibles/service.go GetCollectiblesDetailsResponse
|
||||
|
@ -42,6 +56,19 @@ type
|
|||
collectibles*: seq[CollectibleDetails]
|
||||
errorCode*: ErrorCode
|
||||
|
||||
# CollectibleOwnershipState
|
||||
proc `$`*(self: OwnershipStatus): string =
|
||||
return fmt"""OwnershipStatus(
|
||||
state:{self.state},
|
||||
timestamp:{self.timestamp}
|
||||
"""
|
||||
|
||||
proc fromJson*(t: JsonNode, T: typedesc[OwnershipStatus]): OwnershipStatus {.inline.} =
|
||||
return OwnershipStatus(
|
||||
state: OwnershipState(t{"state"}.getInt),
|
||||
timestamp: t{"timestamp"}.getInt
|
||||
)
|
||||
|
||||
# Responses
|
||||
proc fromJson*(e: JsonNode, T: typedesc[FilterOwnedCollectiblesResponse]): FilterOwnedCollectiblesResponse {.inline.} =
|
||||
var collectibles: seq[CollectibleHeader]
|
||||
|
@ -51,11 +78,21 @@ proc fromJson*(e: JsonNode, T: typedesc[FilterOwnedCollectiblesResponse]): Filte
|
|||
for i in 0 ..< jsonCollectibles.len:
|
||||
collectibles[i] = fromJson(jsonCollectibles[i], CollectibleHeader)
|
||||
|
||||
var ownershipStatus = initTable[string, Table[int, OwnershipStatus]]()
|
||||
if e.hasKey("ownershipStatus"):
|
||||
let jsonOwnershipStatus = e["ownershipStatus"]
|
||||
for address, jsonStatusPerChain in jsonOwnershipStatus.getFields():
|
||||
var statusPerChain = initTable[int, OwnershipStatus]()
|
||||
for chainId, jsonStatus in jsonStatusPerChain.getFields():
|
||||
statusPerChain[parseInt(chainId)] = fromJson(jsonStatus, OwnershipStatus)
|
||||
ownershipStatus[address] = statusPerChain
|
||||
|
||||
result = T(
|
||||
collectibles: collectibles,
|
||||
offset: e["offset"].getInt(),
|
||||
hasMore: if e.hasKey("hasMore"): e["hasMore"].getBool()
|
||||
else: false,
|
||||
ownershipStatus: ownershipStatus,
|
||||
errorCode: ErrorCode(e["errorCode"].getInt())
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue