feat(desktop/communities): View community member messages functionality (#14002)

* feat(desktop/communities): View member messages functionality
This commit is contained in:
Mykhailo Prakhov 2024-03-20 11:50:10 +01:00 committed by GitHub
parent a48b2532ae
commit a586c6d352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 580 additions and 30 deletions

View File

@ -100,6 +100,7 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, communityId: st
return msg_item_qobj.newMessageItem(msg_item.initItem( return msg_item_qobj.newMessageItem(msg_item.initItem(
message.id, message.id,
communityId, # we don't received community id via `activityCenterNotifications` api call communityId, # we don't received community id via `activityCenterNotifications` api call
message.chatId,
message.responseTo, message.responseTo,
message.`from`, message.`from`,
contactDetails.defaultDisplayName, contactDetails.defaultDisplayName,

View File

@ -142,3 +142,6 @@ method setPermissionsCheckOngoing*(self: AccessInterface, value: bool) {.base.}
method getPermissionsCheckOngoing*(self: AccessInterface): bool {.base.} = method getPermissionsCheckOngoing*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method scrollToMessage*(self: AccessInterface, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -151,6 +151,7 @@ proc createMessageItemsFromMessageDtos(self: Module, messages: seq[MessageDto],
var item = initItem( var item = initItem(
message.id, message.id,
message.chatId,
message.communityId, message.communityId,
message.responseTo, message.responseTo,
message.`from`, message.`from`,
@ -239,6 +240,7 @@ proc createFetchMoreMessagesItem(self: Module): Item =
result = initItem( result = initItem(
FETCH_MORE_MESSAGES_MESSAGE_ID, FETCH_MORE_MESSAGES_MESSAGE_ID,
communityId = "", communityId = "",
chatId = "",
responseToMessageWithId = "", responseToMessageWithId = "",
senderId = chatDto.id, senderId = chatDto.id,
senderDisplayName = "", senderDisplayName = "",
@ -306,6 +308,7 @@ proc createChatIdentifierItem(self: Module): Item =
result = initItem( result = initItem(
CHAT_IDENTIFIER_MESSAGE_ID, CHAT_IDENTIFIER_MESSAGE_ID,
communityId = "", communityId = "",
chatId = "",
responseToMessageWithId = "", responseToMessageWithId = "",
senderId = chatDto.id, senderId = chatDto.id,
senderDisplayName = chatName, senderDisplayName = chatName,

View File

@ -174,6 +174,7 @@ proc buildPinnedMessageItem(self: Module, message: MessageDto, actionInitiatedBy
item = pinned_msg_item.initItem( item = pinned_msg_item.initItem(
message.id, message.id,
message.communityId, message.communityId,
message.chatId,
message.responseTo, message.responseTo,
message.`from`, message.`from`,
contactDetails.defaultDisplayName, contactDetails.defaultDisplayName,
@ -425,3 +426,6 @@ method setPermissionsCheckOngoing*(self: Module, value: bool) =
method getPermissionsCheckOngoing*(self: Module): bool = method getPermissionsCheckOngoing*(self: Module): bool =
self.view.getPermissionsCheckOngoing() self.view.getPermissionsCheckOngoing()
method scrollToMessage*(self: Module, messageId: string) =
self.messagesModule.scrollToMessage(messageId)

View File

@ -397,6 +397,20 @@ proc init*(self: Controller) =
self.events.on(SIGNAL_MAILSERVER_HISTORY_REQUEST_COMPLETED) do(e:Args): self.events.on(SIGNAL_MAILSERVER_HISTORY_REQUEST_COMPLETED) do(e:Args):
self.delegate.setLoadingHistoryMessagesInProgress(false) self.delegate.setLoadingHistoryMessagesInProgress(false)
self.events.on(SIGNAL_COMMUNITY_MEMBER_ALL_MESSAGES) do(e:Args):
var args = CommunityMemberMessagesArgs(e)
if args.communityId == self.sectionId:
self.delegate.onCommunityMemberMessagesLoaded(args.messages)
self.events.on(SIGNAL_MESSAGES_DELETED) do(e:Args):
var args = MessagesDeletedArgs(e)
let isSectionEmpty = args.communityId == ""
if args.communityId == self.sectionId or isSectionEmpty:
for chatId, messagesIds in args.deletedMessages:
if isSectionEmpty and not self.delegate.communityContainsChat(chatId):
continue
self.delegate.onCommunityMemberMessagesDeleted(messagesIds)
proc isCommunity*(self: Controller): bool = proc isCommunity*(self: Controller): bool =
return self.isCommunitySection return self.isCommunitySection
@ -725,3 +739,14 @@ proc waitingOnNewCommunityOwnerToConfirmRequestToRejoin*(self: Controller, commu
proc setCommunityShard*(self: Controller, shardIndex: int) = proc setCommunityShard*(self: Controller, shardIndex: int) =
self.communityService.asyncSetCommunityShard(self.getMySectionId(), shardIndex) self.communityService.asyncSetCommunityShard(self.getMySectionId(), shardIndex)
proc loadCommunityMemberMessages*(self: Controller, communityId: string, memberPubKey: string) =
self.messageService.asyncLoadCommunityMemberAllMessages(communityId, memberPubKey)
proc getTransactionDetails*(self: Controller, message: MessageDto): (string,string) =
return self.messageService.getTransactionDetails(message)
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
return self.messageService.getWalletAccounts()
proc deleteCommunityMemberMessages*(self: Controller, memberPubKey: string, messageId: string, chatId: string) =
self.messageService.deleteCommunityMemberMessages(self.getMySectionId(), memberPubKey, messageId, chatId)

View File

@ -404,3 +404,20 @@ method setCommunityShard*(self: AccessInterface, shardIndex: int) {.base.} =
method setShardingInProgress*(self: AccessInterface, value: bool) {.base.} = method setShardingInProgress*(self: AccessInterface, value: bool) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method loadCommunityMemberMessages*(self: AccessInterface, communityId: string, memberPubKey: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityMemberMessagesLoaded*(self: AccessInterface, messages: seq[MessageDto]) {.base.} =
raise newException(ValueError, "No implementation available")
method deleteCommunityMemberMessages*(self: AccessInterface, memberPubKey: string, messageId: string, chatId: string) {.base.} =
raise newException(ValueError, "No implementation available")
method onCommunityMemberMessagesDeleted*(self: AccessInterface, messages: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method communityContainsChat*(self: AccessInterface, chatId: string): bool {.base.} =
raise newException(ValueError, "No implementation available")
method openCommunityChatAndScrollToMessage*(self: AccessInterface, chatId: string, messageId: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -5,6 +5,9 @@ import ../io_interface as delegate_interface
import view, controller, active_item import view, controller, active_item
import model as chats_model import model as chats_model
import item as chat_item import item as chat_item
import ../../shared_models/message_item as member_msg_item
import ../../shared_models/message_model as member_msg_model
import ../../shared_models/message_transaction_parameters_item
import ../../shared_models/user_item as user_item import ../../shared_models/user_item as user_item
import ../../shared_models/user_model as user_model import ../../shared_models/user_model as user_model
import ../../shared_models/token_permissions_model import ../../shared_models/token_permissions_model
@ -87,7 +90,7 @@ proc addOrUpdateChat(self: Module,
sharedUrlsService: shared_urls_service.Service, sharedUrlsService: shared_urls_service.Service,
setChatAsActive: bool = true, setChatAsActive: bool = true,
insertIntoModel: bool = true, insertIntoModel: bool = true,
): Item ): chat_item.Item
proc newModule*( proc newModule*(
delegate: delegate_interface.AccessInterface, delegate: delegate_interface.AccessInterface,
@ -120,6 +123,95 @@ proc newModule*(
result.chatContentModules = initOrderedTable[string, chat_content_module.AccessInterface]() result.chatContentModules = initOrderedTable[string, chat_content_module.AccessInterface]()
proc currentUserWalletContainsAddress(self: Module, address: string): bool =
if (address.len == 0):
return false
let accounts = self.controller.getWalletAccounts()
for acc in accounts:
if (acc.address == address):
return true
return false
# TODO: duplicates in chats and messages
proc buildCommunityMemberMessageItem(self: Module, message: MessageDto): member_msg_item.Item =
let contactDetails = self.controller.getContactDetails(message.`from`)
let communityChats = self.controller.getAllChats(self.getMySectionId())
var quotedMessageAuthorDetails = ContactDetails()
if message.quotedMessage.`from` != "":
if message.`from` == message.quotedMessage.`from`:
quotedMessageAuthorDetails = contactDetails
else:
quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`)
var transactionContract = message.transactionParameters.contract
var transactionValue = message.transactionParameters.value
var isCurrentUser = contactDetails.isCurrentUser
if message.contentType == ContentType.Transaction:
(transactionContract, transactionValue) = self.controller.getTransactionDetails(message)
if message.transactionParameters.fromAddress != "":
isCurrentUser = self.currentUserWalletContainsAddress(message.transactionParameters.fromAddress)
return member_msg_item.initItem(
message.id,
message.communityId,
message.chatId,
message.responseTo,
message.`from`,
contactDetails.defaultDisplayName,
contactDetails.optionalName,
contactDetails.icon,
contactDetails.colorHash,
isCurrentUser,
contactDetails.dto.added,
message.outgoingStatus,
self.controller.getRenderedText(message.parsedText, communityChats),
message.text,
message.parsedText,
message.image,
message.containsContactMentions(),
message.seen,
timestamp = message.timestamp,
clock = message.clock,
message.contentType,
message.messageType,
message.contactRequestState,
message.sticker.url,
message.sticker.pack,
message.links,
message.linkPreviews,
newTransactionParametersItem(message.transactionParameters.id,
message.transactionParameters.fromAddress,
message.transactionParameters.address,
transactionContract,
transactionValue,
message.transactionParameters.transactionHash,
message.transactionParameters.commandState,
message.transactionParameters.signature),
message.mentionedUsersPks,
contactDetails.dto.trustStatus,
contactDetails.dto.ensVerified,
message.discordMessage,
resendError = "",
message.deleted,
message.deletedBy,
deletedByContactDetails = ContactDetails(),
message.mentioned,
message.quotedMessage.`from`,
message.quotedMessage.text,
self.controller.getRenderedText(message.quotedMessage.parsedText, communityChats),
message.quotedMessage.contentType,
message.quotedMessage.deleted,
message.quotedMessage.discordMessage,
quotedMessageAuthorDetails,
message.quotedMessage.albumImages,
message.quotedMessage.albumImagesCount,
message.albumId,
if len(message.albumId) == 0: @[] else: @[message.image],
if len(message.albumId) == 0: @[] else: @[message.id],
message.albumImagesCount,
message.bridgeMessage,
message.quotedMessage.bridgeMessage,
)
method delete*(self: Module) = method delete*(self: Module) =
self.controller.delete self.controller.delete
self.view.delete self.view.delete
@ -166,7 +258,7 @@ proc removeSubmodule(self: Module, chatId: string) =
self.chatContentModules.del(chatId) self.chatContentModules.del(chatId)
proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, communityId: string, insertIntoModel: bool = true): Item = proc addCategoryItem(self: Module, category: Category, memberRole: MemberRole, communityId: string, insertIntoModel: bool = true): chat_item.Item =
let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(communityId, category.id) let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(communityId, category.id)
result = chat_item.initItem( result = chat_item.initItem(
id = category.id, id = category.id,
@ -210,7 +302,7 @@ proc buildChatSectionUI(
var selectedItemId = "" var selectedItemId = ""
let sectionLastOpenChat = singletonInstance.localAccountSensitiveSettings.getSectionLastOpenChat(self.controller.getMySectionId()) let sectionLastOpenChat = singletonInstance.localAccountSensitiveSettings.getSectionLastOpenChat(self.controller.getMySectionId())
var items: seq[Item] = @[] var items: seq[chat_item.Item] = @[]
for categoryDto in channelGroup.categories: for categoryDto in channelGroup.categories:
# Add items for the categories. We use a special type to identify categories # Add items for the categories. We use a special type to identify categories
items.add(self.addCategoryItem(categoryDto, channelGroup.memberRole, channelGroup.id)) items.add(self.addCategoryItem(categoryDto, channelGroup.memberRole, channelGroup.id))
@ -544,7 +636,7 @@ proc addNewChat(
sharedUrlsService: shared_urls_service.Service, sharedUrlsService: shared_urls_service.Service,
setChatAsActive: bool = true, setChatAsActive: bool = true,
insertIntoModel: bool = true, insertIntoModel: bool = true,
): Item = ): chat_item.Item =
let hasNotification =chatDto.unviewedMessagesCount > 0 let hasNotification =chatDto.unviewedMessagesCount > 0
let notificationsCount = chatDto.unviewedMentionsCount let notificationsCount = chatDto.unviewedMentionsCount
@ -1262,7 +1354,7 @@ proc addOrUpdateChat(self: Module,
sharedUrlsService: shared_urls_service.Service, sharedUrlsService: shared_urls_service.Service,
setChatAsActive: bool = true, setChatAsActive: bool = true,
insertIntoModel: bool = true, insertIntoModel: bool = true,
): Item = ): chat_item.Item =
let sectionId = self.controller.getMySectionId() let sectionId = self.controller.getMySectionId()
if(belongsToCommunity and sectionId != chat.communityId or if(belongsToCommunity and sectionId != chat.communityId or
@ -1326,7 +1418,7 @@ method addOrUpdateChat*(self: Module,
sharedUrlsService: shared_urls_service.Service, sharedUrlsService: shared_urls_service.Service,
setChatAsActive: bool = true, setChatAsActive: bool = true,
insertIntoModel: bool = true, insertIntoModel: bool = true,
): Item = ): chat_item.Item =
result = self.addOrUpdateChat( result = self.addOrUpdateChat(
chat, chat,
ChannelGroupDto(), ChannelGroupDto(),
@ -1430,3 +1522,33 @@ method setCommunityShard*(self: Module, shardIndex: int) =
method setShardingInProgress*(self: Module, value: bool) = method setShardingInProgress*(self: Module, value: bool) =
self.view.setShardingInProgress(value) self.view.setShardingInProgress(value)
method loadCommunityMemberMessages*(self: Module, communityId: string, memberPubKey: string) =
self.view.getMemberMessagesModel().clear()
self.controller.loadCommunityMemberMessages(communityId, memberPubKey)
method onCommunityMemberMessagesLoaded*(self: Module, messages: seq[MessageDto]) =
var viewItems: seq[member_msg_item.Item]
for message in messages:
let item = self.buildCommunityMemberMessageItem(message)
viewItems.add(item)
if viewItems.len == 0:
return
self.view.getMemberMessagesModel().insertItemsBasedOnClock(viewItems)
method deleteCommunityMemberMessages*(self: Module, memberPubKey: string, messageId: string, chatId: string) =
self.controller.deleteCommunityMemberMessages(memberPubKey, messageId, chatId)
method onCommunityMemberMessagesDeleted*(self: Module, deletedMessages: seq[string]) =
if self.view.getMemberMessagesModel().rowCount > 0:
for deletedMessageId in deletedMessages:
self.view.getMemberMessagesModel().removeItem(deletedMessageId)
method communityContainsChat*(self: Module, chatId: string): bool =
return self.chatContentModules.hasKey(chatId)
method openCommunityChatAndScrollToMessage*(self: Module, chatId: string, messageId: string) =
self.delegate.setActiveSectionById(self.getMySectionId())
self.setActiveItem(chatId)
self.chatContentModules[chatId].scrollToMessage(messageId)

View File

@ -2,6 +2,7 @@ import NimQml, json, sequtils, strutils
import model as chats_model import model as chats_model
import item, active_item import item, active_item
import ../../shared_models/user_model as user_model import ../../shared_models/user_model as user_model
import ../../shared_models/message_model as member_msg_model
import ../../shared_models/token_permissions_model import ../../shared_models/token_permissions_model
import io_interface import io_interface
@ -32,6 +33,9 @@ QtObject:
isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin: bool isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin: bool
shardingInProgress: bool shardingInProgress: bool
allChannelsAreHiddenBecauseNotPermitted: bool allChannelsAreHiddenBecauseNotPermitted: bool
memberMessagesModel: member_msg_model.Model
memberMessagesModelVariant: QVariant
proc delete*(self: View) = proc delete*(self: View) =
self.model.delete self.model.delete
@ -46,6 +50,8 @@ QtObject:
self.editCategoryChannelsVariant.delete self.editCategoryChannelsVariant.delete
self.tokenPermissionsModel.delete self.tokenPermissionsModel.delete
self.tokenPermissionsVariant.delete self.tokenPermissionsVariant.delete
self.memberMessagesModel.delete
self.memberMessagesModelVariant.delete
self.QObject.delete self.QObject.delete
@ -71,6 +77,8 @@ QtObject:
result.chatsLoaded = false result.chatsLoaded = false
result.communityMetrics = "[]" result.communityMetrics = "[]"
result.isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin = false result.isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin = false
result.memberMessagesModel = member_msg_model.newModel()
result.memberMessagesModelVariant = newQVariant(result.memberMessagesModel)
proc load*(self: View) = proc load*(self: View) =
self.delegate.viewDidLoad() self.delegate.viewDidLoad()
@ -509,3 +517,20 @@ QtObject:
return return
self.allChannelsAreHiddenBecauseNotPermitted = allAreHidden self.allChannelsAreHiddenBecauseNotPermitted = allAreHidden
self.allChannelsAreHiddenBecauseNotPermittedChanged() self.allChannelsAreHiddenBecauseNotPermittedChanged()
proc getMemberMessagesModel*(self: View): member_msg_model.Model =
return self.memberMessagesModel
proc getMemberMessagesModelVariant(self: View): QVariant {.slot.} =
return self.memberMessagesModelVariant
QtProperty[QVariant] memberMessagesModel:
read = getMemberMessagesModelVariant
proc loadCommunityMemberMessages*(self: View, communityId: string, memberPubKey: string) {.slot.} =
self.delegate.loadCommunityMemberMessages(communityId, memberPubKey)
proc deleteCommunityMemberMessages*(self: View, memberPubKey: string, messageId: string, chatId: string) {.slot.} =
self.delegate.deleteCommunityMemberMessages(memberPubKey, messageId, chatId)
proc openCommunityChatAndScrollToMessage*(self: View, chatId: string, messageId: string) {.slot.} =
self.delegate.openCommunityChatAndScrollToMessage(chatId, messageId)

View File

@ -13,6 +13,7 @@ type
Item* = ref object Item* = ref object
id: string id: string
communityId: string communityId: string
chatId: string
responseToMessageWithId: string responseToMessageWithId: string
senderId: string senderId: string
senderDisplayName: string senderDisplayName: string
@ -75,6 +76,7 @@ type
proc initItem*( proc initItem*(
id, id,
communityId, communityId,
chatId,
responseToMessageWithId, responseToMessageWithId,
senderId, senderId,
senderDisplayName, senderDisplayName,
@ -128,6 +130,7 @@ proc initItem*(
result = Item() result = Item()
result.id = id result.id = id
result.communityId = communityId result.communityId = communityId
result.chatId = chatId
result.responseToMessageWithId = responseToMessageWithId result.responseToMessageWithId = responseToMessageWithId
result.senderId = senderId result.senderId = senderId
result.senderDisplayName = senderDisplayName result.senderDisplayName = senderDisplayName
@ -228,6 +231,7 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item =
return initItem( return initItem(
id = "", id = "",
communityId = "", communityId = "",
chatId = "",
responseToMessageWithId = "", responseToMessageWithId = "",
senderId = "", senderId = "",
senderDisplayName = "", senderDisplayName = "",
@ -283,6 +287,7 @@ proc `$`*(self: Item): string =
result = fmt"""Item( result = fmt"""Item(
id: {$self.id}, id: {$self.id},
communityId: {$self.communityId}, communityId: {$self.communityId},
chatId: {$self.chatId},
responseToMessageWithId: {self.responseToMessageWithId}, responseToMessageWithId: {self.responseToMessageWithId},
senderId: {self.senderId}, senderId: {self.senderId},
senderDisplayName: {$self.senderDisplayName}, senderDisplayName: {$self.senderDisplayName},
@ -320,6 +325,9 @@ proc id*(self: Item): string {.inline.} =
proc communityId*(self: Item): string {.inline.} = proc communityId*(self: Item): string {.inline.} =
self.communityId self.communityId
proc chatId*(self: Item): string {.inline.} =
self.chatId
proc responseToMessageWithId*(self: Item): string {.inline.} = proc responseToMessageWithId*(self: Item): string {.inline.} =
self.responseToMessageWithId self.responseToMessageWithId
@ -516,6 +524,7 @@ proc toJsonNode*(self: Item): JsonNode =
result = %* { result = %* {
"id": self.id, "id": self.id,
"communityId": self.communityId, "communityId": self.communityId,
"chatId": self.chatId,
"responseToMessageWithId": self.responseToMessageWithId, "responseToMessageWithId": self.responseToMessageWithId,
"senderId": self.senderId, "senderId": self.senderId,
"senderDisplayName": self.senderDisplayName, "senderDisplayName": self.senderDisplayName,

View File

@ -16,6 +16,7 @@ type
NextMsgIndex NextMsgIndex
NextMsgTimestamp NextMsgTimestamp
CommunityId CommunityId
ChatId
ResponseToMessageWithId ResponseToMessageWithId
SenderId SenderId
SenderDisplayName SenderDisplayName
@ -123,6 +124,7 @@ QtObject:
ModelRole.NextMsgIndex.int:"nextMsgIndex", ModelRole.NextMsgIndex.int:"nextMsgIndex",
ModelRole.NextMsgTimestamp.int:"nextMsgTimestamp", ModelRole.NextMsgTimestamp.int:"nextMsgTimestamp",
ModelRole.CommunityId.int:"communityId", ModelRole.CommunityId.int:"communityId",
ModelRole.ChatId.int:"chatId",
ModelRole.ResponseToMessageWithId.int:"responseToMessageWithId", ModelRole.ResponseToMessageWithId.int:"responseToMessageWithId",
ModelRole.SenderId.int:"senderId", ModelRole.SenderId.int:"senderId",
ModelRole.SenderDisplayName.int:"senderDisplayName", ModelRole.SenderDisplayName.int:"senderDisplayName",
@ -231,6 +233,8 @@ QtObject:
result = newQVariant(0) result = newQVariant(0)
of ModelRole.CommunityId: of ModelRole.CommunityId:
result = newQVariant(item.communityId) result = newQVariant(item.communityId)
of ModelRole.ChatId:
result = newQVariant(item.chatId)
of ModelRole.ResponseToMessageWithId: of ModelRole.ResponseToMessageWithId:
result = newQVariant(item.responseToMessageWithId) result = newQVariant(item.responseToMessageWithId)
of ModelRole.SenderId: of ModelRole.SenderId:

View File

@ -338,3 +338,34 @@ const asyncMarkMessageAsUnreadTask: Task = proc(argEncoded: string) {.gcsafe, ni
responseJson["error"] = %e.msg responseJson["error"] = %e.msg
arg.finish(responseJson) arg.finish(responseJson)
#################################################
# Async load community member messages
#################################################
type
AsyncLoadCommunityMemberAllMessagesTaskArg = ref object of QObjectTaskArg
communityId*: string
memberPubKey*: string
const asyncLoadCommunityMemberAllMessagesTask: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncLoadCommunityMemberAllMessagesTaskArg](argEncoded)
var responseJson = %*{
"communityId": arg.communityId,
"error": ""
}
try:
let response = status_go.getCommunityMemberAllMessages(arg.communityId, arg.memberPubKey)
if not response.error.isNil:
raise newException(CatchableError, "response error: " & response.error.message)
responseJson["messages"] = response.result
except Exception as e:
error "error: ", procName = "asyncLoadCommunityMemberAllMessagesTask", errName = e.name,
errDesription = e.msg, communityId=arg.communityId, memberPubKey=arg.memberPubKey
responseJson["error"] = %e.msg
arg.finish(responseJson)

View File

@ -64,6 +64,7 @@ const SIGNAL_URLS_UNFURLED* = "urlsUnfurled"
const SIGNAL_GET_MESSAGE_FINISHED* = "getMessageFinished" const SIGNAL_GET_MESSAGE_FINISHED* = "getMessageFinished"
const SIGNAL_URLS_UNFURLING_PLAN_READY* = "urlsUnfurlingPlanReady" const SIGNAL_URLS_UNFURLING_PLAN_READY* = "urlsUnfurlingPlanReady"
const SIGNAL_MESSAGE_MARKED_AS_UNREAD* = "messageMarkedAsUnread" const SIGNAL_MESSAGE_MARKED_AS_UNREAD* = "messageMarkedAsUnread"
const SIGNAL_COMMUNITY_MEMBER_ALL_MESSAGES* = "communityMemberAllMessages"
include async_tasks include async_tasks
@ -117,6 +118,7 @@ type
deletedBy*: string deletedBy*: string
MessagesDeletedArgs* = ref object of Args MessagesDeletedArgs* = ref object of Args
communityId*: string
deletedMessages*: Table[string, seq[string]] deletedMessages*: Table[string, seq[string]]
MessageDeliveredArgs* = ref object of Args MessageDeliveredArgs* = ref object of Args
@ -154,6 +156,10 @@ type
message*: MessageDto message*: MessageDto
error*: string error*: string
CommunityMemberMessagesArgs* = ref object of Args
communityId*: string
messages*: seq[MessageDto]
QtObject: QtObject:
type Service* = ref object of QObject type Service* = ref object of QObject
events: EventEmitter events: EventEmitter
@ -274,6 +280,17 @@ QtObject:
discard self.asyncLoadMoreMessagesForChat(chatId) discard self.asyncLoadMoreMessagesForChat(chatId)
proc asyncLoadCommunityMemberAllMessages*(self: Service, communityId: string, memberPublicKey: string) =
let arg = AsyncLoadCommunityMemberAllMessagesTaskArg(
communityId: communityId,
memberPubKey: memberPublicKey,
tptr: cast[ByteAddress](asyncLoadCommunityMemberAllMessagesTask),
vptr: cast[ByteAddress](self.vptr),
slot: "onAsyncLoadCommunityMemberAllMessages"
)
self.threadpool.start(arg)
proc handleMessagesUpdate(self: Service, chats: var seq[ChatDto], messages: var seq[MessageDto]) = proc handleMessagesUpdate(self: Service, chats: var seq[ChatDto], messages: var seq[MessageDto]) =
# We included `chats` in this condition cause that's the form how `status-go` sends updates. # We included `chats` in this condition cause that's the form how `status-go` sends updates.
# The first element from the `receivedData.chats` array contains details about the chat a messages received in # The first element from the `receivedData.chats` array contains details about the chat a messages received in
@ -358,8 +375,8 @@ QtObject:
let data = MessageRemovedArgs(chatId: rm.chatId, messageId: rm.messageId, deletedBy: rm.deletedBy) let data = MessageRemovedArgs(chatId: rm.chatId, messageId: rm.messageId, deletedBy: rm.deletedBy)
self.events.emit(SIGNAL_MESSAGE_REMOVED, data) self.events.emit(SIGNAL_MESSAGE_REMOVED, data)
proc handleDeletedMessagesUpdate(self: Service, deletedMessages: Table[string, seq[string]]) = proc handleDeletedMessagesUpdate(self: Service, deletedMessages: Table[string, seq[string]], communityId: string) =
let data = MessagesDeletedArgs(deletedMessages: deletedMessages) let data = MessagesDeletedArgs(deletedMessages: deletedMessages, communityId: communityId)
self.events.emit(SIGNAL_MESSAGES_DELETED, data) self.events.emit(SIGNAL_MESSAGES_DELETED, data)
proc handleEmojiReactionsUpdate(self: Service, emojiReactions: seq[ReactionDto]) = proc handleEmojiReactionsUpdate(self: Service, emojiReactions: seq[ReactionDto]) =
@ -430,7 +447,7 @@ QtObject:
self.handleRemovedMessagesUpdate(receivedData.removedMessages) self.handleRemovedMessagesUpdate(receivedData.removedMessages)
# Handling deleted messages updates # Handling deleted messages updates
if (receivedData.deletedMessages.len > 0): if (receivedData.deletedMessages.len > 0):
self.handleDeletedMessagesUpdate(receivedData.deletedMessages) self.handleDeletedMessagesUpdate(receivedData.deletedMessages, "")
# Handling emoji reactions updates # Handling emoji reactions updates
if (receivedData.emojiReactions.len > 0): if (receivedData.emojiReactions.len > 0):
self.handleEmojiReactionsUpdate(receivedData.emojiReactions) self.handleEmojiReactionsUpdate(receivedData.emojiReactions)
@ -542,6 +559,29 @@ QtObject:
self.events.emit(SIGNAL_MESSAGES_LOADED, data) self.events.emit(SIGNAL_MESSAGES_LOADED, data)
proc onAsyncLoadCommunityMemberAllMessages*(self: Service, response: string) {.slot.} =
try:
let rpcResponseObj = response.parseJson
if rpcResponseObj{"error"}.kind != JNull and rpcResponseObj{"error"}.getStr != "":
raise newException(RpcException, rpcResponseObj{"error"}.getStr)
if rpcResponseObj{"messages"}.kind == JNull:
return
if rpcResponseObj{"messages"}.kind != JArray:
raise newException(RpcException, "invalid messages type in response")
var communityId: string
discard rpcResponseObj.getProp("communityId", communityId)
var messages = map(rpcResponseObj{"messages"}.getElems(), proc(x: JsonNode): MessageDto = x.toMessageDto())
if messages.len > 0:
self.bulkReplacePubKeysWithDisplayNames(messages)
let data = CommunityMemberMessagesArgs(communityId: communityId, messages: messages)
self.events.emit(SIGNAL_COMMUNITY_MEMBER_ALL_MESSAGES, data)
except Exception as e:
error "error: ", procName="onAsyncLoadCommunityMemberAllMessages", errName = e.name, errDesription = e.msg
proc addReaction*(self: Service, chatId: string, messageId: string, emojiId: int) = proc addReaction*(self: Service, chatId: string, messageId: string, emojiId: int) =
try: try:
let response = status_go.addReaction(chatId, messageId, emojiId) let response = status_go.addReaction(chatId, messageId, emojiId)
@ -1147,3 +1187,26 @@ proc resendChatMessage*(self: Service, messageId: string): string =
except Exception as e: except Exception as e:
error "error: ", procName="resendChatMessage", errName = e.name, errDesription = e.msg error "error: ", procName="resendChatMessage", errName = e.name, errDesription = e.msg
return fmt"{e.name}: {e.msg}" return fmt"{e.name}: {e.msg}"
# TODO: would be nice to make it async but in this case we will need to show come spinner in the UI during deleting the message
proc deleteCommunityMemberMessages*(self: Service, communityId: string, memberPubKey: string, messageId: string, chatId: string) =
try:
let response = status_go.deleteCommunityMemberMessages(communityId, memberPubKey, messageId, chatId)
if response.result.contains("error"):
let errMsg = response.result["error"].getStr
raise newException(RpcException, "Error deleting community member messages: " & errMsg)
var deletedMessages = initTable[string, seq[string]]()
if response.result.contains("deletedMessages"):
let deletedMessagesObj = response.result["deletedMessages"]
for chatId, messageIdsArrayJson in deletedMessagesObj:
if not deletedMessages.hasKey(chatId):
deletedMessages[chatId] = @[]
for messageId in messageIdsArrayJson:
deletedMessages[chatId].add(messageId.getStr())
self.handleDeletedMessagesUpdate(deletedMessages, communityId)
except Exception as e:
error "error: ", procName="deleteCommunityMemberMessages", errName = e.name, errDesription = e.msg

View File

@ -87,3 +87,24 @@ proc getTextURLsToUnfurl*(text: string): RpcResponse[JsonNode] =
proc unfurlUrls*(urls: seq[string]): RpcResponse[JsonNode] = proc unfurlUrls*(urls: seq[string]): RpcResponse[JsonNode] =
let payload = %*[urls] let payload = %*[urls]
result = callPrivateRPC("unfurlURLs".prefix, payload) result = callPrivateRPC("unfurlURLs".prefix, payload)
proc getCommunityMemberAllMessages*(communityId: string, memberPublicKey: string): RpcResponse[JsonNode] =
let payload = %* [{"communityId": communityId, "memberPublicKey": memberPublicKey}]
result = callPrivateRPC("getCommunityMemberAllMessages".prefix, payload)
proc deleteCommunityMemberMessages*(communityId: string, memberPubKey: string, messageId: string, chatId: string): RpcResponse[JsonNode] =
var messages: seq[JsonNode] = @[]
if messageId != "" and chatId != "":
messages.add(%*{
"id": messageId,
"chat_id": chatId,
})
let payload = %* [{
"communityId": communityId,
"memberPubKey": memberPubKey,
"messages": messages,
"deleteAll": messages.len() == 0
}]
result = callPrivateRPC("deleteCommunityMemberMessages".prefix, payload)

View File

@ -329,6 +329,10 @@ QtObject {
chatCommunitySectionModule.removeUserFromCommunity(pubKey); chatCommunitySectionModule.removeUserFromCommunity(pubKey);
} }
function loadCommunityMemberMessages(communityId, pubKey) {
chatCommunitySectionModule.loadCommunityMemberMessages(communityId, pubKey);
}
function banUserFromCommunity(pubKey, deleteAllMessages) { function banUserFromCommunity(pubKey, deleteAllMessages) {
chatCommunitySectionModule.banUserFromCommunity(pubKey, deleteAllMessages); chatCommunitySectionModule.banUserFromCommunity(pubKey, deleteAllMessages);
} }

View File

@ -26,6 +26,7 @@ SettingsPage {
signal unbanUserClicked(string id) signal unbanUserClicked(string id)
signal acceptRequestToJoin(string id) signal acceptRequestToJoin(string id)
signal declineRequestToJoin(string id) signal declineRequestToJoin(string id)
signal viewMemberMessagesClicked(string pubKey, string displayName)
function goTo(tab: int) { function goTo(tab: int) {
if(root.contentItem) { if(root.contentItem) {
@ -127,6 +128,8 @@ SettingsPage {
kickBanPopup.userId = id kickBanPopup.userId = id
kickBanPopup.open() kickBanPopup.open()
} }
onViewMemberMessagesClicked: root.viewMemberMessagesClicked(pubKey, displayName)
} }
MembersTabPanel { MembersTabPanel {
@ -182,6 +185,7 @@ SettingsPage {
Layout.fillHeight: true Layout.fillHeight: true
onUnbanUserClicked: root.unbanUserClicked(id) onUnbanUserClicked: root.unbanUserClicked(id)
onViewMemberMessagesClicked: root.viewMemberMessagesClicked(pubKey, displayName)
} }
} }
} }

View File

@ -29,6 +29,7 @@ Item {
signal kickUserClicked(string id, string name) signal kickUserClicked(string id, string name)
signal banUserClicked(string id, string name) signal banUserClicked(string id, string name)
signal unbanUserClicked(string id) signal unbanUserClicked(string id)
signal viewMemberMessagesClicked(string pubKey, string displayName)
signal acceptRequestToJoin(string id) signal acceptRequestToJoin(string id)
signal declineRequestToJoin(string id) signal declineRequestToJoin(string id)
@ -94,6 +95,10 @@ Item {
readonly property bool tabIsShowingRejectButton: root.panelType === MembersTabPanel.TabType.PendingRequests readonly property bool tabIsShowingRejectButton: root.panelType === MembersTabPanel.TabType.PendingRequests
readonly property bool tabIsShowingAcceptButton: root.panelType === MembersTabPanel.TabType.PendingRequests || readonly property bool tabIsShowingAcceptButton: root.panelType === MembersTabPanel.TabType.PendingRequests ||
root.panelType === MembersTabPanel.TabType.DeclinedRequests root.panelType === MembersTabPanel.TabType.DeclinedRequests
readonly property bool tabIsShowingViewMessagesButton: model.membershipRequestState !== Constants.CommunityMembershipRequestState.BannedWithAllMessagesDelete &&
(root.panelType === MembersTabPanel.TabType.AllMembers ||
root.panelType === MembersTabPanel.TabType.BannedMembers)
// Request states // Request states
readonly property bool isPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.Pending readonly property bool isPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.Pending
@ -130,6 +135,7 @@ Item {
} }
} }
readonly property bool showOnHover: isHovered && ctaAllowed readonly property bool showOnHover: isHovered && ctaAllowed
readonly property bool canDeleteMessages: itsMe || model.memberRole !== Constants.memberRole.owner
/// Button visibility /// /// Button visibility ///
readonly property bool acceptButtonVisible: tabIsShowingAcceptButton && (isPending || isRejected || isRejectedPending || isAcceptedPending) && showOnHover readonly property bool acceptButtonVisible: tabIsShowingAcceptButton && (isPending || isRejected || isRejectedPending || isAcceptedPending) && showOnHover
@ -141,6 +147,9 @@ Item {
readonly property bool kickPendingButtonVisible: tabIsShowingKickBanButtons && isKickPending readonly property bool kickPendingButtonVisible: tabIsShowingKickBanButtons && isKickPending
readonly property bool banPendingButtonVisible: tabIsShowingKickBanButtons && isBanPending readonly property bool banPendingButtonVisible: tabIsShowingKickBanButtons && isBanPending
readonly property bool unbanButtonVisible: tabIsShowingUnbanButton && isBanned && showOnHover readonly property bool unbanButtonVisible: tabIsShowingUnbanButton && isBanned && showOnHover
readonly property bool viewMessagesButtonVisible: tabIsShowingViewMessagesButton && showOnHover
readonly property bool messagesDeletedTextVisible: showOnHover &&
model.membershipRequestState === Constants.CommunityMembershipRequestState.BannedWithAllMessagesDelete
/// Pending states /// /// Pending states ///
readonly property bool isPendingState: isAcceptedPending || isRejectedPending || isBanPending || isUnbanPending || isKickPending readonly property bool isPendingState: isAcceptedPending || isRejectedPending || isBanPending || isUnbanPending || isKickPending
@ -179,6 +188,24 @@ Item {
enabled: pendingText.visible enabled: pendingText.visible
} }
}, },
StatusBaseText {
text: qsTr("Messages deleted")
color: Theme.palette.baseColor1
anchors.verticalCenter: parent.verticalCenter
visible: messagesDeletedTextVisible
},
StatusButton {
id: viewMessages
anchors.verticalCenter: parent.verticalCenter
objectName: "MemberListItem_ViewMessages"
text: qsTr("View Messages")
visible: viewMessagesButtonVisible
size: StatusBaseButton.Size.Small
onClicked: root.viewMemberMessagesClicked(model.pubKey, model.displayName)
},
StatusButton { StatusButton {
id: kickButton id: kickButton
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
@ -204,6 +231,8 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: unbanButtonVisible visible: unbanButtonVisible
text: qsTr("Unban") text: qsTr("Unban")
type: StatusBaseButton.Type.Danger
size: StatusBaseButton.Size.Small
onClicked: root.unbanUserClicked(model.pubKey) onClicked: root.unbanUserClicked(model.pubKey)
}, },

View File

@ -0,0 +1,143 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQml.Models 2.14
import QtGraphicalEffects 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import utils 1.0
import shared.views.chat 1.0
StatusDialog {
id: root
property var store
property var chatCommunitySectionModule
property var memberMessagesModel: chatCommunitySectionModule.memberMessagesModel
property string memberPubKey: ""
property string displayName: ""
width: 800
title: qsTr("%1 messages").arg(root.displayName)
subtitle: qsTr("%n message(s)", "", root.memberMessagesModel.count)
ColumnLayout {
anchors.fill: parent
id: column
StatusBaseText {
visible: communityMemberMessageListView.count === 0
text: qsTr("No messages")
Layout.alignment: Qt.AlignCenter
verticalAlignment: Text.AlignVCenter
color: Style.current.secondaryText
Layout.topMargin: 40
Layout.bottomMargin: 40
}
StatusListView {
id: communityMemberMessageListView
model: root.memberMessagesModel
Layout.fillWidth: true
Layout.fillHeight: count
implicitHeight: contentHeight
delegate: Item {
id: messageDelegate
width: ListView.view.width
height: messageItem.height
MessageView {
id: messageItem
width: parent.width
rootStore: root.store
chatCommunitySectionModule: root.chatCommunitySectionModule
messageStore: root.memberMessagesModel
messageId: model.id
chatId: model.chatId
responseToMessageWithId: model.responseToMessageWithId
amIChatAdmin: true
senderId: model.senderId
senderDisplayName: model.senderDisplayName
senderOptionalName: model.senderOptionalName
senderIsEnsVerified: model.senderEnsVerified
senderIsAdded: model.senderIsAdded
senderIcon: model.senderIcon
senderColorHash: model.senderColorHash
senderTrustStatus: model.senderTrustStatus
amISender: model.amISender
messageText: model.messageText
messageImage: model.messageImage
messageTimestamp: model.timestamp
messageOutgoingStatus: model.outgoingStatus
messageContentType: model.contentType
pinnedMessage: model.pinned
messagePinnedBy: model.pinnedBy
sticker: model.sticker
stickerPack: model.stickerPack
linkPreviewModel: model.linkPreviewModel
links: model.links
transactionParams: model.transactionParameters
quotedMessageText: model.quotedMessageParsedText
quotedMessageFrom: model.quotedMessageFrom
quotedMessageContentType: model.quotedMessageContentType
quotedMessageDeleted: model.quotedMessageDeleted
quotedMessageAuthorDetailsName: model.quotedMessageAuthorName
quotedMessageAuthorDetailsDisplayName: model.quotedMessageAuthorDisplayName
quotedMessageAuthorDetailsThumbnailImage: model.quotedMessageAuthorThumbnailImage
quotedMessageAuthorDetailsEnsVerified: model.quotedMessageAuthorEnsVerified
quotedMessageAuthorDetailsIsContact: model.quotedMessageAuthorIsContact
quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash
bridgeName: model.bridgeName
isViewMemberMessagesePopup: true
shouldRepeatHeader: true
}
MouseArea {
id: mouseArea
acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
root.chatCommunitySectionModule.openCommunityChatAndScrollToMessage(model.chatId, model.id)
Global.switchToCommunityChannelsView(root.chatCommunitySectionModule.getMySectionId())
root.chatCommunitySectionModule.openCommunityChatAndScrollToMessage(model.chatId, model.id)
root.closed()
}
}
}
}
}
footer: StatusDialogFooter {
id: footer
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Delete all messages by %1").arg(root.displayName)
enabled: communityMemberMessageListView.count > 0
type: StatusBaseButton.Type.Danger
onClicked: {
root.chatCommunitySectionModule.deleteCommunityMemberMessages(root.memberPubKey, "", "")
}
borderColor: "transparent"
}
StatusButton {
text: qsTr("Done")
onClicked: root.close()
}
}
}
}

View File

@ -26,3 +26,4 @@ TokenMasterActionPopup 1.0 TokenMasterActionPopup.qml
TokenPermissionsPopup 1.0 TokenPermissionsPopup.qml TokenPermissionsPopup 1.0 TokenPermissionsPopup.qml
TransferOwnershipPopup 1.0 TransferOwnershipPopup.qml TransferOwnershipPopup 1.0 TransferOwnershipPopup.qml
TransferOwnershipAlertPopup 1.0 TransferOwnershipAlertPopup.qml TransferOwnershipAlertPopup 1.0 TransferOwnershipAlertPopup.qml
CommunityMemberMessagesPopup 1.0 CommunityMemberMessagesPopup.qml

View File

@ -252,7 +252,7 @@ StatusSectionLayout {
mintPanel.openNewTokenForm(false/*Collectible owner token*/) mintPanel.openNewTokenForm(false/*Collectible owner token*/)
} }
onShardIndexEdited: if (root.community.shardIndex != shardIndex) { onShardIndexEdited: if (root.community.shardIndex !== shardIndex) {
root.chatCommunitySectionModule.setCommunityShard(shardIndex) root.chatCommunitySectionModule.setCommunityShard(shardIndex)
} }
} }
@ -277,6 +277,10 @@ StatusSectionLayout {
onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id) onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id)
onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(id, root.community.id) onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(id, root.community.id)
onDeclineRequestToJoin: root.rootStore.declineRequestToJoinCommunity(id, root.community.id) onDeclineRequestToJoin: root.rootStore.declineRequestToJoinCommunity(id, root.community.id)
onViewMemberMessagesClicked: {
root.rootStore.loadCommunityMemberMessages(root.community.id, pubKey)
Global.openCommunityMemberMessagesPopupRequested(root.rootStore, root.chatCommunitySectionModule, pubKey, displayName)
}
} }
PermissionsSettingsPanel { PermissionsSettingsPanel {

View File

@ -1413,6 +1413,15 @@ Item {
} }
} }
Connections {
target: Global
function onSwitchToCommunityChannelsView(communityId: string) {
if (communityId !== model.id)
return
chatLayoutComponent.currentIndex = 0
}
}
sendModalPopup: sendModal sendModalPopup: sendModal
emojiPopup: statusEmojiPopup.item emojiPopup: statusEmojiPopup.item
stickersPopup: statusStickersPopupLoader.item stickersPopup: statusStickersPopupLoader.item

View File

@ -86,6 +86,7 @@ QtObject {
Global.openFirstTokenReceivedPopup.connect(openFirstTokenReceivedPopup) Global.openFirstTokenReceivedPopup.connect(openFirstTokenReceivedPopup)
Global.openConfirmHideAssetPopup.connect(openConfirmHideAssetPopup) Global.openConfirmHideAssetPopup.connect(openConfirmHideAssetPopup)
Global.openConfirmHideCollectiblePopup.connect(openConfirmHideCollectiblePopup) Global.openConfirmHideCollectiblePopup.connect(openConfirmHideCollectiblePopup)
Global.openCommunityMemberMessagesPopupRequested.connect(openCommunityMemberMessagesPopup)
} }
property var currentPopup property var currentPopup
@ -362,6 +363,15 @@ QtObject {
openPopup(confirmHideCollectiblePopup, { collectibleSymbol, collectibleName, collectibleImage, isCommunityToken }) openPopup(confirmHideCollectiblePopup, { collectibleSymbol, collectibleName, collectibleImage, isCommunityToken })
} }
function openCommunityMemberMessagesPopup(store, chatCommunitySectionModule, memberPubKey, displayName) {
openPopup(communityMemberMessagesPopup, {
store: store,
chatCommunitySectionModule: chatCommunitySectionModule,
memberPubKey: memberPubKey,
displayName: displayName
})
}
readonly property list<Component> _components: [ readonly property list<Component> _components: [
Component { Component {
id: removeContactConfirmationDialog id: removeContactConfirmationDialog
@ -1135,6 +1145,12 @@ QtObject {
"") "")
} }
} }
},
Component {
id: communityMemberMessagesPopup
CommunityMemberMessagesPopup {
onClosed: destroy()
}
} }
] ]
} }

View File

@ -24,6 +24,7 @@ Loader {
property var usersStore property var usersStore
property var contactsStore property var contactsStore
property var chatContentModule property var chatContentModule
property var chatCommunitySectionModule
property string channelEmoji property string channelEmoji
@ -96,6 +97,7 @@ Loader {
// External behavior changers // External behavior changers
property bool isInPinnedPopup: false // The pinned popup limits the number of buttons shown property bool isInPinnedPopup: false // The pinned popup limits the number of buttons shown
property bool isViewMemberMessagesePopup: false // The view member messages popup limits the number of buttons
property bool disableHover: false // Used to force the HoverHandler to be active (useful for messages in popups) property bool disableHover: false // Used to force the HoverHandler to be active (useful for messages in popups)
property bool placeholderMessage: false property bool placeholderMessage: false
@ -261,7 +263,10 @@ 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.chatContentModule.chatDetails.canPostReactions
readonly property bool addReactionAllowed: !root.isInPinnedPopup &&
root.chatContentModule.chatDetails.canPostReactions &&
!root.isViewMemberMessagesePopup
function nextMessageHasHeader() { function nextMessageHasHeader() {
if(!root.nextMessageAsJsonObj) { if(!root.nextMessageAsJsonObj) {
@ -568,7 +573,7 @@ Loader {
Layout.bottomMargin: 16 Layout.bottomMargin: 16
messageTimestamp: root.messageTimestamp messageTimestamp: root.messageTimestamp
previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp
visible: text !== "" && !root.isInPinnedPopup visible: text !== "" && !root.isInPinnedPopup && !root.isViewMemberMessagesePopup
} }
StatusMessage { StatusMessage {
@ -910,7 +915,8 @@ Loader {
quickActions: [ quickActions: [
Loader { Loader {
active: d.addReactionAllowed && delegate.hovered active: d.addReactionAllowed && delegate.hovered && !root.isViewMemberMessagesePopup
visible: active visible: active
sourceComponent: StatusFlatRoundButton { sourceComponent: StatusFlatRoundButton {
width: d.chatButtonSize width: d.chatButtonSize
@ -925,7 +931,7 @@ Loader {
}, },
Loader { Loader {
active: !root.isInPinnedPopup && delegate.hovered && !delegate.hideQuickActions active: !root.isInPinnedPopup && delegate.hovered && !delegate.hideQuickActions
&& root.rootStore.permissionsStore.viewAndPostCriteriaMet && !root.isViewMemberMessagesePopup && root.rootStore.permissionsStore.viewAndPostCriteriaMet
visible: active visible: active
sourceComponent: StatusFlatRoundButton { sourceComponent: StatusFlatRoundButton {
objectName: "replyToMessageButton" objectName: "replyToMessageButton"
@ -941,7 +947,7 @@ Loader {
}, },
Loader { Loader {
active: !root.isInPinnedPopup && root.isText && !root.editModeOn && root.amISender && delegate.hovered && !delegate.hideQuickActions active: !root.isInPinnedPopup && root.isText && !root.editModeOn && root.amISender && delegate.hovered && !delegate.hideQuickActions
&& root.rootStore.permissionsStore.viewAndPostCriteriaMet && !root.isViewMemberMessagesePopup && root.rootStore.permissionsStore.viewAndPostCriteriaMet
visible: active visible: active
sourceComponent: StatusFlatRoundButton { sourceComponent: StatusFlatRoundButton {
objectName: "editMessageButton" objectName: "editMessageButton"
@ -969,6 +975,10 @@ Loader {
if (!root.rootStore.permissionsStore.viewAndPostCriteriaMet) if (!root.rootStore.permissionsStore.viewAndPostCriteriaMet)
return false; return false;
if (root.isViewMemberMessagesePopup) {
return false
}
const chatType = root.messageStore.chatType; const chatType = root.messageStore.chatType;
const pinMessageAllowedForMembers = root.messageStore.isPinMessageAllowedForMembers const pinMessageAllowedForMembers = root.messageStore.isPinMessageAllowedForMembers
@ -1007,7 +1017,7 @@ Loader {
} }
}, },
Loader { Loader {
active: !root.editModeOn && delegate.hovered && !delegate.hideQuickActions active: !root.editModeOn && delegate.hovered && !delegate.hideQuickActions && !root.isViewMemberMessagesePopup
visible: active visible: active
sourceComponent: StatusFlatRoundButton { sourceComponent: StatusFlatRoundButton {
objectName: "markAsUnreadButton" objectName: "markAsUnreadButton"
@ -1048,9 +1058,9 @@ Loader {
icon.name: "delete" icon.name: "delete"
type: StatusFlatRoundButton.Type.Tertiary type: StatusFlatRoundButton.Type.Tertiary
tooltip.text: qsTr("Delete") tooltip.text: qsTr("Delete")
onClicked: { onClicked: root.isViewMemberMessagesePopup
messageStore.warnAndDeleteMessage(root.messageId) ? root.chatCommunitySectionModule.deleteCommunityMemberMessages(root.senderId, root.messageId, root.chatId)
} : messageStore.warnAndDeleteMessage(root.messageId)
} }
} }
] ]

View File

@ -81,6 +81,7 @@ QtObject {
signal openSendModal(string address) signal openSendModal(string address)
signal switchToCommunity(string communityId) signal switchToCommunity(string communityId)
signal switchToCommunitySettings(string communityId) signal switchToCommunitySettings(string communityId)
signal switchToCommunityChannelsView(string communityId)
signal createCommunityPopupRequested(bool isDiscordImport) signal createCommunityPopupRequested(bool isDiscordImport)
signal importCommunityPopupRequested() signal importCommunityPopupRequested()
signal communityIntroPopupRequested(string communityId, string name, string introMessage, signal communityIntroPopupRequested(string communityId, string name, string introMessage,
@ -101,6 +102,7 @@ QtObject {
signal openDeleteSavedAddressesPopup(var params) signal openDeleteSavedAddressesPopup(var params)
signal openShowQRPopup(var params) signal openShowQRPopup(var params)
signal openSavedAddressActivityPopup(var params) signal openSavedAddressActivityPopup(var params)
signal openCommunityMemberMessagesPopupRequested(var store, var chatCommunitySectionModule, var memberPubKey, var displayName)
function openProfilePopup(publicKey, parentPopup, cb) { function openProfilePopup(publicKey, parentPopup, cb) {
root.openProfilePopupRequested(publicKey, parentPopup, cb) root.openProfilePopupRequested(publicKey, parentPopup, cb)

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 78bf40994a482e5bf46c4c67ae4deb16065581f8 Subproject commit ad342c8887b0cc6fd91cac73919f45ac951efca9