diff --git a/src/app/modules/main/chat_section/chat_content/io_interface.nim b/src/app/modules/main/chat_section/chat_content/io_interface.nim index a5bb85a65c..bf3044a8fe 100644 --- a/src/app/modules/main/chat_section/chat_content/io_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/io_interface.nim @@ -127,3 +127,9 @@ method onMadeActive*(self: AccessInterface) {.base.} = method onMadeInactive*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") + +method onUpdateViewOnlyPermissionsSatisfied*(self: AccessInterface, value: bool) {.base.} = + raise newException(ValueError, "No implementation available") + +method onUpdateViewAndPostPermissionsSatisfied*(self: AccessInterface, value: bool) {.base.} = + raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 42c13a8e84..cab665eb75 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -400,3 +400,9 @@ method amIChatAdmin*(self: Module): bool = else: let communityDto = self.controller.getCommunityDetails() return communityDto.memberRole == MemberRole.Owner or communityDto.memberRole == MemberRole.Admin + +method onUpdateViewOnlyPermissionsSatisfied*(self: Module, value: bool) = + self.view.setViewOnlyPermissionsSatisfied(value) + +method onUpdateViewAndPostPermissionsSatisfied*(self: Module, value: bool) = + self.view.setViewAndPostPermissionsSatisfied(value) diff --git a/src/app/modules/main/chat_section/chat_content/view.nim b/src/app/modules/main/chat_section/chat_content/view.nim index 755141c072..3c5b303fed 100644 --- a/src/app/modules/main/chat_section/chat_content/view.nim +++ b/src/app/modules/main/chat_section/chat_content/view.nim @@ -13,6 +13,8 @@ QtObject: pinnedMessagesModelVariant: QVariant chatDetails: ChatDetails chatDetailsVariant: QVariant + viewOnlyPermissionsSatisfied: bool + viewAndPostPermissionsSatisfied: bool proc chatDetailsChanged*(self:View) {.signal.} @@ -31,6 +33,8 @@ QtObject: result.pinnedMessagesModelVariant = newQVariant(result.pinnedMessagesModel) result.chatDetails = newChatDetails() result.chatDetailsVariant = newQVariant(result.chatDetails) + result.viewOnlyPermissionsSatisfied = false + result.viewAndPostPermissionsSatisfied = false proc load*(self: View, id: string, `type`: int, belongsToCommunity, isUsersListAvailable: bool, name, icon: string, color, description, emoji: string, hasUnreadMessages: bool, @@ -150,3 +154,28 @@ QtObject: proc updateChatBlocked*(self: View, blocked: bool) = self.chatDetails.setBlocked(blocked) + + proc viewOnlyPermissionsSatisfiedChanged(self: View) {.signal.} + + proc setViewOnlyPermissionsSatisfied*(self: View, value: bool) = + self.viewOnlyPermissionsSatisfied = value + self.viewOnlyPermissionsSatisfiedChanged() + + proc getViewOnlyPermissionsSatisfied*(self: View): bool {.slot.} = + return self.viewOnlyPermissionsSatisfied + QtProperty[bool] viewOnlyPermissionsSatisfied: + read = getViewOnlyPermissionsSatisfied + notify = viewOnlyPermissionsSatisfiedChanged + + proc viewAndPostPermissionsSatisfiedChanged(self: View) {.signal.} + + proc setViewAndPostPermissionsSatisfied*(self: View, value: bool) = + self.viewAndPostPermissionsSatisfied = value + self.viewAndPostPermissionsSatisfiedChanged() + + proc getViewAndPostPermissionsSatisfied*(self: View): bool {.slot.} = + return self.viewAndPostPermissionsSatisfied + QtProperty[bool] viewAndPostPermissionsSatisfied: + read = getViewAndPostPermissionsSatisfied + notify = viewAndPostPermissionsSatisfiedChanged + diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index 77f7dce26d..3e0c496be1 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -107,6 +107,21 @@ proc authenticateToRequestToJoinCommunity*(self: Controller, communityId: string self.tmpRequestToJoinEnsName = ensName self.authenticate() +proc getMySectionId*(self: Controller): string = + return self.sectionId + +proc asyncCheckPermissionsToJoin*(self: Controller) = + self.communityService.asyncCheckPermissionsToJoin(self.getMySectionId()) + +proc asyncCheckAllChannelsPermissions*(self: Controller) = + self.communityService.asyncCheckAllChannelsPermissions(self.getMySectionId()) + +proc asyncCheckChannelPermissions*(self: Controller, communityId: string, chatId: string) = + self.communityService.asyncCheckChannelPermissions(communityId, chatId) + +proc asyncCheckPermissions*(self: Controller) = + self.asyncCheckPermissionsToJoin() + self.asyncCheckAllChannelsPermissions() proc init*(self: Controller) = self.events.on(SIGNAL_SENDING_SUCCESS) do(e:Args): @@ -257,7 +272,7 @@ proc init*(self: Controller) = let args = CommunityTokenPermissionArgs(e) if (args.communityId == self.sectionId): self.delegate.onCommunityTokenPermissionCreated(args.communityId, args.tokenPermission) - self.communityService.asyncCheckPermissionsToJoin(self.sectionId) + self.asyncCheckPermissions() self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_CREATION_FAILED) do(e: Args): let args = CommunityTokenPermissionArgs(e) @@ -268,7 +283,7 @@ proc init*(self: Controller) = let args = CommunityTokenPermissionArgs(e) if (args.communityId == self.sectionId): self.delegate.onCommunityTokenPermissionUpdated(args.communityId, args.tokenPermission) - self.communityService.asyncCheckPermissionsToJoin(self.sectionId) + self.asyncCheckPermissions() self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATE_FAILED) do(e: Args): @@ -280,7 +295,7 @@ proc init*(self: Controller) = let args = CommunityTokenPermissionRemovedArgs(e) if (args.communityId == self.sectionId): self.delegate.onCommunityTokenPermissionDeleted(args.communityId, args.permissionId) - self.communityService.asyncCheckPermissionsToJoin(self.sectionId) + self.asyncCheckPermissions() self.events.on(SIGNAL_COMMUNITY_TOKEN_PERMISSION_DELETION_FAILED) do(e: Args): let args = CommunityTokenPermissionArgs(e) @@ -292,6 +307,16 @@ proc init*(self: Controller) = if (args.communityId == self.sectionId): self.delegate.onCommunityCheckPermissionsToJoinResponse(args.checkPermissionsToJoinResponse) + self.events.on(SIGNAL_CHECK_CHANNEL_PERMISSIONS_RESPONSE) do(e: Args): + let args = CheckChannelPermissionsResponseArgs(e) + if args.communityId == self.sectionId: + self.delegate.onCommunityCheckChannelPermissionsResponse(args.chatId, args.checkChannelPermissionsResponse) + + self.events.on(SIGNAL_CHECK_ALL_CHANNELS_PERMISSIONS_RESPONSE) do(e: Args): + let args = CheckAllChannelsPermissionsResponseArgs(e) + if args.communityId == self.sectionId: + self.delegate.onCommunityCheckAllChannelsPermissionsResponse(args.checkAllChannelsPermissionsResponse) + self.events.on(SIGNAL_COMMUNITY_TOKEN_METADATA_ADDED) do(e: Args): let args = CommunityTokenMetadataArgs(e) if (args.communityId == self.sectionId): @@ -299,9 +324,11 @@ proc init*(self: Controller) = self.events.on(SIGNAL_OWNED_COLLECTIBLES_UPDATE_FINISHED) do(e: Args): self.delegate.onOwnedCollectiblesUpdated() + self.asyncCheckPermissions() self.events.on(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e: Args): self.delegate.onWalletAccountTokensRebuilt() + self.asyncCheckPermissions() self.events.on(SIGNAL_COMMUNITY_KICKED) do (e: Args): let args = CommunityArgs(e) @@ -366,9 +393,6 @@ proc init*(self: Controller) = self.events.on(SIGNAL_MAILSERVER_HISTORY_REQUEST_COMPLETED) do(e:Args): self.delegate.setLoadingHistoryMessagesInProgress(false) -proc getMySectionId*(self: Controller): string = - return self.sectionId - proc isCommunity*(self: Controller): bool = return self.isCommunitySection @@ -633,6 +657,12 @@ proc getColorHash*(self: Controller, pubkey: string): ColorHashDto = proc getColorId*(self: Controller, pubkey: string): int = procs_from_visual_identity_service.colorIdOf(pubkey) +proc checkChatHasPermissions*(self: Controller, communityId: string, chatId: string): bool = + return self.communityService.checkChatHasPermissions(communityId, chatId) + +proc checkChatIsLocked*(self: Controller, communityId: string, chatId: string): bool = + return self.communityService.checkChatIsLocked(communityId, chatId) + proc createOrEditCommunityTokenPermission*(self: Controller, communityId: string, tokenPermission: CommunityTokenPermissionDto) = self.communityService.createOrEditCommunityTokenPermission(communityId, tokenPermission) @@ -670,5 +700,3 @@ proc getContractAddressesForToken*(self: Controller, symbol: string): Table[int, proc getCommunityTokenList*(self: Controller): seq[CommunityTokenDto] = return self.communityTokensService.getCommunityTokens(self.getMySectionId()) -proc asyncCheckPermissionsToJoin*(self: Controller) = - self.communityService.asyncCheckPermissionsToJoin(self.getMySectionId()) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index a8375ad502..13bf16ab69 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -343,7 +343,7 @@ method switchToChannel*(self: AccessInterface, channelName: string) {.base.} = method joinSpectatedCommunity*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method createOrEditCommunityTokenPermission*(self: AccessInterface, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, isPrivate: bool) {.base.} = +method createOrEditCommunityTokenPermission*(self: AccessInterface, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, channelIDs: seq[string], isPrivate: bool) {.base.} = raise newException(ValueError, "No implementation available") method deleteCommunityTokenPermission*(self: AccessInterface, communityId: string, permissionId: string) {.base.} = @@ -398,4 +398,11 @@ method onOwnedcollectiblesUpdated*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method onCommunityCheckPermissionsToJoinResponse*(self: AccessInterface, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) {.base.} = + + raise newException(ValueError, "No implementation available") + +method onCommunityCheckChannelPermissionsResponse*(self: AccessInterface, chatId: string, checkChannelPermissionsResponse: CheckChannelPermissionsResponseDto) {.base.} = + raise newException(ValueError, "No implementation available") + +method onCommunityCheckAllChannelsPermissionsResponse*(self: AccessInterface, checkAllChannelsPermissionsResponse: CheckAllChannelsPermissionsResponseDto) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/item.nim b/src/app/modules/main/chat_section/item.nim index efa962d20e..97ce2e0f72 100644 --- a/src/app/modules/main/chat_section/item.nim +++ b/src/app/modules/main/chat_section/item.nim @@ -33,6 +33,8 @@ type trustStatus: TrustStatus onlineStatus: OnlineStatus loaderActive: bool + locked: bool + requiresPermissions: bool proc initItem*( id, @@ -58,7 +60,9 @@ proc initItem*( categoryOpened: bool = true, trustStatus: TrustStatus = TrustStatus.Unknown, onlineStatus = OnlineStatus.Inactive, - loaderActive = false + loaderActive = false, + locked = false, + requiresPermissions = false ): Item = result = Item() result.id = id @@ -86,6 +90,8 @@ proc initItem*( result.trustStatus = trustStatus result.onlineStatus = onlineStatus result.loaderActive = loaderActive + result.locked = locked + result.requiresPermissions = requiresPermissions proc `$`*(self: Item): string = result = fmt"""chat_section/Item( @@ -112,6 +118,8 @@ proc `$`*(self: Item): string = trustStatus: {$self.trustStatus}, onlineStatus: {$self.onlineStatus}, loaderActive: {$self.loaderActive}, + locked: {$self.locked}, + requiresPermissions: {$self.requiresPermissions}, ]""" proc toJsonNode*(self: Item): JsonNode = @@ -138,7 +146,9 @@ proc toJsonNode*(self: Item): JsonNode = "categoryOpened": self.categoryOpened, "trustStatus": self.trustStatus, "onlineStatus": self.onlineStatus, - "loaderActive": self.loaderActive + "loaderActive": self.loaderActive, + "locked": self.locked, + "requiresPermissions": self.requiresPermissions } proc delete*(self: Item) = @@ -278,3 +288,15 @@ proc `loaderActive=`*(self: var Item, value: bool) = proc isCategory*(self: Item): bool = self.`type` == CATEGORY_TYPE + +proc isLocked*(self: Item): bool = + self.locked + +proc `locked=`*(self: Item, value: bool) = + self.locked = value + +proc requiresPermissions*(self: Item): bool = + self.requiresPermissions + +proc `requiresPermissions=`*(self: Item, value: bool) = + self.requiresPermissions = value diff --git a/src/app/modules/main/chat_section/model.nim b/src/app/modules/main/chat_section/model.nim index 0088c26a81..580a5dc892 100644 --- a/src/app/modules/main/chat_section/model.nim +++ b/src/app/modules/main/chat_section/model.nim @@ -31,6 +31,8 @@ type OnlineStatus IsCategory LoaderActive + Locked + RequiresPermissions QtObject: type @@ -99,6 +101,8 @@ QtObject: ModelRole.OnlineStatus.int:"onlineStatus", ModelRole.IsCategory.int:"isCategory", ModelRole.LoaderActive.int:"loaderActive", + ModelRole.Locked.int:"locked", + ModelRole.RequiresPermissions.int:"requiresPermissions", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -162,6 +166,10 @@ QtObject: result = newQVariant(item.isCategory) of ModelRole.LoaderActive: result = newQVariant(item.loaderActive) + of ModelRole.Locked: + result = newQVariant(item.isLocked) + of ModelRole.RequiresPermissions: + result = newQVariant(item.requiresPermissions) proc getItemIdxById(items: seq[Item], id: string): int = var idx = 0 @@ -274,6 +282,22 @@ QtObject: else: self.dataChanged(index, index, @[ModelRole.Active.int]) + proc setItemLocked*(self: Model, id: string, locked: bool) = + let index = self.getItemIdxById(id) + if index == -1: + return + self.items[index].locked = locked + let modelIndex = self.createIndex(index, 0, nil) + self.dataChanged(modelIndex, modelIndex, @[ModelRole.Locked.int]) + + proc setItemPermissionsRequired*(self: Model, id: string, value: bool) = + let index = self.getItemIdxById(id) + if index == -1: + return + self.items[index].requiresPermissions = value + let modelIndex = self.createIndex(index, 0, nil) + self.dataChanged(modelIndex, modelIndex, @[ModelRole.RequiresPermissions.int]) + proc changeMutedOnItemById*(self: Model, id: string, muted: bool) = let index = self.getItemIdxById(id) if index == -1: @@ -545,4 +569,4 @@ QtObject: self.items[index].loaderActive = false self.items[index].active = false let modelIndex = self.createIndex(index, 0, nil) - self.dataChanged(modelIndex, modelIndex, @[ModelRole.Active.int, ModelRole.LoaderActive.int]) \ No newline at end of file + self.dataChanged(modelIndex, modelIndex, @[ModelRole.Active.int, ModelRole.LoaderActive.int]) diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 748aa9f974..270c13ab5d 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -13,6 +13,8 @@ import ../../shared_models/token_criteria_item import ../../shared_models/token_criteria_model import ../../shared_models/token_list_item import ../../shared_models/token_list_model +import ../../shared_models/token_permission_chat_list_item +import ../../shared_models/token_permission_chat_list_model import chat_content/module as chat_content_module import chat_content/users/module as users_module @@ -69,6 +71,8 @@ proc buildChatSectionUI(self: Module, gifService: gif_service.Service, mailserversService: mailservers_service.Service) +proc reevaluateRequiresTokenPermissionToJoin(self: Module) + proc addOrUpdateChat(self: Module, chat: ChatDto, channelGroup: ChannelGroupDto, @@ -291,9 +295,17 @@ proc rebuildCommunityTokenPermissionsModel(self: Module) = tokenPermissionsItem.getType() == TokenPermissionType.BecomeAdmin.int) self.view.tokenPermissionsModel().setItems(tokenPermissionsItems) - self.view.setRequiresTokenPermissionToJoin(len(memberPermissions) > 0 or len(adminPermissions) > 0) + self.reevaluateRequiresTokenPermissionToJoin() -proc initCommunityTokenPermissionsModel(self: Module) = +proc reevaluateRequiresTokenPermissionToJoin(self: Module) = + let community = self.controller.getMyCommunity() + var hasBecomeMemberOrBecomeAdminPermissions = false + for id, tokenPermission in community.tokenPermissions: + if tokenPermission.`type` == TokenPermissionType.BecomeMember or tokenPermission.`type` == TokenPermissionType.BecomeAdmin: + hasBecomeMemberOrBecomeAdminPermissions = true + self.view.setRequiresTokenPermissionToJoin(hasBecomeMemberOrBecomeAdminPermissions) + +proc initCommunityTokenPermissionsModel(self: Module, channelGroup: ChannelGroupDto) = self.rebuildCommunityTokenPermissionsModel() proc buildTokenList(self: Module) = @@ -390,14 +402,19 @@ method onChatsLoaded*( self.usersModule.load() let community = self.controller.getMyCommunity() self.view.setAmIMember(community.joined) - self.initCommunityTokenPermissionsModel() + self.initCommunityTokenPermissionsModel(channelGroup) self.controller.asyncCheckPermissionsToJoin() let activeChatId = self.controller.getActiveChatId() let isCurrentSectionActive = self.controller.getIsCurrentSectionActive() - for chatId, cModule in self.chatContentModules: - if isCurrentSectionActive and chatId == activeChatId: - cModule.onMadeActive() + if isCurrentSectionActive: + for chatId, cModule in self.chatContentModules: + if chatId == activeChatId: + cModule.onMadeActive() + + if(self.controller.isCommunity()): + let community = self.controller.getMyCommunity() + self.controller.asyncCheckChannelPermissions(community.id, activeChatId) self.view.chatsLoaded() @@ -475,6 +492,10 @@ method activeItemSet*(self: Module, itemId: string) = # notify parent module about active chat/channel self.delegate.onActiveChatChange(mySectionId, activeChatId) self.delegate.onDeactivateChatLoader(deactivateSectionId, deactivateChatId) + + if self.controller.isCommunity(): + self.controller.asyncCheckChannelPermissions(mySectionId, activeChatId) + method getModuleAsVariant*(self: Module): QVariant = return self.viewVariant @@ -496,6 +517,16 @@ proc updateParentBadgeNotifications(self: Module) = unviewedMentionsCount ) +proc updateChatLocked(self: Module, chatId: string) = + let communityId = self.controller.getMySectionId() + let locked = self.controller.checkChatIsLocked(communityId, chatId) + self.view.chatsModel().setItemLocked(chatId, locked) + +proc updateChatRequiresPermissions(self: Module, chatId: string) = + let communityId = self.controller.getMySectionId + let requiresPermissions = self.controller.checkChatHasPermissions(communityId, chatId) + self.view.chatsModel().setItemPermissionsRequired(chatId, requiresPermissions) + proc updateBadgeNotifications(self: Module, chat: ChatDto, hasUnreadMessages: bool, unviewedMentionsCount: int) = let chatId = chat.id @@ -530,6 +561,11 @@ method onActiveSectionChange*(self: Module, sectionId: string) = self.setFirstChannelAsActive() else: self.setActiveItem(activeChatId) + + if self.isCommunity(): + self.controller.asyncCheckPermissionsToJoin() + self.controller.asyncCheckAllChannelsPermissions() + self.delegate.onActiveChatChange(self.controller.getMySectionId(), self.controller.getActiveChatId()) method chatsModel*(self: Module): chats_model.Model = @@ -625,7 +661,10 @@ method addNewChat*( categoryOpened, onlineStatus = onlineStatus, loaderActive = setChatAsActive, + locked = self.controller.checkChatIsLocked(self.controller.getMySectionId(), chatDto.id), + requiresPermissions = self.controller.checkChatHasPermissions(self.controller.getMySectionId(), chatDto.id) ) + self.addSubmodule( chatDto.id, belongsToCommunity, @@ -640,6 +679,7 @@ method addNewChat*( gifService, mailserversService, ) + self.chatContentModules[chatDto.id].load(result) if insertIntoModel: self.view.chatsModel().appendItem(result) @@ -786,19 +826,17 @@ method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, per method onCommunityTokenPermissionCreated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) = let tokenPermissionItem = buildTokenPermissionItem(tokenPermission) - if tokenPermissionItem.tokenCriteriaMet: - self.view.setAllTokenRequirementsMet(true) - self.view.tokenPermissionsModel.addItem(tokenPermissionItem) - self.view.setRequiresTokenPermissionToJoin(true) + self.view.tokenPermissionsModel.addItem(tokenPermissionItem) + self.reevaluateRequiresTokenPermissionToJoin() singletonInstance.globalEvents.showCommunityTokenPermissionCreatedNotification(communityId, "Community permission created", "A token permission has been added") -method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) = - let community = self.controller.getMyCommunity() - - for id, criteriaResult in checkPermissionsToJoinResponse.permissions: +proc updateTokenPermissionModel*(self: Module, permissions: Table[string, CheckPermissionsResultDto], community: CommunityDto) = + for id, criteriaResult in permissions: if community.tokenPermissions.hasKey(id): let tokenPermissionItem = self.view.tokenPermissionsModel.getItemById(id) + if tokenPermissionItem.id == "": + continue var updatedTokenCriteriaItems: seq[TokenCriteriaItem] = @[] var permissionSatisfied = true @@ -823,7 +861,7 @@ method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissions tokenPermissionItem.id, tokenPermissionItem.`type`, updatedTokenCriteriaItems, - @[], # TODO: handle chat list items + tokenPermissionItem.getChatList().getItems(), tokenPermissionItem.isPrivate, permissionSatisfied ) @@ -852,9 +890,23 @@ method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissions self.view.setRequiresTokenPermissionToJoin(requiresPermissionToJoin) +proc updateChannelPermissionViewData*(self: Module, chatId: string, viewOnlyPermissions: ViewOnlyOrViewAndPostPermissionsResponseDto, viewAndPostPermissions: ViewOnlyOrViewAndPostPermissionsResponseDto, community: CommunityDto) = + self.updateTokenPermissionModel(viewOnlyPermissions.permissions, community) + self.updateTokenPermissionModel(viewAndPostPermissions.permissions, community) + self.updateChatRequiresPermissions(chatId) + self.updateChatLocked(chatId) + self.chatContentModules[chatId].onUpdateViewOnlyPermissionsSatisfied(viewOnlyPermissions.satisfied) + self.chatContentModules[chatId].onUpdateViewAndPostPermissionsSatisfied(viewAndPostPermissions.satisfied) + +method onCommunityCheckPermissionsToJoinResponse*(self: Module, checkPermissionsToJoinResponse: CheckPermissionsToJoinResponseDto) = + let community = self.controller.getMyCommunity() + self.view.setAllTokenRequirementsMet(checkPermissionsToJoinResponse.satisfied) + self.updateTokenPermissionModel(checkPermissionsToJoinResponse.permissions, community) + method onCommunityTokenPermissionUpdated*(self: Module, communityId: string, tokenPermission: CommunityTokenPermissionDto) = let tokenPermissionItem = buildTokenPermissionItem(tokenPermission) self.view.tokenPermissionsModel.updateItem(tokenPermission.id, tokenPermissionItem) + self.reevaluateRequiresTokenPermissionToJoin() singletonInstance.globalEvents.showCommunityTokenPermissionUpdatedNotification(communityId, "Community permission updated", "A token permission has been updated") @@ -867,6 +919,15 @@ method onCommunityTokenPermissionUpdateFailed*(self: Module, communityId: string method onCommunityTokenPermissionDeletionFailed*(self: Module, communityId: string) = singletonInstance.globalEvents.showCommunityTokenPermissionDeletionFailedNotification(communityId, "Failed to delete community permission", "Something went wrong") +method onCommunityCheckChannelPermissionsResponse*(self: Module, chatId: string, checkChannelPermissionsResponse: CheckChannelPermissionsResponseDto) = + let community = self.controller.getMyCommunity() + self.updateChannelPermissionViewData(chatId, checkChannelPermissionsResponse.viewOnlyPermissions, checkChannelPermissionsResponse.viewAndPostPermissions, community) + +method onCommunityCheckAllChannelsPermissionsResponse*(self: Module, checkAllChannelsPermissionsResponse: CheckAllChannelsPermissionsResponseDto) = + let community = self.controller.getMyCommunity() + for chatId, permissionResult in checkAllChannelsPermissionsResponse.channels: + self.updateChannelPermissionViewData(chatId, permissionResult.viewOnlyPermissions, permissionResult.viewAndPostPermissions, community) + method onCommunityTokenMetadataAdded*(self: Module, communityId: string, tokenMetadata: CommunityTokensMetadataDto) = let tokenListItem = initTokenListItem( key = tokenMetadata.symbol, @@ -1207,6 +1268,8 @@ proc addOrUpdateChat(self: Module, if chatExists: self.changeMutedOnChat(chat.id, chat.muted) + self.updateChatRequiresPermissions(chat.id) + self.updateChatLocked(chat.id) if (chat.chatType == ChatType.PrivateGroupChat): self.onGroupChatDetailsUpdated(chat.id, chat.name, chat.color, chat.icon) elif (chat.chatType != ChatType.OneToOne): @@ -1278,13 +1341,19 @@ method joinSpectatedCommunity*(self: Module) = if self.usersModule != nil: self.usersModule.updateMembersList() -method createOrEditCommunityTokenPermission*(self: Module, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, isPrivate: bool) = +method createOrEditCommunityTokenPermission*(self: Module, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, channelIDs: seq[string], isPrivate: bool) = + var tokenPermission = CommunityTokenPermissionDto() tokenPermission.id = permissionId tokenPermission.isPrivate = isPrivate tokenPermission.`type` = TokenPermissionType(permissionType) + tokenPermission.chatIDs = channelIDs + + if tokenPermission.`type` != TokenPermissionType.View and tokenPermission.`type` != TokenPermissionType.ViewAndPost: + tokenPermission.chatIDs = @[] let tokenCriteriaJsonObj = tokenCriteriaJson.parseJson + for tokenCriteria in tokenCriteriaJsonObj: let viewAmount = tokenCriteria{"amount"}.getFloat diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index 65d2961f2d..33df9ebca3 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -1,4 +1,4 @@ -import NimQml, json, sequtils +import NimQml, json, sequtils, strutils import model as chats_model import item, active_item import ../../shared_models/user_model as user_model @@ -401,8 +401,10 @@ QtObject: QtProperty[QVariant] permissionsModel: read = getTokenPermissionsModel - proc createOrEditCommunityTokenPermission*(self: View, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, isPrivate: bool) {.slot.} = - self.delegate.createOrEditCommunityTokenPermission(communityId, permissionId, permissionType, tokenCriteriaJson, isPrivate) + proc createOrEditCommunityTokenPermission*(self: View, communityId: string, permissionId: string, permissionType: int, tokenCriteriaJson: string, channelIDs: string, isPrivate: bool) {.slot.} = + + let chatIDs = channelIDs.split(',') + self.delegate.createOrEditCommunityTokenPermission(communityId, permissionId, permissionType, tokenCriteriaJson, chatIDs, isPrivate) proc deleteCommunityTokenPermission*(self: View, communityId: string, permissionId: string) {.slot.} = self.delegate.deleteCommunityTokenPermission(communityId, permissionId) @@ -450,4 +452,4 @@ QtObject: QtProperty[bool] allTokenRequirementsMet: read = getAllTokenRequirementsMet - notify = allTokenRequirementsMetChanged \ No newline at end of file + notify = allTokenRequirementsMetChanged diff --git a/src/app/modules/shared_models/token_permission_chat_list_item.nim b/src/app/modules/shared_models/token_permission_chat_list_item.nim index 0eb4f362b5..6edba2f29f 100644 --- a/src/app/modules/shared_models/token_permission_chat_list_item.nim +++ b/src/app/modules/shared_models/token_permission_chat_list_item.nim @@ -3,23 +3,17 @@ import strformat type TokenPermissionChatListItem* = object key: string - name: string proc `$`*(self: TokenPermissionChatListItem): string = result = fmt"""TokenPermissionChatListItem( - key: {self.key}, - name: {self.name}, + key: {self.key} ]""" proc initTokenPermissionChatListItem*( - key: string, - name: string, + key: string ): TokenPermissionChatListItem = result.key = key - result.name = name proc getKey*(self: TokenPermissionChatListItem): string = return self.key -proc getName*(self: TokenPermissionChatListItem): string = - return self.name diff --git a/src/app/modules/shared_models/token_permission_chat_list_model.nim b/src/app/modules/shared_models/token_permission_chat_list_model.nim index def062502b..3f7edb7ca6 100644 --- a/src/app/modules/shared_models/token_permission_chat_list_model.nim +++ b/src/app/modules/shared_models/token_permission_chat_list_model.nim @@ -4,7 +4,6 @@ import token_permission_chat_list_item type ModelRole {.pure.} = enum Key = UserRole + 1 - Name QtObject: type TokenPermissionChatListModel* = ref object of QAbstractListModel @@ -24,7 +23,6 @@ QtObject: method roleNames(self: TokenPermissionChatListModel): Table[int, string] = { ModelRole.Key.int:"key", - ModelRole.Name.int:"name", }.toTable proc countChanged(self: TokenPermissionChatListModel) {.signal.} @@ -47,8 +45,6 @@ QtObject: case enumRole: of ModelRole.Key: result = newQVariant(item.getKey()) - of ModelRole.Name: - result = newQVariant(item.getName()) proc addItem*(self: TokenPermissionChatListModel, item: TokenPermissionChatListItem) = let parentModelIndex = newQModelIndex() @@ -57,3 +53,12 @@ QtObject: self.items.add(item) self.endInsertRows() self.countChanged() + + proc setItems*(self: TokenPermissionChatListModel, items: seq[TokenPermissionChatListItem]) = + self.beginResetModel() + self.items = items + self.endResetModel() + self.countChanged() + + proc getItems*(self: TokenPermissionChatListModel): seq[TokenPermissionChatListItem] = + return self.items diff --git a/src/app/modules/shared_models/token_permission_item.nim b/src/app/modules/shared_models/token_permission_item.nim index 5ff03e9212..97d9223932 100644 --- a/src/app/modules/shared_models/token_permission_item.nim +++ b/src/app/modules/shared_models/token_permission_item.nim @@ -63,7 +63,6 @@ proc getIsPrivate*(self: TokenPermissionItem): bool = proc getTokenCriteriaMet*(self: TokenPermissionItem): bool = return self.tokenCriteriaMet - proc buildTokenPermissionItem*(tokenPermission: CommunityTokenPermissionDto): TokenPermissionItem = var tokenCriteriaItems: seq[TokenCriteriaItem] = @[] @@ -80,11 +79,15 @@ proc buildTokenPermissionItem*(tokenPermission: CommunityTokenPermissionDto): To tokenCriteriaItems.add(tokenCriteriaItem) + var tokenPermissionChatListItems: seq[TokenPermissionChatListItem] = @[] + for chatID in tokenPermission.chatIDs: + tokenPermissionChatListItems.add(initTokenPermissionChatListItem(chatID)) + let tokenPermissionItem = initTokenPermissionItem( tokenPermission.id, tokenPermission.`type`.int, tokenCriteriaItems, - @[], # TODO: handle chat list items + tokenPermissionChatListItems, tokenPermission.isPrivate, false # allTokenCriteriaMet will be update by a call to checkPermissinosToJoin ) diff --git a/src/app/modules/shared_models/token_permissions_model.nim b/src/app/modules/shared_models/token_permissions_model.nim index 333cea1c35..d557e5c9a1 100644 --- a/src/app/modules/shared_models/token_permissions_model.nim +++ b/src/app/modules/shared_models/token_permissions_model.nim @@ -1,5 +1,7 @@ import NimQml, Tables import token_permission_item +import token_permission_chat_list_item +import token_permission_chat_list_model import token_criteria_model type @@ -10,6 +12,7 @@ type TokenCriteria ChatList IsPrivate + TokenCriteriaMet QtObject: type TokenPermissionsModel* = ref object of QAbstractListModel @@ -34,15 +37,34 @@ QtObject: ModelRole.TokenCriteria.int:"holdingsListModel", ModelRole.ChatList.int:"channelsListModel", ModelRole.IsPrivate.int:"isPrivate", + ModelRole.TokenCriteriaMet.int:"tokenCriteriaMet", }.toTable proc countChanged(self: TokenPermissionsModel) {.signal.} proc getCount*(self: TokenPermissionsModel): int {.slot.} = return self.items.len + QtProperty[int] count: read = getCount notify = countChanged + proc findIndexById(self: TokenPermissionsModel, id: string): int = + for i in 0 ..< self.items.len: + if(self.items[i].getId() == id): + return i + return -1 + + proc belongsToChat*(self: TokenPermissionsModel, permissionId: string, chatId: string): bool {.slot.} = + let idx = self.findIndexById(permissionId) + if(idx == -1): + return false + + for clItem in self.items[idx].chatList.getItems(): + if clItem.getKey() == chatId: + return true + + return false + method rowCount(self: TokenPermissionsModel, index: QModelIndex = nil): int = return self.items.len @@ -66,6 +88,8 @@ QtObject: result = newQVariant(item.getChatList()) of ModelRole.IsPrivate: result = newQVariant(item.getIsPrivate()) + of ModelRole.TokenCriteriaMet: + result = newQVariant(item.getTokenCriteriaMet()) proc addItem*(self: TokenPermissionsModel, item: TokenPermissionItem) = let parentModelIndex = newQModelIndex() @@ -84,12 +108,6 @@ QtObject: proc getItems*(self: TokenPermissionsModel): seq[TokenPermissionItem] = return self.items - proc findIndexById(self: TokenPermissionsModel, id: string): int = - for i in 0 ..< self.items.len: - if(self.items[i].getId() == id): - return i - return -1 - proc removeItemWithId*(self: TokenPermissionsModel, permissionId: string) = let idx = self.findIndexById(permissionId) if(idx == -1): @@ -117,6 +135,7 @@ QtObject: self.items[idx].`type` = item.`type` self.items[idx].tokenCriteria.setItems(item.tokenCriteria.getItems()) + self.items[idx].chatList.setItems(item.chatList.getItems()) self.items[idx].isPrivate = item.isPrivate self.items[idx].tokenCriteriaMet = item.tokenCriteriaMet @@ -127,4 +146,5 @@ QtObject: ModelRole.Type.int, ModelRole.TokenCriteria.int, ModelRole.IsPrivate.int, + ModelRole.TokenCriteriaMet.int ]) diff --git a/src/app_service/service/community/async_tasks.nim b/src/app_service/service/community/async_tasks.nim index 3b737dbbe0..2b3fcb604c 100644 --- a/src/app_service/service/community/async_tasks.nim +++ b/src/app_service/service/community/async_tasks.nim @@ -121,3 +121,44 @@ const asyncCheckPermissionsToJoinTask: Task = proc(argEncoded: string) {.gcsafe, "communityId": arg.communityId, "error": e.msg, }) + +type + AsyncCheckChannelPermissionsTaskArg = ref object of QObjectTaskArg + communityId: string + chatId: string + +const asyncCheckChannelPermissionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncCheckChannelPermissionsTaskArg](argEncoded) + try: + let response = status_go.checkCommunityChannelPermissions(arg.communityId, arg.chatId) + arg.finish(%* { + "response": response, + "communityId": arg.communityId, + "chatId": arg.chatId, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "communityId": arg.communityId, + "chatId": arg.chatId, + "error": e.msg, + }) + +type + AsyncCheckAllChannelsPermissionsTaskArg = ref object of QObjectTaskArg + communityId: string + +const asyncCheckAllChannelsPermissionsTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} = + let arg = decode[AsyncCheckAllChannelsPermissionsTaskArg](argEncoded) + try: + let response = status_go.checkAllCommunityChannelsPermissions(arg.communityId) + arg.finish(%* { + "response": response, + "communityId": arg.communityId, + "error": "", + }) + except Exception as e: + arg.finish(%* { + "communityId": arg.communityId, + "error": e.msg, + }) diff --git a/src/app_service/service/community/dto/community.nim b/src/app_service/service/community/dto/community.nim index 13e4d059ea..d67ccc763c 100644 --- a/src/app_service/service/community/dto/community.nim +++ b/src/app_service/service/community/dto/community.nim @@ -39,7 +39,6 @@ type TokenPermissionType* {.pure.}= enum View = 3, ViewAndPost = 4, - type TokenType* {.pure.}= enum Unknown = 0, ERC20 = 1, @@ -71,6 +70,29 @@ type CommunityTokensMetadataDto* = object name*: string tokenType*: TokenType +type AccountChainIDsCombinationDto* = object + address*: string + chainIds*: seq[int] + +type CheckPermissionsResultDto* = object + criteria*: seq[bool] + +type CheckPermissionsToJoinResponseDto* = object + satisfied*: bool + permissions*: Table[string, CheckPermissionsResultDto] + validCombinations*: seq[AccountChainIDsCombinationDto] + +type ViewOnlyOrViewAndPostPermissionsResponseDto* = object + satisfied*: bool + permissions*: Table[string, CheckPermissionsResultDto] + +type CheckChannelPermissionsResponseDto* = object + viewOnlyPermissions*: ViewOnlyOrViewAndPostPermissionsResponseDto + viewAndPostPermissions*: ViewOnlyOrViewAndPostPermissionsResponseDto + +type CheckAllChannelsPermissionsResponseDto* = object + channels*: Table[string, CheckChannelPermissionsResponseDto] + type CommunityDto* = object id*: string memberRole*: MemberRole @@ -106,6 +128,7 @@ type CommunityDto* = object canceledRequestsToJoin*: seq[CommunityMembershipRequestDto] tokenPermissions*: Table[string, CommunityTokenPermissionDto] communityTokensMetadata*: seq[CommunityTokensMetadataDto] + channelPermissions*: CheckAllChannelsPermissionsResponseDto activeMembersCount*: int64 proc isAvailable*(communityDto: CommunityDto): bool = @@ -140,18 +163,6 @@ type DiscordImportTaskProgress* = object stopped*: bool state*: string -type AccountChainIDsCombinationDto* = object - address*: string - chainIds*: seq[int] - -type CheckPermissionToJoinResultDto* = object - criteria*: seq[bool] - -type CheckPermissionsToJoinResponseDto* = object - satisfied*: bool - permissions*: Table[string, CheckPermissionToJoinResultDto] - validCombinations*: seq[AccountChainIDsCombinationDto] - proc toCommunityAdminSettingsDto*(jsonObj: JsonNode): CommunityAdminSettingsDto = result = CommunityAdminSettingsDto() discard jsonObj.getProp("pinMessageAllMembersEnabled", result.pinMessageAllMembersEnabled) @@ -241,7 +252,7 @@ proc toTokenCriteriaDto*(jsonObj: JsonNode): TokenCriteriaDto = proc toCommunityTokenPermissionDto*(jsonObj: JsonNode): CommunityTokenPermissionDto = result = CommunityTokenPermissionDto() discard jsonObj.getProp("id", result.id) - discard jsonObj.getProp("isPrivate", result.isPrivate) + discard jsonObj.getProp("is_private", result.isPrivate) var tokenPermissionTypeInt: int discard jsonObj.getProp("type", tokenPermissionTypeInt) if (tokenPermissionTypeInt >= ord(low(TokenPermissionType)) or tokenPermissionTypeInt <= ord(high(TokenPermissionType))): @@ -253,7 +264,7 @@ proc toCommunityTokenPermissionDto*(jsonObj: JsonNode): CommunityTokenPermission result.tokenCriteria.add(tokenCriteria.toTokenCriteriaDto) var chatIdsObj: JsonNode - if(jsonObj.getProp("chatIds", chatIdsObj) and chatIdsObj.kind == JArray): + if(jsonObj.getProp("chat_ids", chatIdsObj) and chatIdsObj.kind == JArray): for chatId in chatIdsObj: result.chatIds.add(chatId.getStr) @@ -262,8 +273,8 @@ proc toCommunityTokenPermissionDto*(jsonObj: JsonNode): CommunityTokenPermission if jsonObj.hasKey("key"): discard jsonObj.getProp("key", result.id) -proc toCheckPermissionToJoinResultDto*(jsonObj: JsonNode): CheckPermissionToJoinResultDto = - result = CheckPermissionToJoinResultDto() +proc toCheckPermissionsResultDto*(jsonObj: JsonNode): CheckPermissionsResultDto = + result = CheckPermissionsResultDto() var criteriaObj: JsonNode if(jsonObj.getProp("criteria", criteriaObj) and criteriaObj.kind == JArray): for c in criteriaObj: @@ -288,9 +299,39 @@ proc toCheckPermissionsToJoinResponseDto*(jsonObj: JsonNode): CheckPermissionsTo var permissionsObj: JsonNode if(jsonObj.getProp("permissions", permissionsObj) and permissionsObj.kind == JObject): - result.permissions = initTable[string, CheckPermissionToJoinResultDto]() + result.permissions = initTable[string, CheckPermissionsResultDto]() for permissionId, permission in permissionsObj: - result.permissions[permissionId] = permission.toCheckPermissionToJoinResultDto + result.permissions[permissionId] = permission.toCheckPermissionsResultDto + +proc toViewOnlyOrViewAndPostPermissionsResponseDto*(jsonObj: JsonNode): ViewOnlyOrViewAndPostPermissionsResponseDto = + result = ViewOnlyOrViewAndPostPermissionsResponseDto() + discard jsonObj.getProp("satisfied", result.satisfied) + + var permissionsObj: JsonNode + if(jsonObj.getProp("permissions", permissionsObj) and permissionsObj.kind == JObject): + result.permissions = initTable[string, CheckPermissionsResultDto]() + for permissionId, permission in permissionsObj: + result.permissions[permissionId] = permission.toCheckPermissionsResultDto + +proc toCheckChannelPermissionsResponseDto*(jsonObj: JsonNode): CheckChannelPermissionsResponseDto = + result = CheckChannelPermissionsResponseDto() + + var viewOnlyPermissionsObj: JsonNode + if(jsonObj.getProp("viewOnlyPermissions", viewOnlyPermissionsObj) and viewOnlyPermissionsObj.kind == JObject): + result.viewOnlyPermissions = viewOnlyPermissionsObj.toViewOnlyOrViewAndPostPermissionsResponseDto() + + var viewAndPostPermissionsObj: JsonNode + if(jsonObj.getProp("viewAndPostPermissions", viewAndPostPermissionsObj) and viewAndPostPermissionsObj.kind == JObject): + result.viewAndPostPermissions = viewAndPostPermissionsObj.toViewOnlyOrViewAndPostPermissionsResponseDto() + +proc toCheckAllChannelsPermissionsResponseDto*(jsonObj: JsonNode): CheckAllChannelsPermissionsResponseDto = + result = CheckAllChannelsPermissionsResponseDto() + result.channels = initTable[string, CheckChannelPermissionsResponseDto]() + + var channelsObj: JsonNode + if(jsonObj.getProp("channels", channelsObj) and channelsObj.kind == JObject): + for channelId, permissionResponse in channelsObj: + result.channels[channelId] = permissionResponse.toCheckChannelPermissionsResponseDto() proc toCommunityDto*(jsonObj: JsonNode): CommunityDto = result = CommunityDto() diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 59369dc814..2aa502f8b3 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -117,6 +117,15 @@ type communityId*: string checkPermissionsToJoinResponse*: CheckPermissionsToJoinResponseDto + CheckChannelPermissionsResponseArgs* = ref object of Args + communityId*: string + chatId*: string + checkChannelPermissionsResponse*: CheckChannelPermissionsResponseDto + + CheckAllChannelsPermissionsResponseArgs* = ref object of Args + communityId*: string + checkAllChannelsPermissionsResponse*: CheckAllChannelsPermissionsResponseDto + # Signals which may be emitted by this service: const SIGNAL_COMMUNITY_DATA_LOADED* = "communityDataLoaded" const SIGNAL_COMMUNITY_JOINED* = "communityJoined" @@ -179,6 +188,8 @@ const TOKEN_PERMISSIONS_ADDED = "tokenPermissionsAdded" const TOKEN_PERMISSIONS_MODIFIED = "tokenPermissionsModified" const SIGNAL_CHECK_PERMISSIONS_TO_JOIN_RESPONSE* = "checkPermissionsToJoinResponse" +const SIGNAL_CHECK_CHANNEL_PERMISSIONS_RESPONSE* = "checkChannelPermissionsResponse" +const SIGNAL_CHECK_ALL_CHANNELS_PERMISSIONS_RESPONSE* = "checkAllChannelsPermissionsResponse" QtObject: type @@ -581,6 +592,7 @@ QtObject: if tokenPermission.tokenCriteria.len != prevTokenPermission.tokenCriteria.len or tokenPermission.isPrivate != prevTokenPermission.isPrivate or + tokenPermission.chatIds.len != prevTokenPermission.chatIds.len or tokenPermission.`type` != prevTokenPermission.`type`: permissionUpdated = true @@ -588,14 +600,16 @@ QtObject: for tc in tokenPermission.tokenCriteria: let index = findIndexBySymbol(tc.symbol, prevTokenPermission.tokenCriteria) if index == -1: - continue - - let prevTc = prevTokenPermission.tokenCriteria[index] - if tc.amount != prevTc.amount or tc.ensPattern != prevTc.ensPattern: permissionUpdated = true - break + else: + + let prevTc = prevTokenPermission.tokenCriteria[index] + if tc.amount != prevTc.amount or tc.ensPattern != prevTc.ensPattern or tc.symbol != prevTc.symbol or tc.name != prevTc.name or tc.decimals != prevTc.decimals: + permissionUpdated = true + break if permissionUpdated: + self.communities[community.id].tokenPermissions[id] = tokenPermission self.events.emit(SIGNAL_COMMUNITY_TOKEN_PERMISSION_UPDATED, CommunityTokenPermissionArgs(communityId: community.id, tokenPermission: tokenPermission)) @@ -1371,16 +1385,13 @@ QtObject: self.events.emit(SIGNAL_COMMUNITY_DATA_IMPORTED, CommunityArgs(community: community)) proc asyncCheckPermissionsToJoin*(self: Service, communityId: string) = - try: - let arg = AsyncCheckPermissionsToJoinTaskArg( - tptr: cast[ByteAddress](asyncCheckPermissionsToJoinTask), - vptr: cast[ByteAddress](self.vptr), - slot: "onAsyncCheckPermissionsToJoinDone", - communityId: communityId - ) - self.threadpool.start(arg) - except Exception as e: - error "Error checking permissions to join community", msg = e.msg + let arg = AsyncCheckPermissionsToJoinTaskArg( + tptr: cast[ByteAddress](asyncCheckPermissionsToJoinTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCheckPermissionsToJoinDone", + communityId: communityId + ) + self.threadpool.start(arg) proc onAsyncCheckPermissionsToJoinDone*(self: Service, rpcResponse: string) {.slot.} = try: @@ -1397,6 +1408,59 @@ QtObject: let errMsg = e.msg error "error checking permissions to join: ", errMsg + proc asyncCheckChannelPermissions*(self: Service, communityId: string, chatId: string) = + let arg = AsyncCheckChannelPermissionsTaskArg( + tptr: cast[ByteAddress](asyncCheckChannelPermissionsTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCheckChannelPermissionsDone", + communityId: communityId, + chatId: chatId + ) + self.threadpool.start(arg) + + proc onAsyncCheckChannelPermissionsDone*(self: Service, rpcResponse: string) {.slot.} = + try: + let rpcResponseObj = rpcResponse.parseJson + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + let error = Json.decode($rpcResponseObj["error"], RpcError) + error "Error checking community channel permissions", msg = error.message + return + + let communityId = rpcResponseObj{"communityId"}.getStr() + let chatId = rpcResponseObj{"chatId"}.getStr() + let checkChannelPermissionsResponse = rpcResponseObj["response"]["result"].toCheckChannelPermissionsResponseDto() + self.communities[communityId].channelPermissions.channels[chatId] = checkChannelPermissionsResponse + self.events.emit(SIGNAL_CHECK_CHANNEL_PERMISSIONS_RESPONSE, CheckChannelPermissionsResponseArgs(communityId: communityId, chatId: chatId, checkChannelPermissionsResponse: checkChannelPermissionsResponse)) + except Exception as e: + let errMsg = e.msg + error "error checking all channel permissions: ", errMsg + + proc asyncCheckAllChannelsPermissions*(self: Service, communityId: string) = + let arg = AsyncCheckAllChannelsPermissionsTaskArg( + tptr: cast[ByteAddress](asyncCheckAllChannelsPermissionsTask), + vptr: cast[ByteAddress](self.vptr), + slot: "onAsyncCheckAllChannelsPermissionsDone", + communityId: communityId + ) + self.threadpool.start(arg) + + proc onAsyncCheckAllChannelsPermissionsDone*(self: Service, rpcResponse: string) {.slot.} = + try: + let rpcResponseObj = rpcResponse.parseJson + if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "": + let error = Json.decode($rpcResponseObj["error"], RpcError) + error "Error checking all community channel permissions", msg = error.message + return + + let communityId = rpcResponseObj{"communityId"}.getStr() + let checkAllChannelsPermissionsResponse = rpcResponseObj["response"]["result"].toCheckAllChannelsPermissionsResponseDto() + self.communities[communityId].channelPermissions = checkAllChannelsPermissionsResponse + self.events.emit(SIGNAL_CHECK_ALL_CHANNELS_PERMISSIONS_RESPONSE, CheckAllChannelsPermissionsResponseArgs(communityId: communityId, checkAllChannelsPermissionsResponse: checkAllChannelsPermissionsResponse)) + + except Exception as e: + let errMsg = e.msg + error "error checking all channels permissions: ", errMsg + proc asyncRequestToJoinCommunity*(self: Service, communityId: string, ensName: string, password: string) = try: let arg = AsyncRequestToJoinCommunityTaskArg( @@ -1783,9 +1847,9 @@ QtObject: var response: RpcResponse[JsonNode] if editing: - response = status_go.editCommunityTokenPermission(communityId, tokenPermission.id, int(tokenPermission.`type`), Json.encode(tokenPermission.tokenCriteria), tokenPermission.isPrivate) + response = status_go.editCommunityTokenPermission(communityId, tokenPermission.id, int(tokenPermission.`type`), Json.encode(tokenPermission.tokenCriteria), tokenPermission.chatIDs, tokenPermission.isPrivate) else: - response = status_go.createCommunityTokenPermission(communityId, int(tokenPermission.`type`), Json.encode(tokenPermission.tokenCriteria), tokenPermission.isPrivate) + response = status_go.createCommunityTokenPermission(communityId, int(tokenPermission.`type`), Json.encode(tokenPermission.tokenCriteria), tokenPermission.chatIDs, tokenPermission.isPrivate) if response.result != nil and response.result.kind != JNull: var changesField = TOKEN_PERMISSIONS_ADDED @@ -1835,3 +1899,20 @@ QtObject: let community = self.communities[communityId] return community.pendingRequestsToJoin[indexPending].publicKey + + proc checkChatHasPermissions*(self: Service, communityId: string, chatId: string): bool = + let community = self.getCommunityById(communityId) + for id, tokenPermission in community.tokenPermissions: + if TokenPermissionType(tokenPermission.`type`) == TokenPermissionType.View or TokenPermissionType(tokenPermission.`type`) == TokenPermissionType.ViewAndPost: + for id in tokenPermission.chatIds: + if id == chatId: + return true + return false + + proc checkChatIsLocked*(self: Service, communityId: string, chatId: string): bool = + if not self.communities.hasKey(communityId): + return false + + let community = self.getCommunityById(communityId) + return community.channelPermissions.channels.hasKey(chatId) and not community.channelPermissions.channels[chatId].viewAndPostPermissions.satisfied + diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 33be3fdc6a..b1d6bcff41 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -44,6 +44,17 @@ proc checkPermissionsToJoinCommunity*(communityId: string): RpcResponse[JsonNode "communityId": communityId }]) +proc checkCommunityChannelPermissions*(communityId: string, chatId: string): RpcResponse[JsonNode] {.raises: [Exception].} = + result = callPrivateRPC("checkCommunityChannelPermissions".prefix, %*[{ + "communityId": communityId, + "chatId": chatId + }]) + +proc checkAllCommunityChannelsPermissions*(communityId: string): RpcResponse[JsonNode] {.raises: [Exception].} = + result = callPrivateRPC("checkAllCommunityChannelsPermissions".prefix, %*[{ + "communityId": communityId + }]) + proc myPendingRequestsToJoin*(): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("myPendingRequestsToJoin".prefix) @@ -177,20 +188,22 @@ proc requestImportDiscordCommunity*( "filesToImport": filesToImport }]) -proc createCommunityTokenPermission*(communityId: string, permissionType: int, tokenCriteria: string, isPrivate: bool): RpcResponse[JsonNode] {.raises: [Exception].} = +proc createCommunityTokenPermission*(communityId: string, permissionType: int, tokenCriteria: string, chatIDs: seq[string], isPrivate: bool): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("createCommunityTokenPermission".prefix, %*[{ "communityId": communityId, "type": permissionType, "tokenCriteria": parseJson(tokenCriteria), + "chat_ids": chatIDs, "isPrivate": isPrivate }]) -proc editCommunityTokenPermission*(communityId: string, permissionId: string, permissionType: int, tokenCriteria: string, isPrivate: bool): RpcResponse[JsonNode] {.raises: [Exception].} = +proc editCommunityTokenPermission*(communityId: string, permissionId: string, permissionType: int, tokenCriteria: string, chatIDs: seq[string], isPrivate: bool): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("editCommunityTokenPermission".prefix, %*[{ "communityId": communityId, "permissionId": permissionId, "type": permissionType, "tokenCriteria": parseJson(tokenCriteria), + "chat_ids": chatIDs, "isPrivate": isPrivate }]) diff --git a/ui/StatusQ/src/StatusQ/Components/StatusChatList.qml b/ui/StatusQ/src/StatusQ/Components/StatusChatList.qml index 16fbd14cf6..b46172ecc3 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusChatList.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusChatList.qml @@ -180,6 +180,8 @@ Item { onlineStatus: !!model.onlineStatus ? model.onlineStatus : StatusChatListItem.OnlineStatus.Inactive sensor.enabled: draggableItem.dragActive dragged: draggableItem.dragActive + requiresPermissions: model.requiresPermissions + locked: model.locked onClicked: { highlightWhenCreated = false diff --git a/ui/StatusQ/src/StatusQ/Components/StatusChatListItem.qml b/ui/StatusQ/src/StatusQ/Components/StatusChatListItem.qml index d3303ab0ce..949105efe9 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusChatListItem.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusChatListItem.qml @@ -20,6 +20,8 @@ Rectangle { property int notificationsCount: 0 property bool muted: false property int onlineStatus: StatusChatListItem.OnlineStatus.Inactive + property bool requiresPermissions: false + property bool locked: false property StatusAssetSettings asset: StatusAssetSettings { width: 24 @@ -36,9 +38,6 @@ Rectangle { property bool dragged: false property alias sensor: sensor - property bool requiresPermissions - property bool locked - signal clicked(var mouse) signal unmute() diff --git a/ui/app/AppLayouts/Chat/ChatLayout.qml b/ui/app/AppLayouts/Chat/ChatLayout.qml index b896e48f7d..584bf56fa7 100644 --- a/ui/app/AppLayouts/Chat/ChatLayout.qml +++ b/ui/app/AppLayouts/Chat/ChatLayout.qml @@ -32,6 +32,7 @@ StackLayout { } Loader { + id: mainViewLoader readonly property var chatItem: root.rootStore.chatCommunitySectionModule sourceComponent: chatItem.isCommunity() && chatItem.requiresTokenPermissionToJoin && !chatItem.amIMember ? joinCommunityViewComponent : chatViewComponent } @@ -41,6 +42,7 @@ StackLayout { JoinCommunityView { id: joinCommunityView readonly property var communityData: sectionItemModel + readonly property string communityId: communityData.id name: communityData.name introMessage: communityData.introMessage communityDesc: communityData.description @@ -53,7 +55,10 @@ StackLayout { communityData.memberRole === Constants.memberRole.admin communityItemsModel: root.rootStore.communityItemsModel requirementsMet: root.permissionsStore.allTokenRequirementsMet - communityHoldingsModel: root.permissionsStore.permissionsModel + requiresRequest: !communityData.amIMember + communityHoldingsModel: root.permissionsStore.becomeMemberPermissionsModel + viewOnlyHoldingsModel: root.permissionsStore.viewOnlyPermissionsModel + viewAndPostHoldingsModel: root.permissionsStore.viewAndPostPermissionsModel assetsModel: root.rootStore.assetsModel collectiblesModel: root.rootStore.collectiblesModel isInvitationPending: root.rootStore.isCommunityRequestPending(communityData.id) @@ -63,19 +68,20 @@ StackLayout { loginType: root.rootStore.loginType onNotificationButtonClicked: Global.openActivityCenterPopup() onAdHocChatButtonClicked: rootStore.openCloseCreateChatView() - onRevealAddressClicked: openJoinCommunityDialog() + onRevealAddressClicked: { + Global.openPopup(communityIntroDialogPopup, { + communityId: communityData.id, + isInvitationPending: joinCommunityView.isInvitationPending, + name: communityData.name, + introMessage: communityData.introMessage, + imageSrc: communityData.image, + accessType: communityData.access + }) + } onInvitationPendingClicked: { root.rootStore.cancelPendingRequest(communityData.id) joinCommunityView.isInvitationPending = root.rootStore.isCommunityRequestPending(communityData.id) } - onJoined: { - root.rootStore.requestToJoinCommunityWithAuthentication(communityData.id, root.rootStore.userProfileInst.name) - } - - onCancelMembershipRequest: { - root.rootStore.cancelPendingRequest(communityData.id) - joinCommunityView.isInvitationPending = root.rootStore.isCommunityRequestPending(communityData.id) - } Connections { target: root.rootStore.communitiesModuleInst @@ -85,6 +91,25 @@ StackLayout { } } } + + CommunityIntroDialog { + id: communityIntroDialog + + isInvitationPending: joinCommunityView.isInvitationPending + name: communityData.name + introMessage: communityData.introMessage + imageSrc: communityData.image + accessType: communityData.access + + onJoined: { + root.rootStore.requestToJoinCommunityWithAuthentication(communityData.id, root.rootStore.userProfileInst.name) + } + + onCancelMembershipRequest: { + root.rootStore.cancelPendingRequest(communityData.id) + joinCommunityView.isInvitationPending = root.rootStore.isCommunityRequestPending(communityData.id) + } + } } } @@ -92,12 +117,26 @@ StackLayout { id: chatViewComponent ChatView { id: chatView + + readonly property var chatItem: root.rootStore.chatCommunitySectionModule + readonly property string communityId: root.sectionItemModel.id + emojiPopup: root.emojiPopup stickersPopup: root.stickersPopup contactsStore: root.contactsStore rootStore: root.rootStore createChatPropertiesStore: root.createChatPropertiesStore sectionItemModel: root.sectionItemModel + amIMember: chatItem.amIMember + amISectionAdmin: root.sectionItemModel.memberRole === Constants.memberRole.owner || + root.sectionItemModel.memberRole === Constants.memberRole.admin + hasViewOnlyPermissions: root.permissionsStore.viewOnlyPermissionsModel.count > 0 + hasViewAndPostPermissions: root.permissionsStore.viewAndPostPermissionsModel.count > 0 + viewOnlyPermissionsModel: root.permissionsStore.viewOnlyPermissionsModel + viewAndPostPermissionsModel: root.permissionsStore.viewAndPostPermissionsModel + assetsModel: root.rootStore.assetsModel + collectiblesModel: root.rootStore.collectiblesModel + isInvitationPending: root.rootStore.isCommunityRequestPending(root.sectionItemModel.id) onCommunityInfoButtonClicked: root.currentIndex = 1 onCommunityManageButtonClicked: root.currentIndex = 1 @@ -108,6 +147,20 @@ StackLayout { onOpenAppSearch: { root.openAppSearch() } + onRevealAddressClicked: { + Global.openPopup(communityIntroDialogPopup, { + communityId: root.sectionItemModel.id, + isInvitationPending: root.rootStore.isCommunityRequestPending(root.sectionItemModel.id), + name: root.sectionItemModel.name, + introMessage: root.sectionItemModel.introMessage, + imageSrc: root.sectionItemModel.image, + accessType: root.sectionItemModel.access + }) + } + onInvitationPendingClicked: { + root.rootStore.cancelPendingRequest(root.sectionItemModel.id) + chatView.isInvitationPending = root.rootStore.isCommunityRequestPending(root.sectionItemModel.id) + } } } @@ -134,4 +187,37 @@ StackLayout { } } } + + Component { + id: communityIntroDialogPopup + CommunityIntroDialog { + id: communityIntroDialog + + property string communityId + + onJoined: { + root.rootStore.requestToJoinCommunityWithAuthentication(communityIntroDialog.communityId, root.rootStore.userProfileInst.name) + } + + onCancelMembershipRequest: { + root.rootStore.cancelPendingRequest(communityIntroDialog.communityId) + mainViewLoader.item.isInvitationPending = root.rootStore.isCommunityRequestPending(communityIntroDialog.communityId) + } + + onClosed: { + destroy() + } + } + } + + Connections { + target: root.rootStore + enabled: mainViewLoader.item + function onCommunityAccessRequested(communityId: string) { + if (communityId === mainViewLoader.item.communityId) { + mainViewLoader.item.isInvitationPending = root.rootStore.isCommunityRequestPending(communityId) + } + } + } + } diff --git a/ui/app/AppLayouts/Chat/controls/community/PermissionTypes.qml b/ui/app/AppLayouts/Chat/controls/community/PermissionTypes.qml index 02a017f5a1..d7a051c91f 100644 --- a/ui/app/AppLayouts/Chat/controls/community/PermissionTypes.qml +++ b/ui/app/AppLayouts/Chat/controls/community/PermissionTypes.qml @@ -6,7 +6,7 @@ import StatusQ.Core.Theme 0.1 QtObject { enum Type { - None, Admin, Member, Moderator, ViewAndPost, Read + None, Admin, Member, Read, ViewAndPost } function getName(type) { diff --git a/ui/app/AppLayouts/Chat/controls/community/PermissionsDropdown.qml b/ui/app/AppLayouts/Chat/controls/community/PermissionsDropdown.qml index a58e01e7ae..9b5abf8ade 100644 --- a/ui/app/AppLayouts/Chat/controls/community/PermissionsDropdown.qml +++ b/ui/app/AppLayouts/Chat/controls/community/PermissionsDropdown.qml @@ -112,9 +112,6 @@ StatusDropdown { Layout.fillWidth: true } - // TODO: Channel-level permissions are temporarily hidden until they are - // supported by the backend. Uncomment when backend functionality is ready. - /* CustomSeparator { Layout.fillWidth: true Layout.preferredHeight: d.sectionHeight @@ -122,12 +119,6 @@ StatusDropdown { text: qsTr("Channels") } - CustomPermissionListItem { - permissionType: PermissionTypes.Type.Moderator - - Layout.fillWidth: true - } - CustomPermissionListItem { permissionType: PermissionTypes.Type.ViewAndPost @@ -139,7 +130,6 @@ StatusDropdown { Layout.fillWidth: true } - */ Separator { visible: !!group.checkedButton diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml index 7e16258456..b33a502b02 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityPermissionsSettingsPanel.qml @@ -21,10 +21,6 @@ SettingsPageLayout { property int viewWidth: 560 // by design - // TODO: temporary property, to be removed when no need to hide the switch - // in the app - property bool showWhoHoldsSwitch: false - signal createPermissionRequested( int permissionType, var holdings, var channels, bool isPrivate) @@ -182,8 +178,6 @@ SettingsPageLayout { holdingsRequired: selectedHoldingsModel ? selectedHoldingsModel.count > 0 : false - showWhoHoldsSwitch: root.showWhoHoldsSwitch - permissionDuplicated: { // dependencies holdingsTracker.revision diff --git a/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityCenterPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityCenterPanel.qml new file mode 100644 index 0000000000..22f7062d01 --- /dev/null +++ b/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityCenterPanel.qml @@ -0,0 +1,171 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtGraphicalEffects 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 +import StatusQ.Layout 0.1 + +ColumnLayout { + id: root + + property bool joinCommunity: true // Otherwise it means join channel action + + property string name + property string channelName + + property bool isInvitationPending: false + property bool isJoinRequestRejected: false + property bool requiresRequest: false + property alias loginType: overlayPanel.loginType + + property bool requirementsMet: true + + property var communityHoldingsModel + property var viewOnlyHoldingsModel + property var viewAndPostHoldingsModel + property var moderateHoldingsModel + property var assetsModel + property var collectiblesModel + + property string chatDateTimeText + property string listUsersText + property var messagesModel + + signal revealAddressClicked + signal invitationPendingClicked + + spacing: 0 + + // Blur background: + Item { + Layout.fillWidth: true + Layout.preferredHeight: Math.min( + centralPanelData.implicitHeight, + parent.height - overlayPanel.implicitHeight) + + ColumnLayout { + id: centralPanelData + width: parent.width + layer.enabled: true + layer.effect: fastBlur + + StatusBaseText { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 30 + Layout.bottomMargin: 30 + text: root.chatDateTimeText + font.pixelSize: 13 + color: Theme.palette.baseColor1 + } + + RowLayout { + Layout.alignment: Qt.AlignHCenter + + StatusBaseText { + text: root.listUsersText + font.pixelSize: 13 + } + + StatusBaseText { + text: qsTr("joined the channel") + font.pixelSize: 13 + color: Theme.palette.baseColor1 + } + } + + ListView { + Layout.fillWidth: true + Layout.preferredHeight: childrenRect.height + spacing + Layout.topMargin: 16 + spacing: 16 + model: root.messagesModel + delegate: StatusMessage { + width: ListView.view.width + timestamp: model.timestamp + enabled: false + messageDetails: StatusMessageDetails { + messageText: model.message + contentType: model.contentType + sender.displayName: model.senderDisplayName + sender.isContact: model.isContact + sender.trustIndicator: model.trustIndicator + sender.profileImage: StatusProfileImageSettings { + width: 40 + height: 40 + name: model.profileImage || "" + colorId: model.colorId + } + } + } + } + } + } + + // Permissions base information content: + Rectangle { + id: panelBase + + Layout.fillWidth: true + Layout.fillHeight: true + color: Theme.palette.statusAppLayout.rightPanelBackgroundColor + gradient: Gradient { + GradientStop { + position: 0.000 + color: "transparent" + } + GradientStop { + position: 0.180 + color: panelBase.color + } + } + + StatusScrollView { + anchors.fill: parent + padding: 0 + + Item { + implicitHeight: Math.max(overlayPanel.implicitHeight, + panelBase.height) + implicitWidth: Math.max(overlayPanel.implicitWidth, + panelBase.width) + + JoinPermissionsOverlayPanel { + id: overlayPanel + + anchors.centerIn: parent + + topPadding: 2 * bottomPadding + joinCommunity: root.joinCommunity + requirementsMet: root.requirementsMet + isInvitationPending: root.isInvitationPending + isJoinRequestRejected: root.isJoinRequestRejected + requiresRequest: root.requiresRequest + communityName: root.name + communityHoldingsModel: root.communityHoldingsModel + channelName: root.channelName + + viewOnlyHoldingsModel: root.viewOnlyHoldingsModel + viewAndPostHoldingsModel: root.viewAndPostHoldingsModel + moderateHoldingsModel: root.moderateHoldingsModel + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel + + onRevealAddressClicked: root.revealAddressClicked() + onInvitationPendingClicked: root.invitationPendingClicked() + } + } + } + } + + Component { + id: fastBlur + + FastBlur { + radius: 32 + transparentBorder: true + } + } +} diff --git a/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityHeaderPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityHeaderPanel.qml new file mode 100644 index 0000000000..cbc1dc81fd --- /dev/null +++ b/ui/app/AppLayouts/Chat/panels/communities/JoinCommunityHeaderPanel.qml @@ -0,0 +1,73 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtGraphicalEffects 1.0 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Components 0.1 +import StatusQ.Controls 0.1 + +RowLayout { + id: root + + property bool joinCommunity: true // Otherwise it means join channel action + + property color color + + property string name + property string channelName + + property string communityDesc + property string channelDesc + + spacing: 30 + + StatusChatInfoButton { + id: headerInfoButton + Layout.preferredHeight: parent.height + Layout.minimumWidth: 100 + Layout.fillWidth: true + title: root.joinCommunity ? root.name : root.channelName + subTitle: root.joinCommunity ? root.communityDesc : root.channelDesc + asset.color: root.color + enabled: false + type: StatusChatInfoButton.Type.CommunityChat + layer.enabled: root.joinCommunity // Blured when joining community but not when entering channel + layer.effect: fastBlur + } + + RowLayout { + Layout.preferredHeight: parent.height + spacing: 10 + layer.enabled: true + layer.effect: fastBlur + + StatusFlatRoundButton { + id: search + icon.name: "search" + type: StatusFlatRoundButton.Type.Secondary + enabled: false + } + + StatusFlatRoundButton { + icon.name: "group-chat" + type: StatusFlatRoundButton.Type.Secondary + enabled: false + } + + StatusFlatRoundButton { + icon.name: "more" + type: StatusFlatRoundButton.Type.Secondary + enabled: false + } + } + + Component { + id: fastBlur + + FastBlur { + radius: 32 + transparentBorder: true + } + } +} diff --git a/ui/app/AppLayouts/Chat/panels/communities/JoinPermissionsOverlayPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/JoinPermissionsOverlayPanel.qml index c8a18d731d..920be552b8 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/JoinPermissionsOverlayPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/JoinPermissionsOverlayPanel.qml @@ -65,6 +65,38 @@ Control { if(root.loginType == Constants.LoginType.Password) return "password" return root.loginType == Constants.LoginType.Biometrics ? "touch-id" : "keycard" } + + function filterPermissions(model) { + return !!model && (model.tokenCriteriaMet || !model.isPrivate) + } + + readonly property var communityPermissionsModel: SortFilterProxyModel { + sourceModel: root.communityHoldingsModel + filters: [ + ExpressionFilter { + expression: d.filterPermissions(model) + } + ] + } + + readonly property var viewOnlyPermissionsModel: SortFilterProxyModel { + sourceModel: root.viewOnlyHoldingsModel + filters: [ + ExpressionFilter { + expression: d.filterPermissions(model) + } + ] + } + + readonly property var viewAndPostPermissionsModel: SortFilterProxyModel { + sourceModel: root.viewAndPostHoldingsModel + filters: [ + ExpressionFilter { + expression: d.filterPermissions(model) + } + ] + } + } padding: 35 // default by design @@ -84,38 +116,46 @@ Control { } CustomHoldingsListPanel { - visible: root.joinCommunity && root.communityHoldingsModel - introText: qsTr("To join %1 you need to prove that you hold").arg(root.communityName) - model: root.communityHoldingsModel + id: communityRequirements + + visible: root.joinCommunity + introText: d.communityPermissionsModel.count > 0 ? + qsTr("To join %1 you need to prove that you hold").arg(root.communityName) : + qsTr("Sorry, you can't join %1 because it's a private, closed community").arg(root.communityName) + model: d.communityPermissionsModel } CustomHoldingsListPanel { - visible: !root.joinCommunity && !!root.viewOnlyHoldingsModel - introText: qsTr("To only view the %1 channel you need to hold").arg(root.channelName) - model: root.viewOnlyHoldingsModel + visible: !root.joinCommunity && d.viewOnlyPermissionsModel.count > 0 + introText: root.requiresRequest ? + qsTr("To view the #%1 channel you need to join %2 and prove that you hold").arg(root.channelName).arg(root.communityName) : + qsTr("To view the #%1 channel you need to hold").arg(root.channelName) + model: d.viewOnlyPermissionsModel } CustomHoldingsListPanel { - visible: !root.joinCommunity && !!root.viewAndPostHoldingsModel - introText: qsTr("To view and post in the %1 channel you need to hold").arg(root.channelName) - model: root.viewAndPostHoldingsModel + visible: !root.joinCommunity && d.viewAndPostPermissionsModel.count > 0 + introText: root.requiresRequest ? + qsTr("To view and post in the #%1 channel you need to join %2 and prove that you hold").arg(root.channelName).arg(root.communityName) : + qsTr("To view and post in the #%1 channel you need to hold").arg(root.channelName) + model: d.viewAndPostPermissionsModel } HoldingsListPanel { Layout.fillWidth: true spacing: root.spacing - visible: !root.joinCommunity && !!root.moderateHoldings + visible: !root.joinCommunity && !!d.moderateHoldings introText: qsTr("To moderate in the %1 channel you need to hold").arg(root.channelName) - model: root.moderateHoldingsModel + model: d.moderateHoldingsModel } StatusButton { Layout.alignment: Qt.AlignHCenter - visible: !root.showOnlyPanels && !root.isJoinRequestRejected + visible: !root.showOnlyPanels && !root.isJoinRequestRejected && root.requiresRequest text: root.isInvitationPending ? d.getInvitationPendingText() : d.getRevealAddressText() icon.name: root.isInvitationPending ? "" : d.getRevealAddressIcon() font.pixelSize: 13 - enabled: root.requirementsMet + enabled: root.requirementsMet || d.communityPermissionsModel.count == 0 onClicked: root.isInvitationPending ? root.invitationPendingClicked() : root.revealAddressClicked() } diff --git a/ui/app/AppLayouts/Chat/panels/communities/qmldir b/ui/app/AppLayouts/Chat/panels/communities/qmldir index 30153d6718..7a6b3cc576 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/qmldir +++ b/ui/app/AppLayouts/Chat/panels/communities/qmldir @@ -16,3 +16,5 @@ TokenHoldersPanel 1.0 TokenHoldersPanel.qml TokenHoldersProxyModel 1.0 TokenHoldersProxyModel.qml WarningPanel 1.0 WarningPanel.qml ChatPermissionQualificationPanel 1.0 ChatPermissionQualificationPanel.qml +JoinCommunityCenterPanel 1.0 JoinCommunityCenterPanel.qml +JoinCommunityHeaderPanel 1.0 JoinCommunityHeaderPanel.qml diff --git a/ui/app/AppLayouts/Chat/stores/PermissionsStore.qml b/ui/app/AppLayouts/Chat/stores/PermissionsStore.qml index e5fdc2cdde..f598c81cb4 100644 --- a/ui/app/AppLayouts/Chat/stores/PermissionsStore.qml +++ b/ui/app/AppLayouts/Chat/stores/PermissionsStore.qml @@ -1,14 +1,71 @@ import QtQml 2.15 +import SortFilterProxyModel 0.2 +import utils 1.0 + QtObject { id: root required property string activeSectionId + required property string activeChannelId required property var chatCommunitySectionModuleInst + // all permissions model readonly property var permissionsModel: chatCommunitySectionModuleInst.permissionsModel + readonly property var becomeMemberPermissionsModel: SortFilterProxyModel { + id: becomeMemberPermissionsModel + sourceModel: root.permissionsModel + function filterPredicate(modelData) { + return (modelData.permissionType == Constants.permissionType.member) && + (modelData.tokenCriteriaMet || !modelData.isPrivate) + } + filters: [ + ExpressionFilter { + expression: becomeMemberPermissionsModel.filterPredicate(model) + } + ] + } + + readonly property var viewOnlyPermissionsModel: SortFilterProxyModel { + id: viewOnlyPermissionsModel + sourceModel: root.permissionsModel + + function filterPredicate(modelData) { + return (modelData.permissionType == Constants.permissionType.read) && + root.permissionsModel.belongsToChat(modelData.id, root.activeChannelId) && + (modelData.tokenCriteriaMet || !modelData.isPrivate) + } + filters: [ + ExpressionFilter { + expression: { + root.activeChannelId // ensure predicate is re-triggered when activeChannelId changes + viewOnlyPermissionsModel.filterPredicate(model) + } + } + ] + } + + readonly property var viewAndPostPermissionsModel: SortFilterProxyModel { + id: viewAndPostPermissionsModel + sourceModel: root.permissionsModel + function filterPredicate(modelData) { + return (modelData.permissionType == Constants.permissionType.viewAndPost) && + root.permissionsModel.belongsToChat(modelData.id, root.activeChannelId) && + (modelData.tokenCriteriaMet || !modelData.isPrivate) + + } + filters: [ + ExpressionFilter { + expression: { + root.activeChannelId // ensure predicate is re-triggered when activeChannelId changes + viewAndPostPermissionsModel.filterPredicate(model) + } + } + ] + } + readonly property bool isOwner: false readonly property bool allTokenRequirementsMet: chatCommunitySectionModuleInst.allTokenRequirementsMet @@ -33,6 +90,7 @@ QtObject { root.activeSectionId, key, permissionType, JSON.stringify(holdings), + channels.map(c => c.key).join(","), isPrivate) } } diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index 9c2e890536..6bd628910f 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -16,6 +16,7 @@ QtObject { readonly property PermissionsStore permissionsStore: PermissionsStore { activeSectionId: mainModuleInst.activeSection.id + activeChannelId: root.currentChatContentModule().chatDetails.id chatCommunitySectionModuleInst: chatCommunitySectionModule } @@ -78,6 +79,8 @@ QtObject { signal communityInfoAlreadyRequested() + signal communityAccessRequested(string communityId) + signal goToMembershipRequestsPage() function setActiveCommunity(communityId) { @@ -621,6 +624,10 @@ QtObject { function onCommunityInfoAlreadyRequested() { root.communityInfoAlreadyRequested() } + + function onCommunityAccessRequested(communityId) { + root.communityAccessRequested(communityId) + } } readonly property Connections mainModuleInstConnections: Connections { diff --git a/ui/app/AppLayouts/Chat/views/ChatColumnView.qml b/ui/app/AppLayouts/Chat/views/ChatColumnView.qml index d9ca18d6a5..d96ef4461a 100644 --- a/ui/app/AppLayouts/Chat/views/ChatColumnView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatColumnView.qml @@ -44,10 +44,11 @@ Item { property int activeChatType: parentModule && parentModule.activeItem.type property bool stickersLoaded: false property bool viewAndPostPermissionsSatisfied: true - property var viewAndPostPermissionsModel + property var viewAndPostHoldingsModel readonly property var contactDetails: rootStore ? rootStore.oneToOneChatContact : null readonly property bool isUserAdded: !!root.contactDetails && root.contactDetails.isAdded + property bool amISectionAdmin: false signal openStickerPackPopup(string stickerPackId) @@ -267,8 +268,9 @@ Item { if (!channelPostRestrictions.visible) { if (d.activeChatContentModule.chatDetails.blocked) return qsTr("This user has been blocked.") - if (!root.rootStore.sectionDetails.joined || root.rootStore.sectionDetails.amIBanned) + if (!root.rootStore.sectionDetails.joined || root.rootStore.sectionDetails.amIBanned) { return qsTr("You need to join this community to send messages") + } if (!root.viewAndPostPermissionsSatisfied) { return qsTr("Sorry, you don't have the tokens needed to post in this channel.") } @@ -355,7 +357,7 @@ Item { height: chatInput.textInput.height anchors.left: parent.left anchors.leftMargin: (2*Style.current.bigPadding) - visible: (!!root.viewAndPostPermissionsModel && (root.viewAndPostPermissionsModel.count > 0) + visible: (!!root.viewAndPostHoldingsModel && (root.viewAndPostHoldingsModel.count > 0) && !root.amISectionAdmin) assetsModel: root.rootStore.assetsModel collectiblesModel: root.rootStore.collectiblesModel diff --git a/ui/app/AppLayouts/Chat/views/ChatView.qml b/ui/app/AppLayouts/Chat/views/ChatView.qml index 6e1cb62e44..4b4ad5c908 100644 --- a/ui/app/AppLayouts/Chat/views/ChatView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatView.qml @@ -35,11 +35,51 @@ StatusSectionLayout { property var stickersPopup property bool stickersLoaded: false + readonly property var chatContentModule: root.rootStore.currentChatContentModule() || null + readonly property bool viewOnlyPermissionsSatisfied: chatContentModule.viewOnlyPermissionsSatisfied + readonly property bool viewAndPostPermissionsSatisfied: chatContentModule.viewAndPostPermissionsSatisfied + property bool hasViewOnlyPermissions: false + property bool hasViewAndPostPermissions: false + property bool amIMember: false + property bool amISectionAdmin: false + + property bool isInvitationPending: false + + property var viewOnlyPermissionsModel + property var viewAndPostPermissionsModel + property var assetsModel + property var collectiblesModel + + readonly property bool contentLocked: { + if (!rootStore.chatCommunitySectionModule.isCommunity()) { + return false + } + if (!amIMember) { + return hasViewAndPostPermissions || hasViewOnlyPermissions + } + if (amISectionAdmin) { + return false + } + if (!hasViewAndPostPermissions && hasViewOnlyPermissions) { + return !viewOnlyPermissionsSatisfied + } + if (hasViewAndPostPermissions && !hasViewOnlyPermissions) { + return !viewAndPostPermissionsSatisfied + } + if (hasViewOnlyPermissions && hasViewAndPostPermissions) { + return !viewOnlyPermissionsSatisfied && !viewAndPostPermissionsSatisfied + } + return false + } + signal communityInfoButtonClicked() signal communityManageButtonClicked() signal profileButtonClicked() signal openAppSearch() + signal revealAddressClicked + signal invitationPendingClicked + Connections { target: root.rootStore.stickersStore.stickersModule @@ -61,12 +101,9 @@ StatusSectionLayout { notificationCount: activityCenterStore.unreadNotificationsCount hasUnseenNotifications: activityCenterStore.hasUnseenNotifications - headerContent: ChatHeaderContentView { - id: headerContent - visible: !!root.rootStore.currentChatContentModule() - rootStore: root.rootStore - emojiPopup: root.emojiPopup - onSearchButtonClicked: root.openAppSearch() + headerContent: Loader { + id: headerContentLoader + sourceComponent: root.contentLocked ? joinCommunityHeaderPanelComponent : chatHeaderContentViewComponent } leftPanel: Loader { @@ -76,22 +113,16 @@ StatusSectionLayout { contactsColumnComponent } - centerPanel: ChatColumnView { - id: chatColumn + centerPanel: Loader { anchors.fill: parent - parentModule: root.rootStore.chatCommunitySectionModule - rootStore: root.rootStore - createChatPropertiesStore: root.createChatPropertiesStore - contactsStore: root.contactsStore - stickersLoaded: root.stickersLoaded - emojiPopup: root.emojiPopup - stickersPopup: root.stickersPopup - onOpenStickerPackPopup: { - Global.openPopup(statusStickerPackClickPopup, {packId: stickerPackId, store: root.stickersPopup.store} ) - } + sourceComponent: root.contentLocked ? joinCommunityCenterPanelComponent : chatColumnViewComponent } showRightPanel: { + if (root.contentLocked) { + return false + } + if (root.rootStore.openCreateChat || !localAccountSensitiveSettings.showOnlineUsers || !localAccountSensitiveSettings.expandUsersList) { @@ -123,6 +154,67 @@ StatusSectionLayout { } } + Component { + id: chatHeaderContentViewComponent + ChatHeaderContentView { + visible: !!root.rootStore.currentChatContentModule() + rootStore: root.rootStore + emojiPopup: root.emojiPopup + onSearchButtonClicked: root.openAppSearch() + } + } + + Component { + id: joinCommunityHeaderPanelComponent + JoinCommunityHeaderPanel { + readonly property var chatContentModule: root.rootStore.currentChatContentModule() || null + joinCommunity: false + color: chatContentModule.chatDetails.color + channelName: chatContentModule.chatDetails.name + channelDesc: chatContentModule.chatDetails.description + } + } + + Component { + id: chatColumnViewComponent + + ChatColumnView { + parentModule: root.rootStore.chatCommunitySectionModule + rootStore: root.rootStore + createChatPropertiesStore: root.createChatPropertiesStore + contactsStore: root.contactsStore + stickersLoaded: root.stickersLoaded + emojiPopup: root.emojiPopup + stickersPopup: root.stickersPopup + viewAndPostHoldingsModel: root.viewAndPostPermissionsModel + viewAndPostPermissionsSatisfied: !root.rootStore.chatCommunitySectionModule.isCommunity() || root.amISectionAdmin || root.viewAndPostPermissionsSatisfied + amISectionAdmin: root.amISectionAdmin + onOpenStickerPackPopup: { + Global.openPopup(statusStickerPackClickPopup, {packId: stickerPackId, store: root.stickersPopup.store} ) + } + } + } + + Component { + id: joinCommunityCenterPanelComponent + + JoinCommunityCenterPanel { + joinCommunity: false + name: sectionItemModel.name + channelName: root.chatContentModule.chatDetails.name + viewOnlyHoldingsModel: root.viewOnlyPermissionsModel + viewAndPostHoldingsModel: root.viewAndPostPermissionsModel + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel + isInvitationPending: root.isInvitationPending + requiresRequest: !root.amIMember + requirementsMet: (viewOnlyPermissionsSatisfied && viewOnlyPermissionsModel.count > 0) || + (viewAndPostPermissionsSatisfied && viewAndPostPermissionsModel.count > 0) + onRevealAddressClicked: root.revealAddressClicked() + onInvitationPendingClicked: root.invitationPendingClicked() + } + } + Component { id: contactsColumnComponent ContactsColumnView { @@ -138,7 +230,9 @@ StatusSectionLayout { root.openAppSearch() } onAddRemoveGroupMemberClicked: { - headerContent.addRemoveGroupMember() + if (headerContentLoader.item && headerContentLoader.item instanceof ChatHeaderContentView) { + headerContentLoader.item.addRemoveGroupMember() + } } } } diff --git a/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml b/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml index ab877179df..8d23a9f929 100644 --- a/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml +++ b/ui/app/AppLayouts/Chat/views/communities/CommunityNewPermissionView.qml @@ -29,10 +29,6 @@ StatusScrollView { property int viewWidth: 560 // by design property bool isEditState: false - // TODO: temporary property, to be removed when no need to hide the switch - // in the app - property bool showWhoHoldsSwitch: false - readonly property bool dirty: root.holdingsRequired !== d.dirtyValues.holdingsRequired || (d.dirtyValues.holdingsRequired && !holdingsModelComparator.equal) || @@ -221,8 +217,6 @@ StatusScrollView { children: StatusSwitch { id: whoHoldsSwitch - visible: root.showWhoHoldsSwitch - padding: 0 anchors.right: parent.right anchors.top: parent.top diff --git a/ui/app/AppLayouts/Chat/views/communities/JoinCommunityView.qml b/ui/app/AppLayouts/Chat/views/communities/JoinCommunityView.qml index 7bc602c075..9c0beed7e1 100644 --- a/ui/app/AppLayouts/Chat/views/communities/JoinCommunityView.qml +++ b/ui/app/AppLayouts/Chat/views/communities/JoinCommunityView.qml @@ -36,7 +36,7 @@ StatusSectionLayout { property bool requirementsMet: true property bool isJoinRequestRejected: false property bool requiresRequest: false - property alias loginType: overlayPanel.loginType + property alias loginType: joinCommunityCenterPanel.loginType property var communityHoldingsModel property var viewOnlyHoldingsModel @@ -57,12 +57,7 @@ StatusSectionLayout { signal adHocChatButtonClicked signal revealAddressClicked signal invitationPendingClicked - signal joined - signal cancelMembershipRequest - function openJoinCommunityDialog() { - joinCommunityDialog.open() - } QtObject { id: d @@ -70,50 +65,13 @@ StatusSectionLayout { readonly property int blurryRadius: 32 } - // Blur background: - headerContent: RowLayout { - anchors.fill: parent - spacing: 30 - - StatusChatInfoButton { - id: headerInfoButton - Layout.preferredHeight: parent.height - Layout.minimumWidth: 100 - Layout.fillWidth: true - title: root.joinCommunity ? root.name : root.channelName - subTitle: root.joinCommunity ? root.communityDesc : root.channelDesc - asset.color: root.color - enabled: false - type: StatusChatInfoButton.Type.CommunityChat - layer.enabled: root.joinCommunity // Blured when joining community but not when entering channel - layer.effect: fastBlur - } - - RowLayout { - Layout.preferredHeight: parent.height - spacing: 10 - layer.enabled: true - layer.effect: fastBlur - - StatusFlatRoundButton { - id: search - icon.name: "search" - type: StatusFlatRoundButton.Type.Secondary - enabled: false - } - - StatusFlatRoundButton { - icon.name: "group-chat" - type: StatusFlatRoundButton.Type.Secondary - enabled: false - } - - StatusFlatRoundButton { - icon.name: "more" - type: StatusFlatRoundButton.Type.Secondary - enabled: false - } - } + headerContent: JoinCommunityHeaderPanel { + joinCommunity: root.joinCommunity + color: root.color + name: root.name + channelName: root.channelName + communityDesc: root.communityDesc + channelDesc: root.channelDesc } // Blur background: @@ -135,7 +93,7 @@ StatusSectionLayout { ColumnLayout { Layout.fillWidth: true Layout.margins: Style.current.halfPadding - layer.enabled: true + layer.enabled: root.joinCommunity layer.effect: fastBlur Repeater { @@ -160,127 +118,36 @@ StatusSectionLayout { } // Blur background + Permissions base information content: - centerPanel: ColumnLayout { + centerPanel: JoinCommunityCenterPanel { + id: joinCommunityCenterPanel + anchors.fill: parent - spacing: 0 - // Blur background: - Item { - Layout.fillWidth: true - Layout.preferredHeight: Math.min(centralPanelData.implicitHeight, parent.height - overlayPanel.implicitHeight) + joinCommunity: root.joinCommunity // Otherwise it means join channel action - ColumnLayout { - id: centralPanelData - width: parent.width - layer.enabled: true - layer.effect: fastBlur + name: root.name + channelName: root.channelName - StatusBaseText { - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 30 - Layout.bottomMargin: 30 - text: root.chatDateTimeText - font.pixelSize: 13 - color: Theme.palette.baseColor1 - } + isInvitationPending: root.isInvitationPending + isJoinRequestRejected: root.isJoinRequestRejected + requiresRequest: root.requiresRequest + requirementsMet: root.requirementsMet - RowLayout { - Layout.alignment: Qt.AlignHCenter + communityHoldingsModel: root.communityHoldingsModel + viewOnlyHoldingsModel: root.viewOnlyHoldingsModel + viewAndPostHoldingsModel: root.viewAndPostHoldingsModel + moderateHoldingsModel: root.moderateHoldingsModel + assetsModel: root.assetsModel + collectiblesModel: root.collectiblesModel - StatusBaseText { - text: root.listUsersText - font.pixelSize: 13 - } + chatDateTimeText: root.chatDateTimeText + listUsersText: root.listUsersText + messagesModel: root.messagesModel - StatusBaseText { - text: qsTr("joined the channel") - font.pixelSize: 13 - color: Theme.palette.baseColor1 - } - } - - ListView { - Layout.fillWidth: true - Layout.preferredHeight: childrenRect.height + spacing - Layout.topMargin: 16 - spacing: 16 - model: root.messagesModel - delegate: StatusMessage { - width: ListView.view.width - timestamp: model.timestamp - enabled: false - messageDetails: StatusMessageDetails { - messageText: model.message - contentType: model.contentType - sender.displayName: model.senderDisplayName - sender.isContact: model.isContact - sender.trustIndicator: model.trustIndicator - sender.profileImage: StatusProfileImageSettings { - width: 40 - height: 40 - name: model.profileImage || "" - colorId: model.colorId - } - } - } - } - } - } - - // Permissions base information content: - Rectangle { - id: panelBase - - Layout.fillWidth: true - Layout.fillHeight: true - color: Theme.palette.statusAppLayout.rightPanelBackgroundColor - gradient: Gradient { - GradientStop { - position: 0.000 - color: "transparent" - } - GradientStop { - position: 0.180 - color: panelBase.color - } - } - - StatusScrollView { - anchors.fill: parent - padding: 0 - - Item { - implicitHeight: Math.max(overlayPanel.implicitHeight, panelBase.height) - implicitWidth: Math.max(overlayPanel.implicitWidth, panelBase.width) - - JoinPermissionsOverlayPanel { - id: overlayPanel - - anchors.centerIn: parent - - topPadding: 2 * bottomPadding - joinCommunity: root.joinCommunity - requirementsMet: root.requirementsMet - isInvitationPending: root.isInvitationPending - isJoinRequestRejected: root.isJoinRequestRejected - requiresRequest: root.requiresRequest - communityName: root.name - communityHoldingsModel: root.communityHoldingsModel - channelName: root.channelName - - viewOnlyHoldingsModel: root.viewOnlyHoldingsModel - viewAndPostHoldingsModel: root.viewAndPostHoldingsModel - moderateHoldingsModel: root.moderateHoldingsModel - assetsModel: root.assetsModel - collectiblesModel: root.collectiblesModel - - onRevealAddressClicked: root.revealAddressClicked() - onInvitationPendingClicked: root.invitationPendingClicked() - } - } - } - } + onRevealAddressClicked: root.revealAddressClicked() + onInvitationPendingClicked: root.invitationPendingClicked() } + showRightPanel: false Component { @@ -291,17 +158,4 @@ StatusSectionLayout { transparentBorder: true } } - - CommunityIntroDialog { - id: joinCommunityDialog - - name: root.name - introMessage: root.introMessage - imageSrc: root.image - accessType: root.accessType - isInvitationPending: root.isInvitationPending - - onJoined: root.joined() - onCancelMembershipRequest: root.cancelMembershipRequest() - } } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 0c296123dd..613864bf92 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -404,6 +404,14 @@ QtObject { readonly property int admin: 4 } + readonly property QtObject permissionType: QtObject{ + readonly property int none: 0 + readonly property int admin: 1 + readonly property int member: 2 + readonly property int read: 3 + readonly property int viewAndPost: 4 + } + readonly property QtObject messageContentType: QtObject { readonly property int newMessagesMarker: -3 readonly property int fetchMoreMessagesButton: -2 diff --git a/vendor/status-go b/vendor/status-go index a46bf97bf3..bf64f97d5a 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit a46bf97bf3f46b07d1f447732947011e20fa499f +Subproject commit bf64f97d5a2bcb1b5fb6b134dda69994e0ddd2bb