From 634591b69f58e0e9a9b2955dd195b53df72fee50 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Wed, 13 Mar 2024 15:13:41 -0400 Subject: [PATCH] feat: hook reactions in read only channel and fix issues (#13913) * feat: hook reactions in read only channel and fix issues Fixes #13523 * fix crash and missing emoji popup on group chats * code review fixes --- .../chat_content/chat_details.nim | 36 +++++++++++++++-- .../main/chat_section/chat_content/module.nim | 2 +- .../main/chat_section/chat_content/view.nim | 5 ++- .../modules/main/chat_section/controller.nim | 14 +++++-- .../main/chat_section/io_interface.nim | 4 +- src/app/modules/main/chat_section/item.nim | 26 +++++++++++- src/app/modules/main/chat_section/model.nim | 25 ++++++++++++ src/app/modules/main/chat_section/module.nim | 17 ++++++-- src/app/modules/main/chat_section/view.nim | 11 +++-- src/app_service/service/chat/dto/chat.nim | 17 ++++++-- src/app_service/service/chat/service.nim | 10 +++-- src/app_service/service/community/service.nim | 40 ++++++++++++------- src/backend/communities.nim | 12 ++++-- ui/app/AppLayouts/Chat/stores/RootStore.qml | 9 +++-- .../Communities/popups/CreateChannelPopup.qml | 15 +++---- .../Communities/views/CommunityColumnView.qml | 10 ++--- .../Communities/views/PermissionsView.qml | 5 +-- ui/imports/shared/stores/PermissionsStore.qml | 4 -- .../shared/views/chat/ChatContextMenuView.qml | 3 +- .../views/chat/MessageContextMenuView.qml | 3 +- ui/imports/shared/views/chat/MessageView.qml | 9 +++-- 21 files changed, 197 insertions(+), 80 deletions(-) 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 0fd12a77b8..75e21fa912 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 @@ -23,6 +23,7 @@ QtObject: isContact: bool active: bool blocked: bool + canPostReactions: bool proc delete*(self: ChatDetails) = self.QObject.delete @@ -31,10 +32,25 @@ QtObject: new(result, delete) result.QObject.setup - proc setChatDetails*(self: ChatDetails, id: string, `type`: int, belongsToCommunity, - isUsersListAvailable: bool, name, icon: string, color, description, - emoji: string, hasUnreadMessages: bool, notificationsCount: int, highlight, muted: bool, position: int, - isUntrustworthy: bool, isContact: bool = false, blocked: bool = false) = + proc setChatDetails*( + self: ChatDetails, + id: string, + `type`: int, + belongsToCommunity, + isUsersListAvailable: bool, + name, + icon:string, + color, description, + emoji: string, + hasUnreadMessages: bool, + notificationsCount: int, + highlight, muted: bool, + position: int, + isUntrustworthy: bool, + isContact: bool = false, + blocked: bool = false, + canPostReactions: bool = true, + ) = self.id = id self.`type` = `type` self.belongsToCommunity = belongsToCommunity @@ -53,6 +69,7 @@ QtObject: self.isContact = isContact self.active = false self.blocked = blocked + self.canPostReactions = canPostReactions proc getId(self: ChatDetails): string {.slot.} = return self.id @@ -227,3 +244,14 @@ QtObject: proc setBlocked*(self: ChatDetails, value: bool) = self.blocked = value self.blockedChanged() + + proc canPostReactionsChanged(self: ChatDetails) {.signal.} + proc getCanPostReactions(self: ChatDetails): bool {.slot.} = + return self.canPostReactions + QtProperty[bool] canPostReactions: + read = getCanPostReactions + notify = canPostReactionsChanged + + proc setCanPostReactions*(self: ChatDetails, value: bool) = + self.canPostReactions = value + self.canPostReactionsChanged() 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 ba74bedc2d..e45917712c 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -95,7 +95,7 @@ method load*(self: Module, chatItem: chat_item.Item) = self.controller.isUsersListAvailable(), chatName, chatImage, chatItem.color, chatItem.description, chatItem.emoji, chatItem.hasUnreadMessages, chatItem.notificationsCount, chatItem.highlight, chatItem.muted, chatItem.position, isUntrustworthy = trustStatus == TrustStatus.Untrustworthy, - isContact, chatItem.blocked) + isContact, chatItem.blocked, chatItem.canPostReactions) self.inputAreaModule.load() self.messagesModule.load() 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 b4b349ec0b..4238e6a4e8 100644 --- a/src/app/modules/main/chat_section/chat_content/view.nim +++ b/src/app/modules/main/chat_section/chat_content/view.nim @@ -40,10 +40,10 @@ QtObject: proc load*(self: View, id: string, `type`: int, belongsToCommunity, isUsersListAvailable: bool, name, icon: string, color, description, emoji: string, hasUnreadMessages: bool, notificationsCount: int, highlight, muted: bool, position: int, isUntrustworthy: bool, - isContact: bool, blocked: bool) = + isContact: bool, blocked: bool, canPostReactions: bool) = self.chatDetails.setChatDetails(id, `type`, belongsToCommunity, isUsersListAvailable, name, icon, color, description, emoji, hasUnreadMessages, notificationsCount, highlight, muted, position, - isUntrustworthy, isContact, blocked) + isUntrustworthy, isContact, blocked, canPostReactions) self.delegate.viewDidLoad() self.chatDetailsChanged() @@ -149,6 +149,7 @@ QtObject: self.chatDetails.setEmoji(chatDto.emoji) self.chatDetails.setColor(chatDto.color) self.chatDetails.setMuted(chatDto.muted) + self.chatDetails.setCanPostReactions(chatDto.canPostReactions) proc updateChatDetailsName*(self: View, name: string) = self.chatDetails.setName(name) diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index 478cf2efb4..ed52f86a49 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -564,9 +564,11 @@ proc createCommunityChannel*( description: string, emoji: string, color: string, - categoryId: string) = + categoryId: string, + viewersCanPostReactions: bool, + ) = self.communityService.createCommunityChannel(self.sectionId, name, description, emoji, color, - categoryId) + categoryId, viewersCanPostReactions) proc editCommunityChannel*( self: Controller, @@ -576,7 +578,9 @@ proc editCommunityChannel*( emoji: string, color: string, categoryId: string, - position: int) = + position: int, + viewersCanPostReactions: bool, + ) = self.communityService.editCommunityChannel( self.sectionId, channelId, @@ -585,7 +589,9 @@ proc editCommunityChannel*( emoji, color, categoryId, - position) + position, + viewersCanPostReactions + ) proc createCommunityCategory*(self: Controller, name: string, channels: seq[string]) = self.communityService.createCommunityCategory(self.sectionId, name, channels) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index eb8bb757a6..61437f5080 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -266,11 +266,11 @@ method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string, raise newException(ValueError, "No implementation available") method createCommunityChannel*(self: AccessInterface, name: string, description: string, - emoji: string, color: string, categoryId: string) {.base.} = + emoji: string, color: string, categoryId: string, viewersCanPostReactions: bool) {.base.} = raise newException(ValueError, "No implementation available") method editCommunityChannel*(self: AccessInterface, channelId, name, description, emoji, color, - categoryId: string, position: int) {.base.} = + categoryId: string, position: int, viewersCanPostReactions: bool) {.base.} = raise newException(ValueError, "No implementation available") method leaveCommunity*(self: AccessInterface) {.base.} = diff --git a/src/app/modules/main/chat_section/item.nim b/src/app/modules/main/chat_section/item.nim index 30cc1fc05f..7e1b50f814 100644 --- a/src/app/modules/main/chat_section/item.nim +++ b/src/app/modules/main/chat_section/item.nim @@ -35,6 +35,8 @@ type loaderActive: bool locked: bool requiresPermissions: bool + canPostReactions: bool + viewersCanPostReactions: bool proc initItem*( id, @@ -62,7 +64,9 @@ proc initItem*( onlineStatus = OnlineStatus.Inactive, loaderActive = false, locked = false, - requiresPermissions = false + requiresPermissions = false, + canPostReactions = true, + viewersCanPostReactions = true, ): Item = result = Item() result.id = id @@ -92,6 +96,8 @@ proc initItem*( result.loaderActive = loaderActive result.locked = locked result.requiresPermissions = requiresPermissions + result.canPostReactions = canPostReactions + result.viewersCanPostReactions = viewersCanPostReactions proc `$`*(self: Item): string = result = fmt"""chat_section/Item( @@ -120,6 +126,8 @@ proc `$`*(self: Item): string = loaderActive: {$self.loaderActive}, locked: {$self.locked}, requiresPermissions: {$self.requiresPermissions}, + canPostReactions: {$self.canPostReactions}, + viewersCanPostReactions: {$self.viewersCanPostReactions}, ]""" proc toJsonNode*(self: Item): JsonNode = @@ -148,7 +156,9 @@ proc toJsonNode*(self: Item): JsonNode = "onlineStatus": self.onlineStatus, "loaderActive": self.loaderActive, "locked": self.locked, - "requiresPermissions": self.requiresPermissions + "requiresPermissions": self.requiresPermissions, + "canPostReactions": self.canPostReactions, + "viewersCanPostReactions": self.viewersCanPostReactions, } proc delete*(self: Item) = @@ -300,3 +310,15 @@ proc requiresPermissions*(self: Item): bool = proc `requiresPermissions=`*(self: Item, value: bool) = self.requiresPermissions = value + +proc canPostReactions*(self: Item): bool = + self.canPostReactions + +proc `canPostReactions=`*(self: Item, value: bool) = + self.canPostReactions = value + +proc viewersCanPostReactions*(self: Item): bool = + self.viewersCanPostReactions + +proc `viewersCanPostReactions=`*(self: Item, value: bool) = + self.viewersCanPostReactions = value diff --git a/src/app/modules/main/chat_section/model.nim b/src/app/modules/main/chat_section/model.nim index 9531085b66..31dfbb8837 100644 --- a/src/app/modules/main/chat_section/model.nim +++ b/src/app/modules/main/chat_section/model.nim @@ -35,6 +35,8 @@ type LoaderActive Locked RequiresPermissions + CanPostReactions + ViewersCanPostReactions QtObject: type @@ -105,6 +107,8 @@ QtObject: ModelRole.LoaderActive.int:"loaderActive", ModelRole.Locked.int:"locked", ModelRole.RequiresPermissions.int:"requiresPermissions", + ModelRole.CanPostReactions.int:"canPostReactions", + ModelRole.ViewersCanPostReactions.int:"viewersCanPostReactions", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -172,6 +176,10 @@ QtObject: result = newQVariant(item.isLocked) of ModelRole.RequiresPermissions: result = newQVariant(item.requiresPermissions) + of ModelRole.CanPostReactions: + result = newQVariant(item.canPostReactions) + of ModelRole.ViewersCanPostReactions: + result = newQVariant(item.viewersCanPostReactions) proc getItemIdxById(items: seq[Item], id: string): int = var idx = 0 @@ -323,6 +331,23 @@ QtObject: defer: modelIndex.delete self.dataChanged(modelIndex, modelIndex, @[ModelRole.Muted.int]) + proc changeCanPostValues*(self: Model, id: string, canPostReactions, viewersCanPostReactions: bool) = + let index = self.getItemIdxById(id) + if index == -1: + return + if(self.items[index].canPostReactions == canPostReactions and + self.items[index].viewersCanPostReactions == viewersCanPostReactions + ): + return + self.items[index].canPostReactions = canPostReactions + self.items[index].viewersCanPostReactions = viewersCanPostReactions + let modelIndex = self.createIndex(index, 0, nil) + defer: modelIndex.delete + self.dataChanged(modelIndex, modelIndex, @[ + ModelRole.CanPostReactions.int, + ModelRole.ViewersCanPostReactions.int + ]) + proc changeMutedOnItemByCategoryId*(self: Model, categoryId: string, muted: bool) = for i in 0 ..< self.items.len: if self.items[i].categoryId == categoryId and self.items[i].muted != muted: diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index 1878692bd2..45bc245702 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -69,6 +69,8 @@ proc buildChatSectionUI( proc reevaluateRequiresTokenPermissionToJoin(self: Module) +proc changeCanPostValues*(self: Module, chatId: string, canPostReactions, viewersCanPostReactions: bool) + proc addOrUpdateChat(self: Module, chat: ChatDto, channelGroup: ChannelGroupDto, @@ -611,6 +613,8 @@ proc addNewChat*( self.controller.checkChatHasPermissions(self.controller.getMySectionId(), chatDto.id) else: false, + canPostReactions = chatDto.canPostReactions, + viewersCanPostReactions = chatDto.viewersCanPostReactions, ) self.addSubmodule( @@ -720,6 +724,7 @@ method onCommunityChannelEdited*(self: Module, chat: ChatDto) = if(not self.chatContentModules.contains(chat.id)): return self.view.chatsModel().updateItemDetailsById(chat.id, chat.name, chat.description, chat.emoji, chat.color) + self.changeCanPostValues(chat.id, chat.canPostReactions, chat.viewersCanPostReactions) method switchToOrCreateOneToOneChat*(self: Module, chatId: string) = # One To One chat is available only in the `Chat` section @@ -769,6 +774,9 @@ method onCategoryUnmuted*(self: Module, categoryId: string) = method changeMutedOnChat*(self: Module, chatId: string, muted: bool) = self.view.chatsModel().changeMutedOnItemById(chatId, muted) +proc changeCanPostValues*(self: Module, chatId: string, canPostReactions, viewersCanPostReactions: bool) = + self.view.chatsModel().changeCanPostValues(chatId, canPostReactions, viewersCanPostReactions) + method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, permissionId: string) = self.rebuildCommunityTokenPermissionsModel() singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed") @@ -1085,13 +1093,13 @@ method onAcceptRequestToJoinFailedNoPermission*(self: Module, communityId: strin let contact = self.controller.getContactById(memberKey) self.view.emitOpenNoPermissionsToJoinPopupSignal(community.name, contact.displayName, community.id, requestId) -method createCommunityChannel*(self: Module, name, description, emoji, color, categoryId: string) = - self.controller.createCommunityChannel(name, description, emoji, color, categoryId) +method createCommunityChannel*(self: Module, name, description, emoji, color, categoryId: string, viewersCanPostReactions: bool) = + self.controller.createCommunityChannel(name, description, emoji, color, categoryId, viewersCanPostReactions) method editCommunityChannel*(self: Module, channelId, name, description, emoji, color, - categoryId: string, position: int) = + categoryId: string, position: int, viewersCanPostReactions: bool) = self.controller.editCommunityChannel(channelId, name, description, emoji, color, categoryId, - position) + position, viewersCanPostReactions) method createCommunityCategory*(self: Module, name: string, channels: seq[string]) = self.controller.createCommunityCategory(name, channels) @@ -1232,6 +1240,7 @@ proc addOrUpdateChat(self: Module, if chatExists: self.changeMutedOnChat(chat.id, chat.muted) + self.changeCanPostValues(chat.id, chat.canPostReactions, chat.viewersCanPostReactions) self.updateChatRequiresPermissions(chat.id) self.updateChatLocked(chat.id) if (chat.chatType == ChatType.PrivateGroupChat): diff --git a/src/app/modules/main/chat_section/view.nim b/src/app/modules/main/chat_section/view.nim index 9954e79909..2ef8432855 100644 --- a/src/app/modules/main/chat_section/view.nim +++ b/src/app/modules/main/chat_section/view.nim @@ -268,9 +268,10 @@ QtObject: description: string, emoji: string, color: string, - categoryId: string + categoryId: string, + viewersCanPostReactions: bool ) {.slot.} = - self.delegate.createCommunityChannel(name, description, emoji, color, categoryId) + self.delegate.createCommunityChannel(name, description, emoji, color, categoryId, viewersCanPostReactions) proc editCommunityChannel*( self: View, @@ -280,7 +281,8 @@ QtObject: emoji: string, color: string, categoryId: string, - position: int + position: int, + viewersCanPostReactions: bool, ) {.slot.} = self.delegate.editCommunityChannel( channelId, @@ -289,7 +291,8 @@ QtObject: emoji, color, categoryId, - position + position, + viewersCanPostReactions, ) proc leaveCommunity*(self: View) {.slot.} = diff --git a/src/app_service/service/chat/dto/chat.nim b/src/app_service/service/chat/dto/chat.nim index 6a2680aeaf..95ca43c753 100644 --- a/src/app_service/service/chat/dto/chat.nim +++ b/src/app_service/service/chat/dto/chat.nim @@ -83,7 +83,8 @@ type ChatDto* = object syncedTo*: int64 syncedFrom*: int64 firstMessageTimestamp: int64 # valid only for community chats, 0 - undefined, 1 - no messages, >1 valid timestamps - canPost*: bool + canPostReactions*: bool + viewersCanPostReactions*: bool position*: int categoryId*: string highlight*: bool @@ -144,7 +145,8 @@ proc `$`*(self: ChatDto): string = communityId: {self.communityId}, profile: {self.profile}, joined: {self.joined}, - canPost: {self.canPost}, + canPostReactions: {self.canPostReactions}, + viewersCanPostReactions: {self.viewersCanPostReactions}, syncedTo: {self.syncedTo}, syncedFrom: {self.syncedFrom}, firstMessageTimestamp: {self.firstMessageTimestamp}, @@ -269,7 +271,8 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto = discard jsonObj.getProp("readMessagesAtClockValue", result.readMessagesAtClockValue) discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount) discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount) - discard jsonObj.getProp("canPost", result.canPost) + discard jsonObj.getProp("canPostReactions", result.canPostReactions) + discard jsonObj.getProp("viewersCanPostReactions", result.viewersCanPostReactions) discard jsonObj.getProp("alias", result.alias) discard jsonObj.getProp("muted", result.muted) discard jsonObj.getProp("categoryId", result.categoryId) @@ -416,3 +419,11 @@ proc communityChannelUuid*(self: ChatDto): string = if self.communityId == "": return "" return self.id[self.communityId.len .. ^1] + +proc updateMissingFields*(chatToUpdate: var ChatDto, oldChat: ChatDto) = + # This proc sets fields of `chatToUpdate` which are available only for community channels. + chatToUpdate.position = oldChat.position + chatToUpdate.canPostReactions = oldChat.canPostReactions + chatToUpdate.viewersCanPostReactions = oldChat.viewersCanPostReactions + chatToUpdate.categoryId = oldChat.categoryId + chatToUpdate.members = oldChat.members diff --git a/src/app_service/service/chat/service.nim b/src/app_service/service/chat/service.nim index 626f98c617..a1d1d0ac73 100644 --- a/src/app_service/service/chat/service.nim +++ b/src/app_service/service/chat/service.nim @@ -165,13 +165,17 @@ QtObject: var chats: seq[ChatDto] = @[] for chatDto in receivedData.chats: if (chatDto.active): - chats.add(chatDto) - + var updatedChat = chatDto # Handling members update for non-community chats let isCommunityChat = chatDto.chatType == ChatType.CommunityChat if not isCommunityChat and self.chats.hasKey(chatDto.id) and self.chats[chatDto.id].members != chatDto.members: self.events.emit(SIGNAL_CHAT_MEMBERS_CHANGED, ChatMembersChangedArgs(chatId: chatDto.id, members: chatDto.members)) - self.updateOrAddChat(chatDto) + + if isCommunityChat and self.chats.hasKey(chatDto.id): + updatedChat.updateMissingFields(self.chats[chatDto.id]) + + chats.add(updatedChat) + self.updateOrAddChat(updatedChat) elif self.chats.hasKey(chatDto.id) and self.chats[chatDto.id].active: # We left the chat diff --git a/src/app_service/service/community/service.nim b/src/app_service/service/community/service.nim index 5a1e4ed885..f435f126ad 100644 --- a/src/app_service/service/community/service.nim +++ b/src/app_service/service/community/service.nim @@ -421,13 +421,6 @@ QtObject: # but implement a solution for individual updates self.events.emit(SIGNAL_COMMUNITY_HISTORY_ARCHIVES_DOWNLOAD_FINISHED, CommunityIdArgs(communityId: receivedData.communityId)) - proc updateMissingFields(chatDto: var ChatDto, chat: ChatDto) = - # This proc sets fields of `chatDto` which are available only for community channels. - chatDto.position = chat.position - chatDto.canPost = chat.canPost - chatDto.categoryId = chat.categoryId - chatDto.members = chat.members - proc findChatById(id: string, chats: seq[ChatDto]): ChatDto = for chat in chats: if(chat.id == id): @@ -641,10 +634,20 @@ QtObject: ) ) - # Handle name/description changes - if chat.name != prevChat.name or chat.description != prevChat.description or chat.color != prevChat.color or chat.emoji != prevChat.emoji: - var updatedChat = findChatById(chat.id, updatedChats) - updatedChat.updateMissingFields(chat) + if chat.name != prevChat.name or chat.description != prevChat.description or chat.color != prevChat.color or + chat.emoji != prevChat.emoji or chat.viewersCanPostReactions != prevChat.viewersCanPostReactions: + var updatedChat = chat + + # TODO improve this in https://github.com/status-im/status-desktop/issues/12595 + # Currently, status-go only sends canPostReactions on app start (getChannelGroups) + # so here, we need to imply it. If viewersCanPostReactions is true, then everyone can post reactions + # admins can also always post reactions + if chat.viewersCanPostReactions or + (not chat.viewersCanPostReactions and community.memberRole != MemberRole.None): + updatedChat.canPostReactions = true + elif not chat.viewersCanPostReactions and community.memberRole == MemberRole.None: + updatedChat.canPostReactions = false + self.chatService.updateOrAddChat(updatedChat) # we have to update chats stored in the chat service. let data = CommunityChatArgs(chat: updatedChat) @@ -1271,9 +1274,12 @@ QtObject: description: string, emoji: string, color: string, - categoryId: string) = + categoryId: string, + viewersCanPostReactions: bool, + ) = try: - let response = status_go.createCommunityChannel(communityId, name, description, emoji, color, categoryId) + let response = status_go.createCommunityChannel(communityId, name, description, emoji, color, categoryId, + viewersCanPostReactions) if not response.error.isNil: let error = Json.decode($response.error, RpcError) @@ -1308,7 +1314,9 @@ QtObject: emoji: string, color: string, categoryId: string, - position: int) = + position: int, + viewersCanPostReactions: bool, + ) = try: let response = status_go.editCommunityChannel( communityId, @@ -1318,7 +1326,9 @@ QtObject: emoji, color, categoryId, - position) + position, + viewersCanPostReactions + ) if response.error != nil: let error = Json.decode($response.error, RpcError) diff --git a/src/backend/communities.nim b/src/backend/communities.nim index 3368c6214b..4306561128 100644 --- a/src/backend/communities.nim +++ b/src/backend/communities.nim @@ -302,7 +302,8 @@ proc createCommunityChannel*( description: string, emoji: string, color: string, - categoryId: string + categoryId: string, + viewersCanPostReactions: bool, ): RpcResponse[JsonNode] = result = callPrivateRPC("createCommunityChat".prefix, %*[ communityId, @@ -316,7 +317,8 @@ proc createCommunityChannel*( "emoji": emoji, "color": color }, - "category_id": categoryId + "category_id": categoryId, + "viewers_can_post_reactions": viewersCanPostReactions, }]) proc editCommunityChannel*( @@ -327,7 +329,8 @@ proc editCommunityChannel*( emoji: string, color: string, categoryId: string, - position: int + position: int, + viewersCanPostReactions: bool, ): RpcResponse[JsonNode] = result = callPrivateRPC("editCommunityChat".prefix, %*[ communityId, @@ -343,7 +346,8 @@ proc editCommunityChannel*( "color": color }, "category_id": categoryId, - "position": position + "position": position, + "viewers_can_post_reactions": viewersCanPostReactions, }]) proc reorderCommunityCategories*(communityId: string, categoryId: string, position: int): RpcResponse[JsonNode] = diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index 20da5b62fc..5edb045351 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -336,13 +336,13 @@ QtObject { } function createCommunityChannel(channelName, channelDescription, channelEmoji, channelColor, - categoryId) { + categoryId, viewersCanPostReactions) { chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription, - channelEmoji.trim(), channelColor, categoryId); + channelEmoji.trim(), channelColor, categoryId, viewersCanPostReactions); } function editCommunityChannel(chatId, newName, newDescription, newEmoji, newColor, - newCategory, channelPosition) { + newCategory, channelPosition, viewOnlyCanAddReaction) { chatCommunitySectionModule.editCommunityChannel( chatId, newName, @@ -350,7 +350,8 @@ QtObject { newEmoji, newColor, newCategory, - channelPosition + channelPosition, + viewOnlyCanAddReaction ) } diff --git a/ui/app/AppLayouts/Communities/popups/CreateChannelPopup.qml b/ui/app/AppLayouts/Communities/popups/CreateChannelPopup.qml index fa10b33e29..11817e620d 100644 --- a/ui/app/AppLayouts/Communities/popups/CreateChannelPopup.qml +++ b/ui/app/AppLayouts/Communities/popups/CreateChannelPopup.qml @@ -58,8 +58,8 @@ StatusStackModal { readonly property int maxChannelDescLength: 140 // channel signals - signal createCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId) - signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId) + signal createCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId, bool viewOnlyCanAddReaction) + signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId, bool viewOnlyCanAddReaction) signal deleteCommunityChannel() // Permissions signals: @@ -77,7 +77,6 @@ StatusStackModal { signal addPermissions(var permissions) signal removePermissions(var permissions) signal editPermissions(var permissions) - signal setViewOnlyCanAddReaction(bool checked) signal setHideIfPermissionsNotMet(bool checked) width: 640 @@ -187,13 +186,15 @@ StatusStackModal { StatusQUtils.Utils.filterXSS(descriptionTextArea.text), emoji, colorPanel.color.toString().toUpperCase(), - root.categoryId) + root.categoryId, + d.viewOnlyCanAddReaction) } else { root.editCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text), StatusQUtils.Utils.filterXSS(descriptionTextArea.text), emoji, colorPanel.color.toString().toUpperCase(), - root.categoryId) + root.categoryId, + d.viewOnlyCanAddReaction) } if (d.channelEditModel.dirtyPermissions) { @@ -213,10 +214,6 @@ StatusStackModal { } } - if (root.viewOnlyCanAddReaction !== d.viewOnlyCanAddReaction) { - root.setViewOnlyCanAddReaction(d.viewOnlyCanAddReaction); - } - if (root.hideIfPermissionsNotMet !== d.hideIfPermissionsNotMet) { root.setHideIfPermissionsNotMet(d.hideIfPermissionsNotMet); } diff --git a/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml b/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml index 3cec4a8bfd..a08a5d7c10 100644 --- a/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunityColumnView.qml @@ -331,6 +331,7 @@ Item { chatMuted = obj.muted channelPosition = obj.position chatCategoryId = obj.categoryId + viewersCanPostReactions = obj.viewersCanPostReactions } catch (e) { console.error("error parsing chat item json object, id: ", id, " error: ", e) close() @@ -385,6 +386,7 @@ Item { categoryId: chatCategoryId, chatId: chatContextMenuView.chatId, channelPosition: channelPosition, + viewOnlyCanAddReaction: viewersCanPostReactions, deleteChatConfirmationDialog: deleteChatConfirmationDialog }); } @@ -628,7 +630,7 @@ Item { onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor, chCategoryId) { root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor, - chCategoryId) + chCategoryId, viewOnlyCanAddReaction) chatId = root.store.currentChatContentModule().chatDetails.id } onEditCommunityChannel: { @@ -638,7 +640,8 @@ Item { chEmoji, chColor, chCategoryId, - channelPosition); + channelPosition, + viewOnlyCanAddReaction); } onAddPermissions: function (permissions) { @@ -663,9 +666,6 @@ Item { permissions[i].isPrivate) } } - onSetViewOnlyCanAddReaction: function (checked) { - root.store.permissionsStore.setViewOnlyCanAddReaction(chatId, checked) - } onSetHideIfPermissionsNotMet: function (checked) { root.store.permissionsStore.setHideIfPermissionsNotMet(chatId, checked) } diff --git a/ui/app/AppLayouts/Communities/views/PermissionsView.qml b/ui/app/AppLayouts/Communities/views/PermissionsView.qml index ad130d89b8..ce945ee0c2 100644 --- a/ui/app/AppLayouts/Communities/views/PermissionsView.qml +++ b/ui/app/AppLayouts/Communities/views/PermissionsView.qml @@ -127,9 +127,8 @@ ColumnLayout { StatusIconSwitch { Layout.fillWidth: true padding: 0 - - visible: false //TODO: enable this when we have the backend support https://github.com/status-im/status-desktop/issues/13292 - //visible: root.showChannelOptions + + visible: root.showChannelOptions title: qsTr("Users with view only permissions can add reactions") icon: "emojis" checked: root.viewOnlyCanAddReaction diff --git a/ui/imports/shared/stores/PermissionsStore.qml b/ui/imports/shared/stores/PermissionsStore.qml index 1ebdc2896b..a1782f13a7 100644 --- a/ui/imports/shared/stores/PermissionsStore.qml +++ b/ui/imports/shared/stores/PermissionsStore.qml @@ -17,10 +17,6 @@ QtObject { readonly property var permissionsModel: chatCommunitySectionModuleInst.permissionsModel - function setViewOnlyCanAddReaction(chatId, checked) { - //TODO: backend implementation - } - function setHideIfPermissionsNotMet(chatId, checked) { //TODO: backend implementation } diff --git a/ui/imports/shared/views/chat/ChatContextMenuView.qml b/ui/imports/shared/views/chat/ChatContextMenuView.qml index 3a6c086b01..de506ae9c2 100644 --- a/ui/imports/shared/views/chat/ChatContextMenuView.qml +++ b/ui/imports/shared/views/chat/ChatContextMenuView.qml @@ -26,6 +26,7 @@ StatusMenu { property bool chatMuted: false property int channelPosition: -1 property string chatCategoryId: "" + property bool viewersCanPostReactions: true property bool showDebugOptions: false property alias deleteChatConfirmationDialog: deleteChatConfirmationDialogComponent @@ -41,8 +42,6 @@ StatusMenu { signal leaveChat(string chatId) signal updateGroupChatDetails(string chatId, string groupName, string groupColor, string groupImage) - signal createCommunityChannel(string chatId, string newName, string newDescription, string newEmoji, string newColor) - signal editCommunityChannel(string chatId, string newName, string newDescription, string newEmoji, string newColor, string newCategory) signal requestMoreMessages(string chatId) signal addRemoveGroupMember() diff --git a/ui/imports/shared/views/chat/MessageContextMenuView.qml b/ui/imports/shared/views/chat/MessageContextMenuView.qml index 09bbaf7679..b3093b5274 100644 --- a/ui/imports/shared/views/chat/MessageContextMenuView.qml +++ b/ui/imports/shared/views/chat/MessageContextMenuView.qml @@ -23,6 +23,7 @@ StatusMenu { property string myPublicKey: "" property bool amIChatAdmin: false property bool disabledForChat: false + property bool forceEnableEmojiReactions: false property int chatType: Constants.chatType.unknown property string messageId: "" @@ -55,7 +56,7 @@ StatusMenu { id: emojiContainer width: emojiRow.width height: visible ? emojiRow.height : 0 - visible: !root.disabledForChat + visible: !root.disabledForChat || root.forceEnableEmojiReactions MessageReactionsRow { id: emojiRow diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 74c887cb5d..b710e506a4 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -261,7 +261,7 @@ Loader { property string activeMessage readonly property bool isMessageActive: d.activeMessage === root.messageId - readonly property bool addReactionAllowed: !root.isInPinnedPopup && !root.isChatBlocked + readonly property bool addReactionAllowed: !root.isInPinnedPopup && root.chatContentModule.chatDetails.canPostReactions function nextMessageHasHeader() { if(!root.nextMessageAsJsonObj) { @@ -648,7 +648,7 @@ Loader { topPadding: showHeader ? Style.current.halfPadding : 0 bottomPadding: showHeader && d.nextMessageHasHeader() ? Style.current.halfPadding : 2 disableHover: root.disableHover || - delegate.hideQuickActions || + (delegate.hideQuickActions && !d.addReactionAllowed) || (root.chatLogView && root.chatLogView.moving) || Global.activityPopupOpened @@ -727,7 +727,7 @@ Loader { mouseArea { acceptedButtons: Qt.RightButton - enabled: !root.isChatBlocked && + enabled: (!root.isChatBlocked || d.addReactionAllowed) && !root.placeholderMessage onClicked: { root.openMessageContextMenu() @@ -910,7 +910,7 @@ Loader { quickActions: [ Loader { - active: d.addReactionAllowed && delegate.hovered && !delegate.hideQuickActions + active: d.addReactionAllowed && delegate.hovered visible: active sourceComponent: StatusFlatRoundButton { width: d.chatButtonSize @@ -1125,6 +1125,7 @@ Loader { store: root.rootStore reactionModel: root.emojiReactionsModel disabledForChat: !root.rootStore.isUserAllowedToSendMessage + forceEnableEmojiReactions: !root.rootStore.isUserAllowedToSendMessage && d.addReactionAllowed onPinMessage: (messageId) => { root.messageStore.pinMessage(messageId)