From b08eb128ad3c8d596fe77d813f666e5d1e7a8781 Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Fri, 28 Jun 2024 18:29:18 +0200 Subject: [PATCH] feat(communities): inform about missing encryption key closes: #15064 --- .../chat_section/chat_content/chat_details.nim | 14 ++++++++++++++ .../main/chat_section/chat_content/module.nim | 4 +++- src/app/modules/main/chat_section/item.nim | 9 +++++++++ src/app/modules/main/chat_section/model.nim | 17 ++++++++++++++++- src/app/modules/main/chat_section/module.nim | 10 +++++++++- src/app_service/service/chat/dto/chat.nim | 6 +++++- src/app_service/service/community/service.nim | 4 +++- ui/app/AppLayouts/Chat/views/ChatView.qml | 7 +++++-- ...sCheckPendingLoader.qml => BlinkingText.qml} | 2 -- .../panels/JoinCommunityCenterPanel.qml | 2 ++ .../panels/JoinPermissionsOverlayPanel.qml | 11 ++++++++--- ui/app/AppLayouts/Communities/panels/qmldir | 2 +- 12 files changed, 75 insertions(+), 13 deletions(-) rename ui/app/AppLayouts/Communities/panels/{RequirementsCheckPendingLoader.qml => BlinkingText.qml} (90%) diff --git a/src/app/modules/main/chat_section/chat_content/chat_details.nim b/src/app/modules/main/chat_section/chat_content/chat_details.nim index 2cd26ce380..18bfc5aa8e 100644 --- a/src/app/modules/main/chat_section/chat_content/chat_details.nim +++ b/src/app/modules/main/chat_section/chat_content/chat_details.nim @@ -27,6 +27,7 @@ QtObject: canView: bool canPostReactions: bool hideIfPermissionsNotMet: bool + missingEncryptionKey: bool proc delete*(self: ChatDetails) = self.QObject.delete @@ -56,6 +57,7 @@ QtObject: canView: bool = true, canPostReactions: bool = true, hideIfPermissionsNotMet: bool, + missingEncryptionKey: bool, ) = self.id = id self.`type` = `type` @@ -79,6 +81,7 @@ QtObject: self.canView = canView self.canPostReactions = canPostReactions self.hideIfPermissionsNotMet = hideIfPermissionsNotMet + self.missingEncryptionKey = missingEncryptionKey proc getId(self: ChatDetails): string {.slot.} = return self.id @@ -297,3 +300,14 @@ QtObject: proc setHideIfPermissionsNotMet*(self: ChatDetails, value: bool) = self.hideIfPermissionsNotMet = value self.hideIfPermissionsNotMetChanged() + + proc missingEncryptionKeyChanged(self: ChatDetails) {.signal.} + proc getMissingEncryptionKey(self: ChatDetails): bool {.slot.} = + return self.missingEncryptionKey + QtProperty[bool] missingEncryptionKey: + read = getMissingEncryptionKey + notify = missingEncryptionKeyChanged + + proc setMissingEncryptionKey*(self: ChatDetails, value: bool) = + self.missingEncryptionKey = value + self.missingEncryptionKeyChanged() 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 4c3089cb61..98a30a564f 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -97,7 +97,7 @@ method load*(self: Module, chatItem: chat_item.Item) = chatItem.color, chatItem.description, chatItem.emoji, chatItem.hasUnreadMessages, chatItem.notificationsCount, chatItem.highlight, chatItem.muted, chatItem.position, isUntrustworthy = trustStatus == TrustStatus.Untrustworthy, isContact, chatItem.blocked, chatItem.canPost, chatItem.canView, chatItem.canPostReactions, - chatItem.hideIfPermissionsNotMet) + chatItem.hideIfPermissionsNotMet, chatItem.missingEncryptionKey) self.view.chatDetailsChanged() @@ -382,6 +382,7 @@ method onChatUpdated*(self: Module, chatItem: chat_item.Item) = self.view.chatDetails.setCanView(chatItem.canView) self.view.chatDetails.setCanPostReactions(chatItem.canPostReactions) self.view.chatDetails.setHideIfPermissionsNotMet(chat_item.hideIfPermissionsNotMet) + self.view.chatDetails.setMissingEncryptionKey(chat_item.missingEncryptionKey) self.messagesModule.updateChatFetchMoreMessages() self.messagesModule.updateChatIdentifier() @@ -398,6 +399,7 @@ method onCommunityChannelEdited*(self: Module, chatDto: ChatDto) = self.view.chatDetails.setHideIfPermissionsNotMet(chatDto.hideIfPermissionsNotMet) self.view.chatDetails.setName(chatDto.name) self.view.chatDetails.setIcon(chatDto.icon) + self.view.chatDetails.setMissingEncryptionKey(chatDto.missingEncryptionKey) self.messagesModule.updateChatFetchMoreMessages() self.messagesModule.updateChatIdentifier() diff --git a/src/app/modules/main/chat_section/item.nim b/src/app/modules/main/chat_section/item.nim index db1b17cd2e..75b02bc3cf 100644 --- a/src/app/modules/main/chat_section/item.nim +++ b/src/app/modules/main/chat_section/item.nim @@ -40,6 +40,7 @@ type canView: bool viewersCanPostReactions: bool hideIfPermissionsNotMet: bool + missingEncryptionKey: bool proc initItem*( id, @@ -73,6 +74,7 @@ proc initItem*( canPostReactions = true, viewersCanPostReactions = true, hideIfPermissionsNotMet: bool, + missingEncryptionKey: bool ): Item = result = Item() result.id = id @@ -107,6 +109,7 @@ proc initItem*( result.canPostReactions = canPostReactions result.viewersCanPostReactions = viewersCanPostReactions result.hideIfPermissionsNotMet = hideIfPermissionsNotMet + result.missingEncryptionKey = missingEncryptionKey proc `$`*(self: Item): string = result = fmt"""chat_section/Item( @@ -358,3 +361,9 @@ proc `viewersCanPostReactions=`*(self: Item, value: bool) = proc hideBecausePermissionsAreNotMet*(self: Item): bool = self.hideIfPermissionsNotMet and not self.canPost and not self.canView + +proc missingEncryptionKey*(self: Item): bool = + self.missingEncryptionKey + +proc `missingEncryptionKey=`*(self: var Item, value: bool) = + self.missingEncryptionKey = value diff --git a/src/app/modules/main/chat_section/model.nim b/src/app/modules/main/chat_section/model.nim index 9aefe0053c..2058461fa6 100644 --- a/src/app/modules/main/chat_section/model.nim +++ b/src/app/modules/main/chat_section/model.nim @@ -42,6 +42,7 @@ type HideIfPermissionsNotMet ShouldBeHiddenBecausePermissionsAreNotMet #this is a complex role which depends on other roles #(MemberRole , HideIfPermissionsNotMet, canPost and canView) + MissingEncryptionKey QtObject: type @@ -143,7 +144,8 @@ QtObject: ModelRole.CanView.int:"canView", ModelRole.CanPostReactions.int:"canPostReactions", ModelRole.ViewersCanPostReactions.int:"viewersCanPostReactions", - ModelRole.ShouldBeHiddenBecausePermissionsAreNotMet.int:"shouldBeHiddenBecausePermissionsAreNotMet" + ModelRole.ShouldBeHiddenBecausePermissionsAreNotMet.int:"shouldBeHiddenBecausePermissionsAreNotMet", + ModelRole.MissingEncryptionKey.int:"missingEncryptionKey", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -223,6 +225,8 @@ QtObject: result = newQVariant(item.hideIfPermissionsNotMet) of ModelRole.ShouldBeHiddenBecausePermissionsAreNotMet: return newQVariant(self.itemShouldBeHiddenBecauseNotPermitted(item)) + of ModelRole.MissingEncryptionKey: + return newQVariant(item.missingEncryptionKey) proc getItemIdxById(items: seq[Item], id: string): int = var idx = 0 @@ -724,3 +728,14 @@ QtObject: let modelIndex = self.createIndex(index, 0, nil) defer: modelIndex.delete self.dataChanged(modelIndex, modelIndex, @[ModelRole.Active.int, ModelRole.LoaderActive.int]) + + proc updateMissingEncryptionKey*(self: Model, id: string, missingEncryptionKey: bool) = + let index = self.getItemIdxById(id) + if index == -1: + return + + if self.items[index].missingEncryptionKey != missingEncryptionKey: + self.items[index].missingEncryptionKey = missingEncryptionKey + let modelIndex = self.createIndex(index, 0, nil) + defer: modelIndex.delete + self.dataChanged(modelIndex, modelIndex, @[ModelRole.MissingEncryptionKey.int]) diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 3bbf1aedd4..19aff6eb25 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -275,6 +275,7 @@ proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, c category.id, category.position, hideIfPermissionsNotMet = false, + missingEncryptionKey = false, ) if insertIntoModel: @@ -530,7 +531,7 @@ method activeItemSet*(self: Module, itemId: string) = if self.controller.isCommunity(): let community = self.controller.getMyCommunity() if not community.isPrivilegedUser: - if not chat_item.canView or not chat_item.canPost: + if not chat_item.missingEncryptionKey and (not chat_item.canView or not chat_item.canPost): # User doesn't have full access to this channel. Check permissions to know what is missing self.controller.asyncCheckChannelPermissions(mySectionId, activeChatId) @@ -699,6 +700,7 @@ proc getChatItemFromChatDto( var canPostReactions = true var hideIfPermissionsNotMet = false var viewersCanPostReactions = true + var missingEncryptionKey = false if self.controller.isCommunity: let communityChat = community.getCommunityChat(chatDto.id) # NOTE: workaround for new community chat, which is delivered in chatDto before the community will know about that @@ -710,12 +712,14 @@ proc getChatItemFromChatDto( canPostReactions = communityChat.canPostReactions hideIfPermissionsNotMet = communityChat.hideIfPermissionsNotMet viewersCanPostReactions = communityChat.viewersCanPostReactions + missingEncryptionKey = communityChat.missingEncryptionKey else: canPost = chatDto.canPost canView = chatDto.canView canPostReactions = chatDto.canPostReactions hideIfPermissionsNotMet = chatDto.hideIfPermissionsNotMet viewersCanPostReactions = chatDto.viewersCanPostReactions + missingEncryptionKey = chatDto.missingEncryptionKey result = chat_item.initItem( chatDto.id, @@ -754,6 +758,7 @@ proc getChatItemFromChatDto( canPostReactions = canPostReactions, viewersCanPostReactions = viewersCanPostReactions, hideIfPermissionsNotMet = hideIfPermissionsNotMet, + missingEncryptionKey = missingEncryptionKey ) proc addNewChat( @@ -1386,6 +1391,7 @@ method prepareEditCategoryModel*(self: Module, categoryId: string) = c.position, categoryId="", hideIfPermissionsNotMet=false, + missingEncryptionKey=false, ) self.view.editCategoryChannelsModel().appendItem(chatItem) let catChats = self.controller.getChats(communityId, categoryId) @@ -1409,6 +1415,7 @@ method prepareEditCategoryModel*(self: Module, categoryId: string) = c.position, categoryId, hideIfPermissionsNotMet=false, + missingEncryptionKey=false, ) self.view.editCategoryChannelsModel().appendItem(chatItem, ignoreCategory = true) @@ -1473,6 +1480,7 @@ method addOrUpdateChat(self: Module, self.changeCanPostValues(chat.id, result.canPost, result.canView, result.canPostReactions, result.viewersCanPostReactions) self.updatePermissionsRequiredOnChat(chat.id) self.updateChatLocked(chat.id) + self.view.chatsModel().updateMissingEncryptionKey(chat.id, result.missingEncryptionKey) if (chat.chatType == ChatType.PrivateGroupChat): self.onGroupChatDetailsUpdated(chat.id, chat.name, chat.color, chat.icon) elif (chat.chatType != ChatType.OneToOne): diff --git a/src/app_service/service/chat/dto/chat.nim b/src/app_service/service/chat/dto/chat.nim index ed3cbe1048..0b988ebce2 100644 --- a/src/app_service/service/chat/dto/chat.nim +++ b/src/app_service/service/chat/dto/chat.nim @@ -95,6 +95,7 @@ type ChatDto* = object permissions*: Permission hideIfPermissionsNotMet*: bool tokenGated*: bool + missingEncryptionKey*: bool type ClearedHistoryDto* = object chatId*: string @@ -130,7 +131,9 @@ proc `$`*(self: ChatDto): string = categoryId: {self.categoryId}, position: {self.position}, highlight: {self.highlight}, - hideIfPermissionsNotMet: {self.hideIfPermissionsNotMet} + hideIfPermissionsNotMet: {self.hideIfPermissionsNotMet}, + tokenGated: {self.tokenGated}, + missingEncryptionKey: {self.missingEncryptionKey} )""" proc toCheckPermissionsResultDto*(jsonObj: JsonNode): CheckPermissionsResultDto = @@ -264,6 +267,7 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto = discard jsonObj.getProp("categoryID", result.categoryId) discard jsonObj.getProp("hideIfPermissionsNotMet", result.hideIfPermissionsNotMet) discard jsonObj.getProp("tokenGated", result.tokenGated) + discard jsonObj.getProp("missingEncryptionKey", result.missingEncryptionKey) discard jsonObj.getProp("position", result.position) discard jsonObj.getProp("communityId", result.communityId) discard jsonObj.getProp("profile", result.profile) diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 2cd0eb590b..a63c50dc7a 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -649,7 +649,9 @@ QtObject: chat.viewersCanPostReactions != prevChat.viewersCanPostReactions or chat.canPost != prevChat.canPost or chat.canView != prevChat.canView or - chat.hideIfPermissionsNotMet != prevChat.hideIfPermissionsNotMet: + chat.hideIfPermissionsNotMet != prevChat.hideIfPermissionsNotMet or + chat.tokenGated != prevChat.tokenGated or + chat.missingEncryptionKey != prevChat.missingEncryptionKey: var updatedChat = chat self.chatService.updateOrAddChat(updatedChat) # we have to update chats stored in the chat service. diff --git a/ui/app/AppLayouts/Chat/views/ChatView.qml b/ui/app/AppLayouts/Chat/views/ChatView.qml index a24961dc4c..747582e330 100644 --- a/ui/app/AppLayouts/Chat/views/ChatView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatView.qml @@ -51,6 +51,7 @@ StatusSectionLayout { readonly property var chatContentModule: rootStore.currentChatContentModule() || null readonly property bool canView: chatContentModule.chatDetails.canView readonly property bool canPost: chatContentModule.chatDetails.canPost + readonly property bool missingEncryptionKey: chatContentModule.chatDetails.missingEncryptionKey property bool hasViewOnlyPermissions: false property bool hasUnrestrictedViewOnlyPermission: false @@ -243,9 +244,11 @@ StatusSectionLayout { collectiblesModel: root.collectiblesModel requestToJoinState: root.requestToJoinState requiresRequest: !root.amIMember - requirementsMet: (canView && viewOnlyPermissionsModel.count > 0) || - (canPost && viewAndPostPermissionsModel.count > 0) + requirementsMet: root.missingEncryptionKey || + (root.canView && viewOnlyPermissionsModel.count > 0) || + (root.canPost && viewAndPostPermissionsModel.count > 0) requirementsCheckPending: root.chatContentModule.permissionsCheckOngoing + missingEncryptionKey: root.missingEncryptionKey onRequestToJoinClicked: root.requestToJoinClicked() onInvitationPendingClicked: root.invitationPendingClicked() } diff --git a/ui/app/AppLayouts/Communities/panels/RequirementsCheckPendingLoader.qml b/ui/app/AppLayouts/Communities/panels/BlinkingText.qml similarity index 90% rename from ui/app/AppLayouts/Communities/panels/RequirementsCheckPendingLoader.qml rename to ui/app/AppLayouts/Communities/panels/BlinkingText.qml index b5d1dbe8ea..4d87f76cf8 100644 --- a/ui/app/AppLayouts/Communities/panels/RequirementsCheckPendingLoader.qml +++ b/ui/app/AppLayouts/Communities/panels/BlinkingText.qml @@ -7,8 +7,6 @@ import StatusQ.Core.Theme 0.1 StatusBaseText { id: root - text: qsTr("Requirements check pending...") - color: Theme.palette.dangerColor1 SequentialAnimation { diff --git a/ui/app/AppLayouts/Communities/panels/JoinCommunityCenterPanel.qml b/ui/app/AppLayouts/Communities/panels/JoinCommunityCenterPanel.qml index 2a81d6151c..b17c4c3d07 100644 --- a/ui/app/AppLayouts/Communities/panels/JoinCommunityCenterPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/JoinCommunityCenterPanel.qml @@ -25,6 +25,7 @@ ColumnLayout { property bool requirementsMet: true property bool requirementsCheckPending: false + property bool missingEncryptionKey: false property var communityHoldingsModel property var viewOnlyHoldingsModel @@ -145,6 +146,7 @@ ColumnLayout { allChannelsAreHiddenBecauseNotPermitted: root.allChannelsAreHiddenBecauseNotPermitted requirementsMet: root.requirementsMet requirementsCheckPending: root.requirementsCheckPending + missingEncryptionKey: root.missingEncryptionKey requestToJoinState: root.requestToJoinState isJoinRequestRejected: root.isJoinRequestRejected requiresRequest: root.requiresRequest diff --git a/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml b/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml index 480bb4c56d..535e6b19a4 100644 --- a/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/JoinPermissionsOverlayPanel.qml @@ -25,6 +25,7 @@ Control { property bool requiresRequest: false property int requestToJoinState: Constants.RequestToJoinState.None property bool isInvitationPending: root.requestToJoinState !== Constants.RequestToJoinState.None + property bool missingEncryptionKey: false property bool isJoinRequestRejected: false property string communityName @@ -50,7 +51,9 @@ Control { readonly property string channelRequirementsNotMetText: qsTr("Channel requirements not met") readonly property string channelMembershipRequestPendingText: qsTr("Channel Membership Request Pending...") readonly property string membershipRequestRejectedText: qsTr("Membership Request Rejected") - readonly property string allChannelsAreHiddenBecauseNotPermittedText: qsTr("Sorry, you don't hodl the necessary tokens to view or post in any of %1 channels").arg(root.communityName) + readonly property string allChannelsAreHiddenBecauseNotPermittedText: qsTr("Sorry, you don't hold the necessary tokens to view or post in any of %1 channels").arg(root.communityName) + readonly property string requirementsCheckPendingText: qsTr("Requirements check pending...") + readonly property string missingEncryptionKeyText: qsTr("Encryption key has not arrived yet...") readonly property bool onlyPrivateNotMetPermissions: (d.visiblePermissionsModel.count === 0) && root.communityHoldingsModel.count > 0 @@ -174,6 +177,7 @@ Control { Layout.alignment: Qt.AlignHCenter visible: !root.showOnlyPanels && !root.requirementsCheckPending + && !root.missingEncryptionKey && (root.isJoinRequestRejected || !root.requirementsMet) && !d.onlyPrivateNotMetPermissions && !root.allChannelsAreHiddenBecauseNotPermitted @@ -182,9 +186,10 @@ Control { color: Theme.palette.dangerColor1 } - RequirementsCheckPendingLoader { - visible: root.requirementsCheckPending + BlinkingText { Layout.alignment: Qt.AlignHCenter + visible: root.requirementsCheckPending || root.missingEncryptionKey + text: root.missingEncryptionKey ? d.missingEncryptionKeyText : d.requirementsCheckPendingText } } } diff --git a/ui/app/AppLayouts/Communities/panels/qmldir b/ui/app/AppLayouts/Communities/panels/qmldir index 83d3406003..f4f7c10d6a 100644 --- a/ui/app/AppLayouts/Communities/panels/qmldir +++ b/ui/app/AppLayouts/Communities/panels/qmldir @@ -1,6 +1,7 @@ AirdropsSettingsPanel 1.0 AirdropsSettingsPanel.qml BackUpCommuntyBannerPanel 1.0 BackUpCommuntyBannerPanel.qml BannerPanel 1.0 BannerPanel.qml +BlinkingText 1.0 BlinkingText.qml ChannelsAndCategoriesBannerPanel 1.0 ChannelsAndCategoriesBannerPanel.qml ChatPermissionQualificationPanel 1.0 ChatPermissionQualificationPanel.qml ColorPanel 1.0 ColorPanel.qml @@ -28,7 +29,6 @@ PrivilegedTokenArtworkPanel 1.0 PrivilegedTokenArtworkPanel.qml ProfilePopupInviteFriendsPanel 1.0 ProfilePopupInviteFriendsPanel.qml ProfilePopupInviteMessagePanel 1.0 ProfilePopupInviteMessagePanel.qml ProfilePopupOverviewPanel 1.0 ProfilePopupOverviewPanel.qml -RequirementsCheckPendingLoader 1.0 RequirementsCheckPendingLoader.qml SharedAddressesAccountSelector 1.0 SharedAddressesAccountSelector.qml SharedAddressesPanel 1.0 SharedAddressesPanel.qml SharedAddressesSigningPanel 1.0 SharedAddressesSigningPanel.qml