feat(@wallet): update collectibles model only with changes

Fixes #13254
This commit is contained in:
Dario Gabriel Lipicar 2024-02-13 11:51:18 -03:00 committed by dlipicar
parent 2fa65968c0
commit 48f8fb3e55
4 changed files with 151 additions and 20 deletions

View File

@ -223,6 +223,12 @@ QtObject:
of "communityColor": result = item.getCommunityColor() of "communityColor": result = item.getCommunityColor()
of "communityPrivilegesLevel": result = $item.getCommunityPrivilegesLevel() of "communityPrivilegesLevel": result = $item.getCommunityPrivilegesLevel()
proc resetCollectibleItems(self: Model, newItems: seq[CollectiblesEntry] = @[]) =
self.beginResetModel()
self.items = newItems
self.endResetModel()
self.countChanged()
proc appendCollectibleItems(self: Model, newItems: seq[CollectiblesEntry]) = proc appendCollectibleItems(self: Model, newItems: seq[CollectiblesEntry]) =
if len(newItems) == 0: if len(newItems) == 0:
return return
@ -239,23 +245,58 @@ QtObject:
self.items.insert(newItems, startIdx) self.items.insert(newItems, startIdx)
self.endInsertRows() self.endInsertRows()
self.countChanged() self.countChanged()
proc removeCollectibleItems(self: Model) = proc removeCollectibleItem(self: Model, idx: int) =
if self.items.len <= 0: if idx < 0 or idx >= self.items.len:
return return
let parentModelIndex = newQModelIndex() let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete defer: parentModelIndex.delete
# Start from the beginning self.beginRemoveRows(parentModelIndex, idx, idx)
let startIdx = 0 self.items.delete(idx)
# End at the last real item
let endIdx = startIdx + self.items.len - 1
self.beginRemoveRows(parentModelIndex, startIdx, endIdx)
self.items = @[]
self.endRemoveRows() self.endRemoveRows()
self.countChanged() self.countChanged()
proc updateCollectibleItems(self: Model, newItems: seq[CollectiblesEntry]) =
if len(self.items) == 0:
# Current list is empty, just replace with new list
self.resetCollectibleItems(newItems)
return
if len(newItems) == 0:
# New list is empty, just remove all items
self.resetCollectibleItems()
return
var newTable = initTable[string, int](len(newItems))
for i in 0 ..< len(newItems):
newTable.add(newItems[i].getID(), i)
# Needs to be built in sequential index order
var oldIndicesToRemove: seq[int] = @[]
for idx in 0 ..< len(self.items):
let uid = self.items[idx].getID()
if not newTable.hasKey(uid):
# Item in old list but not in new -> Must remove
oldIndicesToRemove.add(idx)
else:
# Item both in old and new lists -> Nothing to do in the current list,
# remove from the new list so it only holds new items.
newTable.del(uid)
if len(oldIndicesToRemove) > 0:
var removedItems = 0
for idx in oldIndicesToRemove:
let updatedIdx = idx - removedItems
self.removeCollectibleItem(updatedIdx)
removedItems += 1
self.countChanged()
var newItemsToAdd: seq[CollectiblesEntry] = @[]
for uid, idx in newTable:
newItemsToAdd.add(newItems[idx])
self.appendCollectibleItems(newItemsToAdd)
proc getItems*(self: Model): seq[CollectiblesEntry] = proc getItems*(self: Model): seq[CollectiblesEntry] =
return self.items return self.items
@ -268,16 +309,24 @@ QtObject:
proc setItems*(self: Model, newItems: seq[CollectiblesEntry], offset: int, hasMore: bool) = proc setItems*(self: Model, newItems: seq[CollectiblesEntry], offset: int, hasMore: bool) =
if offset == 0: if offset == 0:
self.removeCollectibleItems() self.resetCollectibleItems(newItems)
elif offset != self.getCount(): elif offset != self.getCount():
error "invalid offset" error "invalid offset"
return return
else:
self.appendCollectibleItems(newItems) self.appendCollectibleItems(newItems)
self.setHasMore(hasMore) self.setHasMore(hasMore)
proc itemsUpdated(self: Model) {.signal.} # Checks the diff between the current list and the new list, appends new items,
proc updateItems*(self: Model, updates: seq[backend_collectibles.Collectible]) = # removes missing items.
# We assume the order of the items in the input could change, and we don't care
# about the order of the items in the model.
proc updateItems*(self: Model, newItems: seq[CollectiblesEntry]) =
self.updateCollectibleItems(newItems)
self.setHasMore(false)
proc itemsDataUpdated(self: Model) {.signal.}
proc updateItemsData*(self: Model, updates: seq[backend_collectibles.Collectible]) =
var anyUpdated = false var anyUpdated = false
for i in countdown(self.items.high, 0): for i in countdown(self.items.high, 0):
let entry = self.items[i] let entry = self.items[i]
@ -290,7 +339,7 @@ QtObject:
anyUpdated = true anyUpdated = true
break break
if anyUpdated: if anyUpdated:
self.itemsUpdated() self.itemsDataUpdated()
proc getImageUrl*(self: Model, id: string): string {.slot.} = proc getImageUrl*(self: Model, id: string): string {.slot.} =
for item in self.items: for item in self.items:

View File

@ -38,7 +38,7 @@ QtObject:
result.setup result.setup
signalConnect(result.flatModel, "countChanged()", result, "refreshItems()") signalConnect(result.flatModel, "countChanged()", result, "refreshItems()")
signalConnect(result.flatModel, "itemsUpdated()", result, "refreshItems()") signalConnect(result.flatModel, "itemsDataUpdated()", result, "refreshItems()")
# Forward declaration # Forward declaration
proc refreshItems*(self: Model) proc refreshItems*(self: Model)

View File

@ -181,7 +181,7 @@ QtObject:
self.setTempItems(items, res.offset) self.setTempItems(items, res.offset)
# If we reached the end of the list, commit the items to the model # If we reached the end of the list, commit the items to the model
if not res.hasMore: if not res.hasMore:
self.model.setItems(self.tempItems, 0, false) self.model.updateItems(self.tempItems)
self.tempItems = @[] self.tempItems = @[]
except Exception as e: except Exception as e:
error "Error converting activity entries: ", e.msg error "Error converting activity entries: ", e.msg
@ -207,7 +207,7 @@ QtObject:
for jsonCollectible in jsonObj.getElems(): for jsonCollectible in jsonObj.getElems():
let collectible = fromJson(jsonCollectible, backend_collectibles.Collectible) let collectible = fromJson(jsonCollectible, backend_collectibles.Collectible)
collectibles.add(collectible) collectibles.add(collectible)
self.model.updateItems(collectibles) self.model.updateItemsData(collectibles)
if not self.loadType.isPaginated(): if not self.loadType.isPaginated():
self.updateTempItems(collectibles) self.updateTempItems(collectibles)

View File

@ -0,0 +1,82 @@
import unittest
import stint, strutils, random
import backend/collectibles_types
import app/modules/shared_models/collectibles_model
import app/modules/shared_models/collectibles_entry
proc createTestCollectible(seed: int): CollectiblesEntry =
let data = Collectible(
dataType: UniqueID,
id: CollectibleUniqueID(
contractID: ContractID(
address: seed.toHex,
chainID: seed mod 4
),
tokenID: u256(seed)
)
)
let extradata = ExtraData(
networkShortName: "Chain" & seed.toHex,
networkColor: "Color" & seed.toHex,
networkIconURL: "URL" & seed.toHex,
)
return newCollectibleDetailsFullEntry(data, extradata)
proc createTestCollectibles(seed: int, count: int): seq[CollectiblesEntry] =
result = @[]
for i in 0..<count:
result.add(createTestCollectible(seed + i))
suite "collectibles model":
test "Collectible list set":
let collectibles = createTestCollectibles(0, 15)
let moreCollectibles = createTestCollectibles(100, 10)
let model = newModel()
model.setItems(collectibles, 0, false)
check(model.getItems() == collectibles)
# Wrong offset, should not change the list
model.setItems(collectibles, 20, false)
check(model.getItems() == collectibles)
# Right offset, should append
model.setItems(moreCollectibles, 15, false)
check(model.getItems() == collectibles & moreCollectibles)
# 0 offset, should replace
model.setItems(moreCollectibles, 0, false)
check(model.getItems() == moreCollectibles)
test "Collectible list update":
let oldCollectibles = createTestCollectibles(0, 15)
let model = newModel()
model.updateItems(oldCollectibles)
check(model.getItems() == oldCollectibles)
model.updateItems(oldCollectibles)
check(model.getItems() == oldCollectibles)
var newCollectibles = oldCollectibles
newCollectibles.del(0)
newCollectibles.del(2)
newCollectibles.del(7)
for newC in createTestCollectibles(100, 7):
newCollectibles.add(newC)
var r = initRand(678)
r.shuffle(newCollectibles)
model.updateItems(newCollectibles)
for c in model.getItems():
check(c in newCollectibles)
for c in newCollectibles:
check(c in model.getItems())
model.updateItems(@[])
check(model.getItems().len == 0)