Skip to content

Commit

Permalink
refactor(community_tokens): only fetch holders when going to the page (
Browse files Browse the repository at this point in the history
…#16308)

* refactor(community_tokens): only fetch holders when going to the page

Fixes #16307

Instead of fetching community token holders each time members change, we fetch when the page for the token is opened.
It shows a small loading text then the resulting holders.
If the list is already available (fetched previously, we show it directly).
There is still the timer to refresh the list if you stay on the page.

* add loading property to storybook
  • Loading branch information
jrainville authored Sep 19, 2024
1 parent ea8827e commit 3f8dfee
Show file tree
Hide file tree
Showing 18 changed files with 199 additions and 119 deletions.
6 changes: 0 additions & 6 deletions src/app/modules/main/communities/tokens/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,3 @@ proc declineOwnership*(self: Controller, communityId: string) =

proc asyncGetOwnerTokenOwnerAddress*(self: Controller, chainId: int, contractAddress: string) =
self.communityTokensService.asyncGetOwnerTokenOwnerAddress(chainId, contractAddress)

proc startTokenHoldersManagement*(self: Controller, chainId: int, contractAddress: string) =
self.communityTokensService.startTokenHoldersManagement(chainId, contractAddress)

proc stopTokenHoldersManagement*(self: Controller) =
self.communityTokensService.stopTokenHoldersManagement()
6 changes: 0 additions & 6 deletions src/app/modules/main/communities/tokens/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,3 @@ method onOwnerTokenOwnerAddress*(self: AccessInterface, chainId: int, contractAd

method asyncGetOwnerTokenDetails*(self: AccessInterface, communityId: string) {.base.} =
raise newException(ValueError, "No implementation available")

method startTokenHoldersManagement*(self: AccessInterface, chainId: int, contractAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")

method stopTokenHoldersManagement*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type
burnState*: ContractTransactionStatus
remoteDestructedAddresses*: seq[string]
tokenOwnersModel*: token_owners_model.TokenOwnersModel
tokenHoldersLoading*: bool

proc initTokenItem*(
tokenDto: CommunityTokenDto,
Expand All @@ -29,7 +30,7 @@ proc initTokenItem*(
burnState: ContractTransactionStatus,
remoteDestructedAddresses: seq[string],
remainingSupply: Uint256,
destructedAmount: Uint256
destructedAmount: Uint256,
): TokenItem =
result.tokenDto = tokenDto
if network != nil:
Expand All @@ -45,6 +46,7 @@ proc initTokenItem*(
# TODO: provide number of messages here
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, 0, owner.collectibleOwner, remoteDestructedAddresses)
))
result.tokenHoldersLoading = false

proc `$`*(self: TokenItem): string =
result = fmt"""TokenItem(
Expand All @@ -55,6 +57,7 @@ proc `$`*(self: TokenItem): string =
destructedAmount: {self.destructedAmount},
burnState: {self.burnState},
tokenOwnersModel: {self.tokenOwnersModel},
tokenHoldersLoading: {self.tokenHoldersLoading},
remoteDestructedAddresses: {self.remoteDestructedAddresses}
]"""

169 changes: 101 additions & 68 deletions src/app/modules/main/communities/tokens/models/token_model.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type
ChainName
ChainIcon
TokenOwnersModel
TokenHoldersLoading
AccountName
AccountAddress
RemainingSupply
Expand All @@ -50,76 +51,105 @@ QtObject:
new(result, delete)
result.setup

proc updateDeployState*(self: TokenModel, chainId: int, contractAddress: string, deployState: DeployState) =
proc getItemIndex(self: TokenModel, chainId: int, contractAddress: string): int =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenDto.deployState = deployState
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.DeployState.int])
return
if self.items[i].tokenDto.address == contractAddress and self.items[i].tokenDto.chainId == chainId:
return i
return -1

proc updateDeployState*(self: TokenModel, chainId: int, contractAddress: string, deployState: DeployState) =
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1 and self.items[itemIdx].tokenDto.deployState == deployState:
return

self.items[itemIdx].tokenDto.deployState = deployState
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.DeployState.int])

proc updateAddress*(self: TokenModel, chainId: int, oldContractAddress: string, newContractAddress: string) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == oldContractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenDto.address = newContractAddress
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.TokenAddress.int])
return
let itemIdx = self.getItemIndex(chainId, oldContractAddress)
if itemIdx == -1 and self.items[itemIdx].tokenDto.address == newContractAddress:
return

self.items[itemIdx].tokenDto.address = newContractAddress
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.TokenAddress.int])

proc updateBurnState*(self: TokenModel, chainId: int, contractAddress: string, burnState: ContractTransactionStatus) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].burnState = burnState
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.BurnState.int])
return
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1 and self.items[itemIdx].burnState == burnState:
return

self.items[itemIdx].burnState = burnState
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.BurnState.int])

proc updateRemoteDestructedAddresses*(self: TokenModel, chainId: int, contractAddress: string, remoteDestructedAddresses: seq[string]) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].remoteDestructedAddresses = remoteDestructedAddresses
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.RemotelyDestructState.int])
self.items[i].tokenOwnersModel.updateRemoteDestructState(remoteDestructedAddresses)
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int])
return
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1 and self.items[itemIdx].remoteDestructedAddresses == remoteDestructedAddresses:
return

self.items[itemIdx].remoteDestructedAddresses = remoteDestructedAddresses
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.RemotelyDestructState.int])
self.items[itemIdx].tokenOwnersModel.updateRemoteDestructState(remoteDestructedAddresses)
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int])

proc updateSupply*(self: TokenModel, chainId: int, contractAddress: string, supply: Uint256, destructedAmount: Uint256) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
if self.items[i].tokenDto.supply != supply or self.items[i].destructedAmount != destructedAmount:
self.items[i].tokenDto.supply = supply
self.items[i].destructedAmount = destructedAmount
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.Supply.int])
return
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1:
return

if self.items[itemIdx].tokenDto.supply != supply or self.items[itemIdx].destructedAmount != destructedAmount:
self.items[itemIdx].tokenDto.supply = supply
self.items[itemIdx].destructedAmount = destructedAmount
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.Supply.int])

proc updateRemainingSupply*(self: TokenModel, chainId: int, contractAddress: string, remainingSupply: Uint256) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
if self.items[i].remainingSupply != remainingSupply:
self.items[i].remainingSupply = remainingSupply
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.RemainingSupply.int])
return
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1 and self.items[itemIdx].remainingSupply == remainingSupply:
return

self.items[itemIdx].remainingSupply = remainingSupply
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.RemainingSupply.int])

proc hasTokenHolders*(self: TokenModel, chainId: int, contractAddress: string): bool =
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1:
return false
return self.items[itemIdx].tokenOwnersModel.count > 0

proc setCommunityTokenOwners*(self: TokenModel, chainId: int, contractAddress: string, owners: seq[CommunityCollectibleOwner]) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == contractAddress) and (self.items[i].tokenDto.chainId == chainId)):
self.items[i].tokenOwnersModel.setItems(owners.map(proc(owner: CommunityCollectibleOwner): TokenOwnersItem =
# TODO: provide number of messages here
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, 0, owner.collectibleOwner, self.items[i].remoteDestructedAddresses)
))
let index = self.createIndex(i, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int])
return
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1:
return

self.items[itemIdx].tokenHoldersLoading = false
self.items[itemIdx].tokenOwnersModel.setItems(owners.map(proc(owner: CommunityCollectibleOwner): TokenOwnersItem =
# TODO: provide number of messages here
result = initTokenOwnersItem(owner.contactId, owner.name, owner.imageSource, 0, owner.collectibleOwner, self.items[itemIdx].remoteDestructedAddresses)
))
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.TokenOwnersModel.int, ModelRole.TokenHoldersLoading.int])

proc setCommunityTokenHoldersLoading*(self: TokenModel, chainId: int, contractAddress: string, value: bool) =
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1 and self.items[itemIdx].tokenHoldersLoading == value:
return

self.items[itemIdx].tokenHoldersLoading = value
let index = self.createIndex(itemIdx, 0, nil)
defer: index.delete
self.dataChanged(index, index, @[ModelRole.TokenHoldersLoading.int])

proc countChanged(self: TokenModel) {.signal.}

Expand All @@ -129,7 +159,6 @@ QtObject:
self.endResetModel()
self.countChanged()


proc getOwnerToken*(self: TokenModel): TokenItem =
for i in 0 ..< self.items.len:
if(self.items[i].tokenDto.privilegesLevel == PrivilegesLevel.Owner):
Expand All @@ -144,17 +173,18 @@ QtObject:
self.endInsertRows()
self.countChanged()

proc removeItemByChainIdAndAddress*(self: TokenModel, chainId: int, address: string) =
for i in 0 ..< self.items.len:
if((self.items[i].tokenDto.address == address) and (self.items[i].tokenDto.chainId == chainId)):
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete
proc removeItemByChainIdAndAddress*(self: TokenModel, chainId: int, contractAddress: string) =
let itemIdx = self.getItemIndex(chainId, contractAddress)
if itemIdx == -1:
return

self.beginRemoveRows(parentModelIndex, i, i)
self.items.delete(i)
self.endRemoveRows()
self.countChanged()
return
let parentModelIndex = newQModelIndex()
defer: parentModelIndex.delete

self.beginRemoveRows(parentModelIndex, itemIdx, itemIdx)
self.items.delete(itemIdx)
self.endRemoveRows()
self.countChanged()

proc getCount*(self: TokenModel): int {.slot.} =
self.items.len
Expand Down Expand Up @@ -184,6 +214,7 @@ QtObject:
ModelRole.ChainName.int:"chainName",
ModelRole.ChainIcon.int:"chainIcon",
ModelRole.TokenOwnersModel.int:"tokenOwnersModel",
ModelRole.TokenHoldersLoading.int:"tokenHoldersLoading",
ModelRole.AccountName.int:"accountName",
ModelRole.AccountAddress.int:"accountAddress",
ModelRole.RemainingSupply.int:"remainingSupply",
Expand Down Expand Up @@ -235,6 +266,8 @@ QtObject:
result = newQVariant(item.chainIcon)
of ModelRole.TokenOwnersModel:
result = newQVariant(item.tokenOwnersModel)
of ModelRole.TokenHoldersLoading:
result = newQVariant(item.tokenHoldersLoading)
of ModelRole.AccountName:
result = newQVariant(item.accountName)
of ModelRole.AccountAddress:
Expand Down
6 changes: 0 additions & 6 deletions src/app/modules/main/communities/tokens/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,3 @@ method onOwnerTokenOwnerAddress*(self: Module, chainId: int, contractAddress: st
"contractAddress": contractAddress
}
self.view.setOwnerTokenDetails($jsonObj)

method startTokenHoldersManagement*(self: Module, chainId: int, contractAddress: string) =
self.controller.startTokenHoldersManagement(chainId, contractAddress)

method stopTokenHoldersManagement*(self: Module) =
self.controller.stopTokenHoldersManagement()
6 changes: 0 additions & 6 deletions src/app/modules/main/communities/tokens/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,3 @@ QtObject:
QtProperty[string] ownerTokenDetails:
read = getOwnerTokenDetails
notify = ownerTokenDetailsChanged

proc startTokenHoldersManagement*(self: View, chainId: int, contractAddress: string) {.slot.} =
self.communityTokensModule.startTokenHoldersManagement(chainId, contractAddress)

proc stopTokenHoldersManagement*(self: View) {.slot.} =
self.communityTokensModule.stopTokenHoldersManagement()
14 changes: 10 additions & 4 deletions src/app/modules/main/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,10 @@ proc init*(self: Controller) =
let args = CommunityTokenOwnersArgs(e)
self.delegate.onCommunityTokenOwnersFetched(args.communityId, args.chainId, args.contractAddress, args.owners)

self.events.on(SIGNAL_COMMUNITY_TOKEN_OWNERS_LOADING_FAILED) do(e: Args):
let args = CommunityTokenOwnersArgs(e)
self.delegate.errorLoadingTokenHolders(args.communityId, args.chainId, args.contractAddress, args.error)

self.events.on(SIGNAL_ACCEPT_REQUEST_TO_JOIN_LOADING) do(e: Args):
var args = CommunityMemberArgs(e)
self.delegate.onAcceptRequestToJoinLoading(args.communityId, args.pubKey)
Expand All @@ -412,10 +416,6 @@ proc init*(self: Controller) =
let args = CommunityMemberStatusUpdatedArgs(e)
self.delegate.onMembershipStateUpdated(args.communityId, args.memberPubkey, args.state)

self.events.on(SIGNAL_COMMUNITY_MEMBERS_CHANGED) do(e: Args):
let args = CommunityMembersArgs(e)
self.communityTokensService.fetchCommunityTokenOwners(args.communityId)

self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED) do(e: Args):
let args = SharedKeycarModuleFlowTerminatedArgs(e)
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER:
Expand Down Expand Up @@ -597,3 +597,9 @@ proc asyncGetRevealedAccountsForAllMembers*(self: Controller, communityId: strin

proc asyncReevaluateCommunityMembersPermissions*(self: Controller, communityId: string) =
self.communityService.asyncReevaluateCommunityMembersPermissions(communityId)

proc startTokenHoldersManagement*(self: Controller, chainId: int, contractAddress: string) =
self.communityTokensService.startTokenHoldersManagement(chainId, contractAddress)

proc stopTokenHoldersManagement*(self: Controller) =
self.communityTokensService.stopTokenHoldersManagement()
9 changes: 9 additions & 0 deletions src/app/modules/main/io_interface.nim
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ method onOwnerTokensDeploymentStarted*(self: AccessInterface, ownerToken: Commun
method onCommunityTokenOwnersFetched*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, owners: seq[CommunityCollectibleOwner]) {.base.} =
raise newException(ValueError, "No implementation available")

method errorLoadingTokenHolders*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, error: string) {.base.} =
raise newException(ValueError, "No implementation available")

method onCommunityTokenDeployStateChanged*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string, deployState: DeployState) {.base.} =
raise newException(ValueError, "No implementation available")

Expand Down Expand Up @@ -421,6 +424,12 @@ method openSectionChatAndMessage*(self: AccessInterface, sectionId: string, chat
method updateRequestToJoinState*(self: AccessInterface, sectionId: string, requestToJoinState: RequestToJoinState) {.base.} =
raise newException(ValueError, "No implementation available")

method startTokenHoldersManagement*(self: AccessInterface, communityId: string, chainId: int, contractAddress: string) {.base.} =
raise newException(ValueError, "No implementation available")

method stopTokenHoldersManagement*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

# This way (using concepts) is used only for the modules managed by AppController
type
DelegateInterface* = concept c
Expand Down
14 changes: 14 additions & 0 deletions src/app/modules/main/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,20 @@ method onCommunityTokenRemoved*[T](self: Module[T], communityId: string, chainId
if item.id != "":
item.removeCommunityToken(chainId, address)

method startTokenHoldersManagement*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string) =
self.controller.startTokenHoldersManagement(chainId, contractAddress)
let item = self.view.model().getItemById(communityId)
if item.id != "" and not item.communityTokens.hasTokenHolders(chainId, contractAddress):
item.setCommunityTokenHoldersLoading(chainId, contractAddress, value = true)

method stopTokenHoldersManagement*[T](self: Module[T]) =
self.controller.stopTokenHoldersManagement()

method errorLoadingTokenHolders*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, error: string) =
let item = self.view.model().getItemById(communityId)
if item.id != "":
item.setCommunityTokenHoldersLoading(chainId, contractAddress, value = false)

method onCommunityTokenOwnersFetched*[T](self: Module[T], communityId: string, chainId: int, contractAddress: string, owners: seq[CommunityCollectibleOwner]) =
let item = self.view.model().getItemById(communityId)
if item.id != "":
Expand Down
6 changes: 6 additions & 0 deletions src/app/modules/main/view.nim
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,9 @@ QtObject:
proc emitCommunityMemberStatusEphemeralNotification*(self:View, communityName: string, memberName: string,
membershipState: int) =
self.communityMemberStatusEphemeralNotification(communityName, memberName, membershipState)

proc startTokenHoldersManagement*(self: View, communityId: string, chainId: int, contractAddress: string) {.slot.} =
self.delegate.startTokenHoldersManagement(communityId, chainId, contractAddress)

proc stopTokenHoldersManagement*(self: View) {.slot.} =
self.delegate.stopTokenHoldersManagement()
3 changes: 3 additions & 0 deletions src/app/modules/shared_models/section_item.nim
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ proc updateRemoteDestructedAddresses*(self: SectionItem, chainId: int, contractA
proc setCommunityTokenOwners*(self: SectionItem, chainId: int, contractAddress: string, owners: seq[CommunityCollectibleOwner]) {.inline.} =
self.communityTokensModel.setCommunityTokenOwners(chainId, contractAddress, owners)

proc setCommunityTokenHoldersLoading*(self: SectionItem, chainId: int, contractAddress: string, value: bool) {.inline.} =
self.communityTokensModel.setCommunityTokenHoldersLoading(chainId, contractAddress, value)

proc communityTokens*(self: SectionItem): community_tokens_model.TokenModel {.inline.} =
self.communityTokensModel

Expand Down
Loading

0 comments on commit 3f8dfee

Please sign in to comment.