diff --git a/src/app/modules/main/communities/tokens/controller.nim b/src/app/modules/main/communities/tokens/controller.nim index 0924796926..1d66af99e1 100644 --- a/src/app/modules/main/communities/tokens/controller.nim +++ b/src/app/modules/main/communities/tokens/controller.nim @@ -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() \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/io_interface.nim b/src/app/modules/main/communities/tokens/io_interface.nim index 61848f4ceb..47926ca61a 100644 --- a/src/app/modules/main/communities/tokens/io_interface.nim +++ b/src/app/modules/main/communities/tokens/io_interface.nim @@ -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") \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/models/token_item.nim b/src/app/modules/main/communities/tokens/models/token_item.nim index 4db2fd9d04..493933ce02 100644 --- a/src/app/modules/main/communities/tokens/models/token_item.nim +++ b/src/app/modules/main/communities/tokens/models/token_item.nim @@ -20,6 +20,7 @@ type burnState*: ContractTransactionStatus remoteDestructedAddresses*: seq[string] tokenOwnersModel*: token_owners_model.TokenOwnersModel + tokenHoldersLoading*: bool proc initTokenItem*( tokenDto: CommunityTokenDto, @@ -29,7 +30,7 @@ proc initTokenItem*( burnState: ContractTransactionStatus, remoteDestructedAddresses: seq[string], remainingSupply: Uint256, - destructedAmount: Uint256 + destructedAmount: Uint256, ): TokenItem = result.tokenDto = tokenDto if network != nil: @@ -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( @@ -55,6 +57,7 @@ proc `$`*(self: TokenItem): string = destructedAmount: {self.destructedAmount}, burnState: {self.burnState}, tokenOwnersModel: {self.tokenOwnersModel}, + tokenHoldersLoading: {self.tokenHoldersLoading}, remoteDestructedAddresses: {self.remoteDestructedAddresses} ]""" diff --git a/src/app/modules/main/communities/tokens/models/token_model.nim b/src/app/modules/main/communities/tokens/models/token_model.nim index 06365c26eb..5e29440033 100644 --- a/src/app/modules/main/communities/tokens/models/token_model.nim +++ b/src/app/modules/main/communities/tokens/models/token_model.nim @@ -26,6 +26,7 @@ type ChainName ChainIcon TokenOwnersModel + TokenHoldersLoading AccountName AccountAddress RemainingSupply @@ -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.} @@ -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): @@ -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 @@ -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", @@ -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: diff --git a/src/app/modules/main/communities/tokens/module.nim b/src/app/modules/main/communities/tokens/module.nim index 9f731b0fe9..f005a01b5b 100644 --- a/src/app/modules/main/communities/tokens/module.nim +++ b/src/app/modules/main/communities/tokens/module.nim @@ -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() \ No newline at end of file diff --git a/src/app/modules/main/communities/tokens/view.nim b/src/app/modules/main/communities/tokens/view.nim index c19d7fa9e0..9ffb55402e 100644 --- a/src/app/modules/main/communities/tokens/view.nim +++ b/src/app/modules/main/communities/tokens/view.nim @@ -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() \ No newline at end of file diff --git a/src/app/modules/main/controller.nim b/src/app/modules/main/controller.nim index 70e812e567..3f32ea0201 100644 --- a/src/app/modules/main/controller.nim +++ b/src/app/modules/main/controller.nim @@ -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) @@ -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: @@ -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() diff --git a/src/app/modules/main/io_interface.nim b/src/app/modules/main/io_interface.nim index 582e6c903c..e36cd2c807 100644 --- a/src/app/modules/main/io_interface.nim +++ b/src/app/modules/main/io_interface.nim @@ -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") @@ -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 diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 0c6d14c369..0b233609b8 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -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 != "": diff --git a/src/app/modules/main/view.nim b/src/app/modules/main/view.nim index 9712e5ffe8..50e407d6b0 100644 --- a/src/app/modules/main/view.nim +++ b/src/app/modules/main/view.nim @@ -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() diff --git a/src/app/modules/shared_models/section_item.nim b/src/app/modules/shared_models/section_item.nim index c023754424..0bf1ec6d4e 100644 --- a/src/app/modules/shared_models/section_item.nim +++ b/src/app/modules/shared_models/section_item.nim @@ -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 diff --git a/src/app_service/service/community_tokens/service.nim b/src/app_service/service/community_tokens/service.nim index 9eb845b947..42162376b5 100644 --- a/src/app_service/service/community_tokens/service.nim +++ b/src/app_service/service/community_tokens/service.nim @@ -156,6 +156,7 @@ type contractAddress*: string chainId*: int owners*: seq[CommunityCollectibleOwner] + error*: string type CommunityTokensDetailsArgs* = ref object of Args @@ -259,6 +260,7 @@ const SIGNAL_COMPUTE_SELF_DESTRUCT_FEE* = "communityTokens-computeSelfDestructFe const SIGNAL_COMPUTE_BURN_FEE* = "communityTokens-computeBurnFee" const SIGNAL_COMPUTE_AIRDROP_FEE* = "communityTokens-computeAirdropFee" const SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED* = "communityTokens-communityTokenOwnersFetched" +const SIGNAL_COMMUNITY_TOKEN_OWNERS_LOADING_FAILED* = "communityTokens-communityTokenOwnersLoadingFailed" const SIGNAL_REMOTE_DESTRUCT_STATUS* = "communityTokens-communityTokenRemoteDestructStatus" const SIGNAL_BURN_STATUS* = "communityTokens-communityTokenBurnStatus" const SIGNAL_BURN_ACTION_RECEIVED* = "communityTokens-communityTokenBurnActionReceived" @@ -1290,17 +1292,28 @@ QtObject: proc onCommunityTokenOwnersFetched*(self:Service, response: string) {.slot.} = let responseJson = response.parseJson() - if responseJson{"error"}.kind != JNull and responseJson{"error"}.getStr != "": - let errorMessage = responseJson["error"].getStr - error "Can't fetch community token owners", chainId=responseJson{"chainId"}, contractAddress=responseJson{"contractAddress"}, errorMsg=errorMessage - return let chainId = responseJson{"chainId"}.getInt let contractAddress = responseJson{"contractAddress"}.getStr let communityId = responseJson{"communityId"}.getStr - let communityTokenOwners = toCommunityCollectibleOwners(responseJson{"result"}) - self.tokenOwnersCache[(chainId, contractAddress)] = communityTokenOwners - let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: communityTokenOwners) - self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data) + + try: + if responseJson{"error"}.kind != JNull and responseJson{"error"}.getStr != "": + raise newException(ValueError, responseJson["error"].getStr) + + let communityTokenOwners = toCommunityCollectibleOwners(responseJson{"result"}) + self.tokenOwnersCache[(chainId, contractAddress)] = communityTokenOwners + let data = CommunityTokenOwnersArgs(chainId: chainId, contractAddress: contractAddress, communityId: communityId, owners: communityTokenOwners) + self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_FETCHED, data) + except Exception as e: + error "Can't fetch community token owners", chainId=responseJson{"chainId"}, contractAddress=responseJson{"contractAddress"}, errorMsg=e.msg + + let data = CommunityTokenOwnersArgs( + chainId: chainId, + contractAddress: contractAddress, + communityId: communityId, + error: e.msg, + ) + self.events.emit(SIGNAL_COMMUNITY_TOKEN_OWNERS_LOADING_FAILED, data) # restart token holders timer self.restartTokenHoldersTimer(chainId, contractAddress) @@ -1313,14 +1326,6 @@ QtObject: let community = self.communityService.getCommunityById(communityId) return community.isPrivilegedUser() - # used when community members changed - proc fetchCommunityTokenOwners*(self: Service, communityId: string) = - if not self.iAmCommunityPrivilegedUser(communityId): - return - let tokens = self.getCommunityTokens(communityId) - for token in tokens: - self.fetchCommunityOwners(token) - proc getOwnerToken*(self: Service, communityId: string): CommunityTokenDto = let communityTokens = self.getCommunityTokens(communityId) for token in communityTokens: diff --git a/storybook/pages/CommunityTokenViewPage.qml b/storybook/pages/CommunityTokenViewPage.qml index 7cfe999701..5452ebad8c 100644 --- a/storybook/pages/CommunityTokenViewPage.qml +++ b/storybook/pages/CommunityTokenViewPage.qml @@ -41,6 +41,7 @@ SplitView { chainName: networksGroup.checkedButton.text chainIcon: networksGroup.checkedButton.chainIcon accountName: "helloworld" + tokenHoldersLoading: loadingTokenHolders.checked // collectible-specific properties remotelyDestructState: remotelyDestructStateBox.checked @@ -141,6 +142,16 @@ SplitView { } } + GroupBox { + Layout.fillWidth: true + + CheckBox { + id: loadingTokenHolders + text: "Loading Token Holders" + checked: false + } + } + GroupBox { Layout.fillWidth: true diff --git a/ui/app/AppLayouts/Communities/helpers/TokenObject.qml b/ui/app/AppLayouts/Communities/helpers/TokenObject.qml index 748a3431a2..aa520aae5c 100644 --- a/ui/app/AppLayouts/Communities/helpers/TokenObject.qml +++ b/ui/app/AppLayouts/Communities/helpers/TokenObject.qml @@ -51,4 +51,7 @@ QtObject { // Asset-specific properties: property int decimals: 2 + + // Loading indicators + property bool tokenHoldersLoading: false } diff --git a/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml index 62e01461d9..530799155a 100644 --- a/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MintTokensSettingsPanel.qml @@ -1005,6 +1005,7 @@ StackView { token.accountAddress: model.accountAddress token.multiplierIndex: model.multiplierIndex token.tokenAddress: model.tokenAddress + token.tokenHoldersLoading: model.tokenHoldersLoading } onCountChanged: { diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index 525bb13849..45d3b27f66 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -375,7 +375,7 @@ StatusSectionLayout { onRegisterBurnTokenFeesSubscriber: d.feesBroker.registerBurnFeesSubscriber(feeSubscriber) - onStartTokenHoldersManagement: communityTokensStore.startTokenHoldersManagement(chainId, address) + onStartTokenHoldersManagement: communityTokensStore.startTokenHoldersManagement(root.community.id, chainId, address) onStopTokenHoldersManagement: communityTokensStore.stopTokenHoldersManagement() diff --git a/ui/app/AppLayouts/Communities/views/CommunityTokenView.qml b/ui/app/AppLayouts/Communities/views/CommunityTokenView.qml index 22f75e1c61..761ecf168c 100644 --- a/ui/app/AppLayouts/Communities/views/CommunityTokenView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunityTokenView.qml @@ -96,6 +96,7 @@ StatusScrollView { id: d readonly property int iconSize: 20 + property bool loadingTokenHolders: false readonly property var renamedTokenOwnersModel: RolesRenamingModel { sourceModel: root.tokenOwnersModel @@ -172,7 +173,7 @@ StatusScrollView { wrapMode: Text.Wrap font.pixelSize: Style.current.primaryTextFontSize color: Theme.palette.baseColor1 - text: qsTr("Review token details before minting it as they can’t be edited later") + text: qsTr("Review token details before minting it as they can't be edited later") } } @@ -228,7 +229,15 @@ StatusScrollView { id: tokenHolderLoader visible: !root.preview && root.deploymentCompleted - sourceComponent: isOwnerTokenItem ? tokenHolderContact : sortableTokenHolderPanel + sourceComponent: isOwnerTokenItem ? tokenHolderContact : (token.tokenHoldersLoading ? tokenHoldersLoadingComponent : sortableTokenHolderPanel) + } + + Component { + id: tokenHoldersLoadingComponent + + StatusBaseText { + text: qsTr("Loading token holders...") + } } Component { diff --git a/ui/imports/shared/stores/CommunityTokensStore.qml b/ui/imports/shared/stores/CommunityTokensStore.qml index 5aba9bf15c..eac1a210e2 100644 --- a/ui/imports/shared/stores/CommunityTokensStore.qml +++ b/ui/imports/shared/stores/CommunityTokensStore.qml @@ -7,6 +7,7 @@ QtObject { id: root property var communityTokensModuleInst: communityTokensModule ?? null + property var mainModuleInst: mainModule ?? null // Network selection properties: property var flatNetworks: networksModule.flatNetworks @@ -231,11 +232,11 @@ QtObject { communityTokensModuleInst.asyncGetOwnerTokenDetails(communityId) } - function startTokenHoldersManagement(chainId, contractAddress) { - communityTokensModuleInst.startTokenHoldersManagement(chainId, contractAddress) + function startTokenHoldersManagement(communityId, chainId, contractAddress) { + mainModuleInst.startTokenHoldersManagement(communityId, chainId, contractAddress) } function stopTokenHoldersManagement() { - communityTokensModuleInst.stopTokenHoldersManagement() + mainModuleInst.stopTokenHoldersManagement() } }