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
This commit is contained in:
Jonathan Rainville 2024-03-13 15:13:41 -04:00 committed by GitHub
parent fc16b81caf
commit 634591b69f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 197 additions and 80 deletions

View File

@ -23,6 +23,7 @@ QtObject:
isContact: bool isContact: bool
active: bool active: bool
blocked: bool blocked: bool
canPostReactions: bool
proc delete*(self: ChatDetails) = proc delete*(self: ChatDetails) =
self.QObject.delete self.QObject.delete
@ -31,10 +32,25 @@ QtObject:
new(result, delete) new(result, delete)
result.QObject.setup result.QObject.setup
proc setChatDetails*(self: ChatDetails, id: string, `type`: int, belongsToCommunity, proc setChatDetails*(
isUsersListAvailable: bool, name, icon: string, color, description, self: ChatDetails,
emoji: string, hasUnreadMessages: bool, notificationsCount: int, highlight, muted: bool, position: int, id: string,
isUntrustworthy: bool, isContact: bool = false, blocked: bool = false) = `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.id = id
self.`type` = `type` self.`type` = `type`
self.belongsToCommunity = belongsToCommunity self.belongsToCommunity = belongsToCommunity
@ -53,6 +69,7 @@ QtObject:
self.isContact = isContact self.isContact = isContact
self.active = false self.active = false
self.blocked = blocked self.blocked = blocked
self.canPostReactions = canPostReactions
proc getId(self: ChatDetails): string {.slot.} = proc getId(self: ChatDetails): string {.slot.} =
return self.id return self.id
@ -227,3 +244,14 @@ QtObject:
proc setBlocked*(self: ChatDetails, value: bool) = proc setBlocked*(self: ChatDetails, value: bool) =
self.blocked = value self.blocked = value
self.blockedChanged() 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()

View File

@ -95,7 +95,7 @@ method load*(self: Module, chatItem: chat_item.Item) =
self.controller.isUsersListAvailable(), chatName, chatImage, self.controller.isUsersListAvailable(), chatName, chatImage,
chatItem.color, chatItem.description, chatItem.emoji, chatItem.hasUnreadMessages, chatItem.notificationsCount, chatItem.color, chatItem.description, chatItem.emoji, chatItem.hasUnreadMessages, chatItem.notificationsCount,
chatItem.highlight, chatItem.muted, chatItem.position, isUntrustworthy = trustStatus == TrustStatus.Untrustworthy, chatItem.highlight, chatItem.muted, chatItem.position, isUntrustworthy = trustStatus == TrustStatus.Untrustworthy,
isContact, chatItem.blocked) isContact, chatItem.blocked, chatItem.canPostReactions)
self.inputAreaModule.load() self.inputAreaModule.load()
self.messagesModule.load() self.messagesModule.load()

View File

@ -40,10 +40,10 @@ QtObject:
proc load*(self: View, id: string, `type`: int, belongsToCommunity, isUsersListAvailable: bool, proc load*(self: View, id: string, `type`: int, belongsToCommunity, isUsersListAvailable: bool,
name, icon: string, color, description, emoji: string, hasUnreadMessages: bool, name, icon: string, color, description, emoji: string, hasUnreadMessages: bool,
notificationsCount: int, highlight, muted: bool, position: int, isUntrustworthy: 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, self.chatDetails.setChatDetails(id, `type`, belongsToCommunity, isUsersListAvailable, name,
icon, color, description, emoji, hasUnreadMessages, notificationsCount, highlight, muted, position, icon, color, description, emoji, hasUnreadMessages, notificationsCount, highlight, muted, position,
isUntrustworthy, isContact, blocked) isUntrustworthy, isContact, blocked, canPostReactions)
self.delegate.viewDidLoad() self.delegate.viewDidLoad()
self.chatDetailsChanged() self.chatDetailsChanged()
@ -149,6 +149,7 @@ QtObject:
self.chatDetails.setEmoji(chatDto.emoji) self.chatDetails.setEmoji(chatDto.emoji)
self.chatDetails.setColor(chatDto.color) self.chatDetails.setColor(chatDto.color)
self.chatDetails.setMuted(chatDto.muted) self.chatDetails.setMuted(chatDto.muted)
self.chatDetails.setCanPostReactions(chatDto.canPostReactions)
proc updateChatDetailsName*(self: View, name: string) = proc updateChatDetailsName*(self: View, name: string) =
self.chatDetails.setName(name) self.chatDetails.setName(name)

View File

@ -564,9 +564,11 @@ proc createCommunityChannel*(
description: string, description: string,
emoji: string, emoji: string,
color: string, color: string,
categoryId: string) = categoryId: string,
viewersCanPostReactions: bool,
) =
self.communityService.createCommunityChannel(self.sectionId, name, description, emoji, color, self.communityService.createCommunityChannel(self.sectionId, name, description, emoji, color,
categoryId) categoryId, viewersCanPostReactions)
proc editCommunityChannel*( proc editCommunityChannel*(
self: Controller, self: Controller,
@ -576,7 +578,9 @@ proc editCommunityChannel*(
emoji: string, emoji: string,
color: string, color: string,
categoryId: string, categoryId: string,
position: int) = position: int,
viewersCanPostReactions: bool,
) =
self.communityService.editCommunityChannel( self.communityService.editCommunityChannel(
self.sectionId, self.sectionId,
channelId, channelId,
@ -585,7 +589,9 @@ proc editCommunityChannel*(
emoji, emoji,
color, color,
categoryId, categoryId,
position) position,
viewersCanPostReactions
)
proc createCommunityCategory*(self: Controller, name: string, channels: seq[string]) = proc createCommunityCategory*(self: Controller, name: string, channels: seq[string]) =
self.communityService.createCommunityCategory(self.sectionId, name, channels) self.communityService.createCommunityCategory(self.sectionId, name, channels)

View File

@ -266,11 +266,11 @@ method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string,
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method createCommunityChannel*(self: AccessInterface, name: string, description: string, 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") raise newException(ValueError, "No implementation available")
method editCommunityChannel*(self: AccessInterface, channelId, name, description, emoji, color, 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") raise newException(ValueError, "No implementation available")
method leaveCommunity*(self: AccessInterface) {.base.} = method leaveCommunity*(self: AccessInterface) {.base.} =

View File

@ -35,6 +35,8 @@ type
loaderActive: bool loaderActive: bool
locked: bool locked: bool
requiresPermissions: bool requiresPermissions: bool
canPostReactions: bool
viewersCanPostReactions: bool
proc initItem*( proc initItem*(
id, id,
@ -62,7 +64,9 @@ proc initItem*(
onlineStatus = OnlineStatus.Inactive, onlineStatus = OnlineStatus.Inactive,
loaderActive = false, loaderActive = false,
locked = false, locked = false,
requiresPermissions = false requiresPermissions = false,
canPostReactions = true,
viewersCanPostReactions = true,
): Item = ): Item =
result = Item() result = Item()
result.id = id result.id = id
@ -92,6 +96,8 @@ proc initItem*(
result.loaderActive = loaderActive result.loaderActive = loaderActive
result.locked = locked result.locked = locked
result.requiresPermissions = requiresPermissions result.requiresPermissions = requiresPermissions
result.canPostReactions = canPostReactions
result.viewersCanPostReactions = viewersCanPostReactions
proc `$`*(self: Item): string = proc `$`*(self: Item): string =
result = fmt"""chat_section/Item( result = fmt"""chat_section/Item(
@ -120,6 +126,8 @@ proc `$`*(self: Item): string =
loaderActive: {$self.loaderActive}, loaderActive: {$self.loaderActive},
locked: {$self.locked}, locked: {$self.locked},
requiresPermissions: {$self.requiresPermissions}, requiresPermissions: {$self.requiresPermissions},
canPostReactions: {$self.canPostReactions},
viewersCanPostReactions: {$self.viewersCanPostReactions},
]""" ]"""
proc toJsonNode*(self: Item): JsonNode = proc toJsonNode*(self: Item): JsonNode =
@ -148,7 +156,9 @@ proc toJsonNode*(self: Item): JsonNode =
"onlineStatus": self.onlineStatus, "onlineStatus": self.onlineStatus,
"loaderActive": self.loaderActive, "loaderActive": self.loaderActive,
"locked": self.locked, "locked": self.locked,
"requiresPermissions": self.requiresPermissions "requiresPermissions": self.requiresPermissions,
"canPostReactions": self.canPostReactions,
"viewersCanPostReactions": self.viewersCanPostReactions,
} }
proc delete*(self: Item) = proc delete*(self: Item) =
@ -300,3 +310,15 @@ proc requiresPermissions*(self: Item): bool =
proc `requiresPermissions=`*(self: Item, value: bool) = proc `requiresPermissions=`*(self: Item, value: bool) =
self.requiresPermissions = value 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

View File

@ -35,6 +35,8 @@ type
LoaderActive LoaderActive
Locked Locked
RequiresPermissions RequiresPermissions
CanPostReactions
ViewersCanPostReactions
QtObject: QtObject:
type type
@ -105,6 +107,8 @@ QtObject:
ModelRole.LoaderActive.int:"loaderActive", ModelRole.LoaderActive.int:"loaderActive",
ModelRole.Locked.int:"locked", ModelRole.Locked.int:"locked",
ModelRole.RequiresPermissions.int:"requiresPermissions", ModelRole.RequiresPermissions.int:"requiresPermissions",
ModelRole.CanPostReactions.int:"canPostReactions",
ModelRole.ViewersCanPostReactions.int:"viewersCanPostReactions",
}.toTable }.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant = method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -172,6 +176,10 @@ QtObject:
result = newQVariant(item.isLocked) result = newQVariant(item.isLocked)
of ModelRole.RequiresPermissions: of ModelRole.RequiresPermissions:
result = newQVariant(item.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 = proc getItemIdxById(items: seq[Item], id: string): int =
var idx = 0 var idx = 0
@ -323,6 +331,23 @@ QtObject:
defer: modelIndex.delete defer: modelIndex.delete
self.dataChanged(modelIndex, modelIndex, @[ModelRole.Muted.int]) 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) = proc changeMutedOnItemByCategoryId*(self: Model, categoryId: string, muted: bool) =
for i in 0 ..< self.items.len: for i in 0 ..< self.items.len:
if self.items[i].categoryId == categoryId and self.items[i].muted != muted: if self.items[i].categoryId == categoryId and self.items[i].muted != muted:

View File

@ -69,6 +69,8 @@ proc buildChatSectionUI(
proc reevaluateRequiresTokenPermissionToJoin(self: Module) proc reevaluateRequiresTokenPermissionToJoin(self: Module)
proc changeCanPostValues*(self: Module, chatId: string, canPostReactions, viewersCanPostReactions: bool)
proc addOrUpdateChat(self: Module, proc addOrUpdateChat(self: Module,
chat: ChatDto, chat: ChatDto,
channelGroup: ChannelGroupDto, channelGroup: ChannelGroupDto,
@ -611,6 +613,8 @@ proc addNewChat*(
self.controller.checkChatHasPermissions(self.controller.getMySectionId(), chatDto.id) self.controller.checkChatHasPermissions(self.controller.getMySectionId(), chatDto.id)
else: else:
false, false,
canPostReactions = chatDto.canPostReactions,
viewersCanPostReactions = chatDto.viewersCanPostReactions,
) )
self.addSubmodule( self.addSubmodule(
@ -720,6 +724,7 @@ method onCommunityChannelEdited*(self: Module, chat: ChatDto) =
if(not self.chatContentModules.contains(chat.id)): if(not self.chatContentModules.contains(chat.id)):
return return
self.view.chatsModel().updateItemDetailsById(chat.id, chat.name, chat.description, chat.emoji, chat.color) 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) = method switchToOrCreateOneToOneChat*(self: Module, chatId: string) =
# One To One chat is available only in the `Chat` section # 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) = method changeMutedOnChat*(self: Module, chatId: string, muted: bool) =
self.view.chatsModel().changeMutedOnItemById(chatId, muted) 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) = method onCommunityTokenPermissionDeleted*(self: Module, communityId: string, permissionId: string) =
self.rebuildCommunityTokenPermissionsModel() self.rebuildCommunityTokenPermissionsModel()
singletonInstance.globalEvents.showCommunityTokenPermissionDeletedNotification(communityId, "Community permission deleted", "A token permission has been removed") 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) let contact = self.controller.getContactById(memberKey)
self.view.emitOpenNoPermissionsToJoinPopupSignal(community.name, contact.displayName, community.id, requestId) self.view.emitOpenNoPermissionsToJoinPopupSignal(community.name, contact.displayName, community.id, requestId)
method createCommunityChannel*(self: Module, name, description, emoji, color, categoryId: string) = method createCommunityChannel*(self: Module, name, description, emoji, color, categoryId: string, viewersCanPostReactions: bool) =
self.controller.createCommunityChannel(name, description, emoji, color, categoryId) self.controller.createCommunityChannel(name, description, emoji, color, categoryId, viewersCanPostReactions)
method editCommunityChannel*(self: Module, channelId, name, description, emoji, color, 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, self.controller.editCommunityChannel(channelId, name, description, emoji, color, categoryId,
position) position, viewersCanPostReactions)
method createCommunityCategory*(self: Module, name: string, channels: seq[string]) = method createCommunityCategory*(self: Module, name: string, channels: seq[string]) =
self.controller.createCommunityCategory(name, channels) self.controller.createCommunityCategory(name, channels)
@ -1232,6 +1240,7 @@ proc addOrUpdateChat(self: Module,
if chatExists: if chatExists:
self.changeMutedOnChat(chat.id, chat.muted) self.changeMutedOnChat(chat.id, chat.muted)
self.changeCanPostValues(chat.id, chat.canPostReactions, chat.viewersCanPostReactions)
self.updateChatRequiresPermissions(chat.id) self.updateChatRequiresPermissions(chat.id)
self.updateChatLocked(chat.id) self.updateChatLocked(chat.id)
if (chat.chatType == ChatType.PrivateGroupChat): if (chat.chatType == ChatType.PrivateGroupChat):

View File

@ -268,9 +268,10 @@ QtObject:
description: string, description: string,
emoji: string, emoji: string,
color: string, color: string,
categoryId: string categoryId: string,
viewersCanPostReactions: bool
) {.slot.} = ) {.slot.} =
self.delegate.createCommunityChannel(name, description, emoji, color, categoryId) self.delegate.createCommunityChannel(name, description, emoji, color, categoryId, viewersCanPostReactions)
proc editCommunityChannel*( proc editCommunityChannel*(
self: View, self: View,
@ -280,7 +281,8 @@ QtObject:
emoji: string, emoji: string,
color: string, color: string,
categoryId: string, categoryId: string,
position: int position: int,
viewersCanPostReactions: bool,
) {.slot.} = ) {.slot.} =
self.delegate.editCommunityChannel( self.delegate.editCommunityChannel(
channelId, channelId,
@ -289,7 +291,8 @@ QtObject:
emoji, emoji,
color, color,
categoryId, categoryId,
position position,
viewersCanPostReactions,
) )
proc leaveCommunity*(self: View) {.slot.} = proc leaveCommunity*(self: View) {.slot.} =

View File

@ -83,7 +83,8 @@ type ChatDto* = object
syncedTo*: int64 syncedTo*: int64
syncedFrom*: int64 syncedFrom*: int64
firstMessageTimestamp: int64 # valid only for community chats, 0 - undefined, 1 - no messages, >1 valid timestamps firstMessageTimestamp: int64 # valid only for community chats, 0 - undefined, 1 - no messages, >1 valid timestamps
canPost*: bool canPostReactions*: bool
viewersCanPostReactions*: bool
position*: int position*: int
categoryId*: string categoryId*: string
highlight*: bool highlight*: bool
@ -144,7 +145,8 @@ proc `$`*(self: ChatDto): string =
communityId: {self.communityId}, communityId: {self.communityId},
profile: {self.profile}, profile: {self.profile},
joined: {self.joined}, joined: {self.joined},
canPost: {self.canPost}, canPostReactions: {self.canPostReactions},
viewersCanPostReactions: {self.viewersCanPostReactions},
syncedTo: {self.syncedTo}, syncedTo: {self.syncedTo},
syncedFrom: {self.syncedFrom}, syncedFrom: {self.syncedFrom},
firstMessageTimestamp: {self.firstMessageTimestamp}, firstMessageTimestamp: {self.firstMessageTimestamp},
@ -269,7 +271,8 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto =
discard jsonObj.getProp("readMessagesAtClockValue", result.readMessagesAtClockValue) discard jsonObj.getProp("readMessagesAtClockValue", result.readMessagesAtClockValue)
discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount) discard jsonObj.getProp("unviewedMessagesCount", result.unviewedMessagesCount)
discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount) 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("alias", result.alias)
discard jsonObj.getProp("muted", result.muted) discard jsonObj.getProp("muted", result.muted)
discard jsonObj.getProp("categoryId", result.categoryId) discard jsonObj.getProp("categoryId", result.categoryId)
@ -416,3 +419,11 @@ proc communityChannelUuid*(self: ChatDto): string =
if self.communityId == "": if self.communityId == "":
return "" return ""
return self.id[self.communityId.len .. ^1] 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

View File

@ -165,13 +165,17 @@ QtObject:
var chats: seq[ChatDto] = @[] var chats: seq[ChatDto] = @[]
for chatDto in receivedData.chats: for chatDto in receivedData.chats:
if (chatDto.active): if (chatDto.active):
chats.add(chatDto) var updatedChat = chatDto
# Handling members update for non-community chats # Handling members update for non-community chats
let isCommunityChat = chatDto.chatType == ChatType.CommunityChat let isCommunityChat = chatDto.chatType == ChatType.CommunityChat
if not isCommunityChat and self.chats.hasKey(chatDto.id) and self.chats[chatDto.id].members != chatDto.members: 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.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: elif self.chats.hasKey(chatDto.id) and self.chats[chatDto.id].active:
# We left the chat # We left the chat

View File

@ -421,13 +421,6 @@ QtObject:
# but implement a solution for individual updates # but implement a solution for individual updates
self.events.emit(SIGNAL_COMMUNITY_HISTORY_ARCHIVES_DOWNLOAD_FINISHED, CommunityIdArgs(communityId: receivedData.communityId)) 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 = proc findChatById(id: string, chats: seq[ChatDto]): ChatDto =
for chat in chats: for chat in chats:
if(chat.id == id): 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
if chat.name != prevChat.name or chat.description != prevChat.description or chat.color != prevChat.color or chat.emoji != prevChat.emoji: chat.emoji != prevChat.emoji or chat.viewersCanPostReactions != prevChat.viewersCanPostReactions:
var updatedChat = findChatById(chat.id, updatedChats) var updatedChat = chat
updatedChat.updateMissingFields(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. self.chatService.updateOrAddChat(updatedChat) # we have to update chats stored in the chat service.
let data = CommunityChatArgs(chat: updatedChat) let data = CommunityChatArgs(chat: updatedChat)
@ -1271,9 +1274,12 @@ QtObject:
description: string, description: string,
emoji: string, emoji: string,
color: string, color: string,
categoryId: string) = categoryId: string,
viewersCanPostReactions: bool,
) =
try: 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: if not response.error.isNil:
let error = Json.decode($response.error, RpcError) let error = Json.decode($response.error, RpcError)
@ -1308,7 +1314,9 @@ QtObject:
emoji: string, emoji: string,
color: string, color: string,
categoryId: string, categoryId: string,
position: int) = position: int,
viewersCanPostReactions: bool,
) =
try: try:
let response = status_go.editCommunityChannel( let response = status_go.editCommunityChannel(
communityId, communityId,
@ -1318,7 +1326,9 @@ QtObject:
emoji, emoji,
color, color,
categoryId, categoryId,
position) position,
viewersCanPostReactions
)
if response.error != nil: if response.error != nil:
let error = Json.decode($response.error, RpcError) let error = Json.decode($response.error, RpcError)

View File

@ -302,7 +302,8 @@ proc createCommunityChannel*(
description: string, description: string,
emoji: string, emoji: string,
color: string, color: string,
categoryId: string categoryId: string,
viewersCanPostReactions: bool,
): RpcResponse[JsonNode] = ): RpcResponse[JsonNode] =
result = callPrivateRPC("createCommunityChat".prefix, %*[ result = callPrivateRPC("createCommunityChat".prefix, %*[
communityId, communityId,
@ -316,7 +317,8 @@ proc createCommunityChannel*(
"emoji": emoji, "emoji": emoji,
"color": color "color": color
}, },
"category_id": categoryId "category_id": categoryId,
"viewers_can_post_reactions": viewersCanPostReactions,
}]) }])
proc editCommunityChannel*( proc editCommunityChannel*(
@ -327,7 +329,8 @@ proc editCommunityChannel*(
emoji: string, emoji: string,
color: string, color: string,
categoryId: string, categoryId: string,
position: int position: int,
viewersCanPostReactions: bool,
): RpcResponse[JsonNode] = ): RpcResponse[JsonNode] =
result = callPrivateRPC("editCommunityChat".prefix, %*[ result = callPrivateRPC("editCommunityChat".prefix, %*[
communityId, communityId,
@ -343,7 +346,8 @@ proc editCommunityChannel*(
"color": color "color": color
}, },
"category_id": categoryId, "category_id": categoryId,
"position": position "position": position,
"viewers_can_post_reactions": viewersCanPostReactions,
}]) }])
proc reorderCommunityCategories*(communityId: string, categoryId: string, position: int): RpcResponse[JsonNode] = proc reorderCommunityCategories*(communityId: string, categoryId: string, position: int): RpcResponse[JsonNode] =

View File

@ -336,13 +336,13 @@ QtObject {
} }
function createCommunityChannel(channelName, channelDescription, channelEmoji, channelColor, function createCommunityChannel(channelName, channelDescription, channelEmoji, channelColor,
categoryId) { categoryId, viewersCanPostReactions) {
chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription, chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription,
channelEmoji.trim(), channelColor, categoryId); channelEmoji.trim(), channelColor, categoryId, viewersCanPostReactions);
} }
function editCommunityChannel(chatId, newName, newDescription, newEmoji, newColor, function editCommunityChannel(chatId, newName, newDescription, newEmoji, newColor,
newCategory, channelPosition) { newCategory, channelPosition, viewOnlyCanAddReaction) {
chatCommunitySectionModule.editCommunityChannel( chatCommunitySectionModule.editCommunityChannel(
chatId, chatId,
newName, newName,
@ -350,7 +350,8 @@ QtObject {
newEmoji, newEmoji,
newColor, newColor,
newCategory, newCategory,
channelPosition channelPosition,
viewOnlyCanAddReaction
) )
} }

View File

@ -58,8 +58,8 @@ StatusStackModal {
readonly property int maxChannelDescLength: 140 readonly property int maxChannelDescLength: 140
// channel signals // channel signals
signal createCommunityChannel(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) signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chColor, string chCategoryId, bool viewOnlyCanAddReaction)
signal deleteCommunityChannel() signal deleteCommunityChannel()
// Permissions signals: // Permissions signals:
@ -77,7 +77,6 @@ StatusStackModal {
signal addPermissions(var permissions) signal addPermissions(var permissions)
signal removePermissions(var permissions) signal removePermissions(var permissions)
signal editPermissions(var permissions) signal editPermissions(var permissions)
signal setViewOnlyCanAddReaction(bool checked)
signal setHideIfPermissionsNotMet(bool checked) signal setHideIfPermissionsNotMet(bool checked)
width: 640 width: 640
@ -187,13 +186,15 @@ StatusStackModal {
StatusQUtils.Utils.filterXSS(descriptionTextArea.text), StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji, emoji,
colorPanel.color.toString().toUpperCase(), colorPanel.color.toString().toUpperCase(),
root.categoryId) root.categoryId,
d.viewOnlyCanAddReaction)
} else { } else {
root.editCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text), root.editCommunityChannel(StatusQUtils.Utils.filterXSS(nameInput.input.text),
StatusQUtils.Utils.filterXSS(descriptionTextArea.text), StatusQUtils.Utils.filterXSS(descriptionTextArea.text),
emoji, emoji,
colorPanel.color.toString().toUpperCase(), colorPanel.color.toString().toUpperCase(),
root.categoryId) root.categoryId,
d.viewOnlyCanAddReaction)
} }
if (d.channelEditModel.dirtyPermissions) { if (d.channelEditModel.dirtyPermissions) {
@ -213,10 +214,6 @@ StatusStackModal {
} }
} }
if (root.viewOnlyCanAddReaction !== d.viewOnlyCanAddReaction) {
root.setViewOnlyCanAddReaction(d.viewOnlyCanAddReaction);
}
if (root.hideIfPermissionsNotMet !== d.hideIfPermissionsNotMet) { if (root.hideIfPermissionsNotMet !== d.hideIfPermissionsNotMet) {
root.setHideIfPermissionsNotMet(d.hideIfPermissionsNotMet); root.setHideIfPermissionsNotMet(d.hideIfPermissionsNotMet);
} }

View File

@ -331,6 +331,7 @@ Item {
chatMuted = obj.muted chatMuted = obj.muted
channelPosition = obj.position channelPosition = obj.position
chatCategoryId = obj.categoryId chatCategoryId = obj.categoryId
viewersCanPostReactions = obj.viewersCanPostReactions
} catch (e) { } catch (e) {
console.error("error parsing chat item json object, id: ", id, " error: ", e) console.error("error parsing chat item json object, id: ", id, " error: ", e)
close() close()
@ -385,6 +386,7 @@ Item {
categoryId: chatCategoryId, categoryId: chatCategoryId,
chatId: chatContextMenuView.chatId, chatId: chatContextMenuView.chatId,
channelPosition: channelPosition, channelPosition: channelPosition,
viewOnlyCanAddReaction: viewersCanPostReactions,
deleteChatConfirmationDialog: deleteChatConfirmationDialog deleteChatConfirmationDialog: deleteChatConfirmationDialog
}); });
} }
@ -628,7 +630,7 @@ Item {
onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor, onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor,
chCategoryId) { chCategoryId) {
root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor, root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor,
chCategoryId) chCategoryId, viewOnlyCanAddReaction)
chatId = root.store.currentChatContentModule().chatDetails.id chatId = root.store.currentChatContentModule().chatDetails.id
} }
onEditCommunityChannel: { onEditCommunityChannel: {
@ -638,7 +640,8 @@ Item {
chEmoji, chEmoji,
chColor, chColor,
chCategoryId, chCategoryId,
channelPosition); channelPosition,
viewOnlyCanAddReaction);
} }
onAddPermissions: function (permissions) { onAddPermissions: function (permissions) {
@ -663,9 +666,6 @@ Item {
permissions[i].isPrivate) permissions[i].isPrivate)
} }
} }
onSetViewOnlyCanAddReaction: function (checked) {
root.store.permissionsStore.setViewOnlyCanAddReaction(chatId, checked)
}
onSetHideIfPermissionsNotMet: function (checked) { onSetHideIfPermissionsNotMet: function (checked) {
root.store.permissionsStore.setHideIfPermissionsNotMet(chatId, checked) root.store.permissionsStore.setHideIfPermissionsNotMet(chatId, checked)
} }

View File

@ -127,9 +127,8 @@ ColumnLayout {
StatusIconSwitch { StatusIconSwitch {
Layout.fillWidth: true Layout.fillWidth: true
padding: 0 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") title: qsTr("Users with view only permissions can add reactions")
icon: "emojis" icon: "emojis"
checked: root.viewOnlyCanAddReaction checked: root.viewOnlyCanAddReaction

View File

@ -17,10 +17,6 @@ QtObject {
readonly property var permissionsModel: readonly property var permissionsModel:
chatCommunitySectionModuleInst.permissionsModel chatCommunitySectionModuleInst.permissionsModel
function setViewOnlyCanAddReaction(chatId, checked) {
//TODO: backend implementation
}
function setHideIfPermissionsNotMet(chatId, checked) { function setHideIfPermissionsNotMet(chatId, checked) {
//TODO: backend implementation //TODO: backend implementation
} }

View File

@ -26,6 +26,7 @@ StatusMenu {
property bool chatMuted: false property bool chatMuted: false
property int channelPosition: -1 property int channelPosition: -1
property string chatCategoryId: "" property string chatCategoryId: ""
property bool viewersCanPostReactions: true
property bool showDebugOptions: false property bool showDebugOptions: false
property alias deleteChatConfirmationDialog: deleteChatConfirmationDialogComponent property alias deleteChatConfirmationDialog: deleteChatConfirmationDialogComponent
@ -41,8 +42,6 @@ StatusMenu {
signal leaveChat(string chatId) signal leaveChat(string chatId)
signal updateGroupChatDetails(string chatId, string groupName, string groupColor, string groupImage) 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 requestMoreMessages(string chatId)
signal addRemoveGroupMember() signal addRemoveGroupMember()

View File

@ -23,6 +23,7 @@ StatusMenu {
property string myPublicKey: "" property string myPublicKey: ""
property bool amIChatAdmin: false property bool amIChatAdmin: false
property bool disabledForChat: false property bool disabledForChat: false
property bool forceEnableEmojiReactions: false
property int chatType: Constants.chatType.unknown property int chatType: Constants.chatType.unknown
property string messageId: "" property string messageId: ""
@ -55,7 +56,7 @@ StatusMenu {
id: emojiContainer id: emojiContainer
width: emojiRow.width width: emojiRow.width
height: visible ? emojiRow.height : 0 height: visible ? emojiRow.height : 0
visible: !root.disabledForChat visible: !root.disabledForChat || root.forceEnableEmojiReactions
MessageReactionsRow { MessageReactionsRow {
id: emojiRow id: emojiRow

View File

@ -261,7 +261,7 @@ Loader {
property string activeMessage property string activeMessage
readonly property bool isMessageActive: d.activeMessage === root.messageId 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() { function nextMessageHasHeader() {
if(!root.nextMessageAsJsonObj) { if(!root.nextMessageAsJsonObj) {
@ -648,7 +648,7 @@ Loader {
topPadding: showHeader ? Style.current.halfPadding : 0 topPadding: showHeader ? Style.current.halfPadding : 0
bottomPadding: showHeader && d.nextMessageHasHeader() ? Style.current.halfPadding : 2 bottomPadding: showHeader && d.nextMessageHasHeader() ? Style.current.halfPadding : 2
disableHover: root.disableHover || disableHover: root.disableHover ||
delegate.hideQuickActions || (delegate.hideQuickActions && !d.addReactionAllowed) ||
(root.chatLogView && root.chatLogView.moving) || (root.chatLogView && root.chatLogView.moving) ||
Global.activityPopupOpened Global.activityPopupOpened
@ -727,7 +727,7 @@ Loader {
mouseArea { mouseArea {
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
enabled: !root.isChatBlocked && enabled: (!root.isChatBlocked || d.addReactionAllowed) &&
!root.placeholderMessage !root.placeholderMessage
onClicked: { onClicked: {
root.openMessageContextMenu() root.openMessageContextMenu()
@ -910,7 +910,7 @@ Loader {
quickActions: [ quickActions: [
Loader { Loader {
active: d.addReactionAllowed && delegate.hovered && !delegate.hideQuickActions active: d.addReactionAllowed && delegate.hovered
visible: active visible: active
sourceComponent: StatusFlatRoundButton { sourceComponent: StatusFlatRoundButton {
width: d.chatButtonSize width: d.chatButtonSize
@ -1125,6 +1125,7 @@ Loader {
store: root.rootStore store: root.rootStore
reactionModel: root.emojiReactionsModel reactionModel: root.emojiReactionsModel
disabledForChat: !root.rootStore.isUserAllowedToSendMessage disabledForChat: !root.rootStore.isUserAllowedToSendMessage
forceEnableEmojiReactions: !root.rootStore.isUserAllowedToSendMessage && d.addReactionAllowed
onPinMessage: (messageId) => { onPinMessage: (messageId) => {
root.messageStore.pinMessage(messageId) root.messageStore.pinMessage(messageId)