feat(desktop/communities): View community member messages functionality (#14002)
* feat(desktop/communities): View member messages functionality
This commit is contained in:
parent
a48b2532ae
commit
a586c6d352
|
@ -100,6 +100,7 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, communityId: st
|
|||
return msg_item_qobj.newMessageItem(msg_item.initItem(
|
||||
message.id,
|
||||
communityId, # we don't received community id via `activityCenterNotifications` api call
|
||||
message.chatId,
|
||||
message.responseTo,
|
||||
message.`from`,
|
||||
contactDetails.defaultDisplayName,
|
||||
|
|
|
@ -142,3 +142,6 @@ method setPermissionsCheckOngoing*(self: AccessInterface, value: bool) {.base.}
|
|||
|
||||
method getPermissionsCheckOngoing*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method scrollToMessage*(self: AccessInterface, messageId: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
|
@ -151,6 +151,7 @@ proc createMessageItemsFromMessageDtos(self: Module, messages: seq[MessageDto],
|
|||
|
||||
var item = initItem(
|
||||
message.id,
|
||||
message.chatId,
|
||||
message.communityId,
|
||||
message.responseTo,
|
||||
message.`from`,
|
||||
|
@ -239,6 +240,7 @@ proc createFetchMoreMessagesItem(self: Module): Item =
|
|||
result = initItem(
|
||||
FETCH_MORE_MESSAGES_MESSAGE_ID,
|
||||
communityId = "",
|
||||
chatId = "",
|
||||
responseToMessageWithId = "",
|
||||
senderId = chatDto.id,
|
||||
senderDisplayName = "",
|
||||
|
@ -306,6 +308,7 @@ proc createChatIdentifierItem(self: Module): Item =
|
|||
result = initItem(
|
||||
CHAT_IDENTIFIER_MESSAGE_ID,
|
||||
communityId = "",
|
||||
chatId = "",
|
||||
responseToMessageWithId = "",
|
||||
senderId = chatDto.id,
|
||||
senderDisplayName = chatName,
|
||||
|
@ -389,7 +392,7 @@ proc currentUserWalletContainsAddress(self: Module, address: string): bool =
|
|||
return false
|
||||
|
||||
method reevaluateViewLoadingState*(self: Module) =
|
||||
let loading = not self.initialMessagesLoaded or
|
||||
let loading = not self.initialMessagesLoaded or
|
||||
not self.firstUnseenMessageState.initialized or
|
||||
self.firstUnseenMessageState.fetching or
|
||||
self.view.getMessageSearchOngoing()
|
||||
|
|
|
@ -58,7 +58,7 @@ proc newModule*(delegate: delegate_interface.AccessInterface, events: EventEmitt
|
|||
messageService)
|
||||
result.moduleLoaded = false
|
||||
|
||||
result.inputAreaModule = input_area_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
|
||||
result.inputAreaModule = input_area_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
|
||||
chatService, communityService, contactService, gifService, messageService, settingsService)
|
||||
result.messagesModule = messages_module.newModule(result, events, sectionId, chatId, belongsToCommunity,
|
||||
contactService, communityService, chatService, messageService, mailserversService, sharedUrlsService)
|
||||
|
@ -174,6 +174,7 @@ proc buildPinnedMessageItem(self: Module, message: MessageDto, actionInitiatedBy
|
|||
item = pinned_msg_item.initItem(
|
||||
message.id,
|
||||
message.communityId,
|
||||
message.chatId,
|
||||
message.responseTo,
|
||||
message.`from`,
|
||||
contactDetails.defaultDisplayName,
|
||||
|
@ -411,7 +412,7 @@ method amIChatAdmin*(self: Module): bool =
|
|||
return false
|
||||
else:
|
||||
let communityDto = self.controller.getCommunityDetails()
|
||||
return communityDto.memberRole == MemberRole.Owner or
|
||||
return communityDto.memberRole == MemberRole.Owner or
|
||||
communityDto.memberRole == MemberRole.Admin or communityDto.memberRole == MemberRole.TokenMaster
|
||||
|
||||
method onUpdateViewOnlyPermissionsSatisfied*(self: Module, value: bool) =
|
||||
|
@ -425,3 +426,6 @@ method setPermissionsCheckOngoing*(self: Module, value: bool) =
|
|||
|
||||
method getPermissionsCheckOngoing*(self: Module): bool =
|
||||
self.view.getPermissionsCheckOngoing()
|
||||
|
||||
method scrollToMessage*(self: Module, messageId: string) =
|
||||
self.messagesModule.scrollToMessage(messageId)
|
|
@ -397,6 +397,20 @@ proc init*(self: Controller) =
|
|||
self.events.on(SIGNAL_MAILSERVER_HISTORY_REQUEST_COMPLETED) do(e:Args):
|
||||
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 =
|
||||
return self.isCommunitySection
|
||||
|
||||
|
@ -725,3 +739,14 @@ proc waitingOnNewCommunityOwnerToConfirmRequestToRejoin*(self: Controller, commu
|
|||
proc setCommunityShard*(self: Controller, shardIndex: int) =
|
||||
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)
|
||||
|
|
|
@ -404,3 +404,20 @@ method setCommunityShard*(self: AccessInterface, shardIndex: int) {.base.} =
|
|||
method setShardingInProgress*(self: AccessInterface, value: bool) {.base.} =
|
||||
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")
|
||||
|
|
|
@ -5,6 +5,9 @@ import ../io_interface as delegate_interface
|
|||
import view, controller, active_item
|
||||
import model as chats_model
|
||||
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_model as user_model
|
||||
import ../../shared_models/token_permissions_model
|
||||
|
@ -87,7 +90,7 @@ proc addOrUpdateChat(self: Module,
|
|||
sharedUrlsService: shared_urls_service.Service,
|
||||
setChatAsActive: bool = true,
|
||||
insertIntoModel: bool = true,
|
||||
): Item
|
||||
): chat_item.Item
|
||||
|
||||
proc newModule*(
|
||||
delegate: delegate_interface.AccessInterface,
|
||||
|
@ -120,6 +123,95 @@ proc newModule*(
|
|||
|
||||
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) =
|
||||
self.controller.delete
|
||||
self.view.delete
|
||||
|
@ -166,7 +258,7 @@ proc removeSubmodule(self: Module, chatId: string) =
|
|||
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)
|
||||
result = chat_item.initItem(
|
||||
id = category.id,
|
||||
|
@ -210,7 +302,7 @@ proc buildChatSectionUI(
|
|||
var selectedItemId = ""
|
||||
let sectionLastOpenChat = singletonInstance.localAccountSensitiveSettings.getSectionLastOpenChat(self.controller.getMySectionId())
|
||||
|
||||
var items: seq[Item] = @[]
|
||||
var items: seq[chat_item.Item] = @[]
|
||||
for categoryDto in channelGroup.categories:
|
||||
# Add items for the categories. We use a special type to identify categories
|
||||
items.add(self.addCategoryItem(categoryDto, channelGroup.memberRole, channelGroup.id))
|
||||
|
@ -544,7 +636,7 @@ proc addNewChat(
|
|||
sharedUrlsService: shared_urls_service.Service,
|
||||
setChatAsActive: bool = true,
|
||||
insertIntoModel: bool = true,
|
||||
): Item =
|
||||
): chat_item.Item =
|
||||
let hasNotification =chatDto.unviewedMessagesCount > 0
|
||||
let notificationsCount = chatDto.unviewedMentionsCount
|
||||
|
||||
|
@ -1262,7 +1354,7 @@ proc addOrUpdateChat(self: Module,
|
|||
sharedUrlsService: shared_urls_service.Service,
|
||||
setChatAsActive: bool = true,
|
||||
insertIntoModel: bool = true,
|
||||
): Item =
|
||||
): chat_item.Item =
|
||||
|
||||
let sectionId = self.controller.getMySectionId()
|
||||
if(belongsToCommunity and sectionId != chat.communityId or
|
||||
|
@ -1326,7 +1418,7 @@ method addOrUpdateChat*(self: Module,
|
|||
sharedUrlsService: shared_urls_service.Service,
|
||||
setChatAsActive: bool = true,
|
||||
insertIntoModel: bool = true,
|
||||
): Item =
|
||||
): chat_item.Item =
|
||||
result = self.addOrUpdateChat(
|
||||
chat,
|
||||
ChannelGroupDto(),
|
||||
|
@ -1430,3 +1522,33 @@ method setCommunityShard*(self: Module, shardIndex: int) =
|
|||
method setShardingInProgress*(self: Module, value: bool) =
|
||||
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)
|
|
@ -2,6 +2,7 @@ import NimQml, json, sequtils, strutils
|
|||
import model as chats_model
|
||||
import item, active_item
|
||||
import ../../shared_models/user_model as user_model
|
||||
import ../../shared_models/message_model as member_msg_model
|
||||
import ../../shared_models/token_permissions_model
|
||||
import io_interface
|
||||
|
||||
|
@ -32,6 +33,9 @@ QtObject:
|
|||
isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin: bool
|
||||
shardingInProgress: bool
|
||||
allChannelsAreHiddenBecauseNotPermitted: bool
|
||||
memberMessagesModel: member_msg_model.Model
|
||||
memberMessagesModelVariant: QVariant
|
||||
|
||||
|
||||
proc delete*(self: View) =
|
||||
self.model.delete
|
||||
|
@ -46,6 +50,8 @@ QtObject:
|
|||
self.editCategoryChannelsVariant.delete
|
||||
self.tokenPermissionsModel.delete
|
||||
self.tokenPermissionsVariant.delete
|
||||
self.memberMessagesModel.delete
|
||||
self.memberMessagesModelVariant.delete
|
||||
|
||||
self.QObject.delete
|
||||
|
||||
|
@ -71,6 +77,8 @@ QtObject:
|
|||
result.chatsLoaded = false
|
||||
result.communityMetrics = "[]"
|
||||
result.isWaitingOnNewCommunityOwnerToConfirmRequestToRejoin = false
|
||||
result.memberMessagesModel = member_msg_model.newModel()
|
||||
result.memberMessagesModelVariant = newQVariant(result.memberMessagesModel)
|
||||
|
||||
proc load*(self: View) =
|
||||
self.delegate.viewDidLoad()
|
||||
|
@ -508,4 +516,21 @@ QtObject:
|
|||
if (allAreHidden == self.allChannelsAreHiddenBecauseNotPermitted):
|
||||
return
|
||||
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)
|
||||
|
|
|
@ -13,6 +13,7 @@ type
|
|||
Item* = ref object
|
||||
id: string
|
||||
communityId: string
|
||||
chatId: string
|
||||
responseToMessageWithId: string
|
||||
senderId: string
|
||||
senderDisplayName: string
|
||||
|
@ -75,6 +76,7 @@ type
|
|||
proc initItem*(
|
||||
id,
|
||||
communityId,
|
||||
chatId,
|
||||
responseToMessageWithId,
|
||||
senderId,
|
||||
senderDisplayName,
|
||||
|
@ -128,6 +130,7 @@ proc initItem*(
|
|||
result = Item()
|
||||
result.id = id
|
||||
result.communityId = communityId
|
||||
result.chatId = chatId
|
||||
result.responseToMessageWithId = responseToMessageWithId
|
||||
result.senderId = senderId
|
||||
result.senderDisplayName = senderDisplayName
|
||||
|
@ -228,6 +231,7 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item =
|
|||
return initItem(
|
||||
id = "",
|
||||
communityId = "",
|
||||
chatId = "",
|
||||
responseToMessageWithId = "",
|
||||
senderId = "",
|
||||
senderDisplayName = "",
|
||||
|
@ -283,6 +287,7 @@ proc `$`*(self: Item): string =
|
|||
result = fmt"""Item(
|
||||
id: {$self.id},
|
||||
communityId: {$self.communityId},
|
||||
chatId: {$self.chatId},
|
||||
responseToMessageWithId: {self.responseToMessageWithId},
|
||||
senderId: {self.senderId},
|
||||
senderDisplayName: {$self.senderDisplayName},
|
||||
|
@ -320,6 +325,9 @@ proc id*(self: Item): string {.inline.} =
|
|||
proc communityId*(self: Item): string {.inline.} =
|
||||
self.communityId
|
||||
|
||||
proc chatId*(self: Item): string {.inline.} =
|
||||
self.chatId
|
||||
|
||||
proc responseToMessageWithId*(self: Item): string {.inline.} =
|
||||
self.responseToMessageWithId
|
||||
|
||||
|
@ -419,7 +427,7 @@ proc albumMessageIds*(self: Item): seq[string] {.inline.} =
|
|||
proc `albumMessageIds=`*(self: Item, value: seq[string]) {.inline.} =
|
||||
self.albumMessageIds = value
|
||||
|
||||
proc albumImagesCount*(self: Item): int {.inline.} =
|
||||
proc albumImagesCount*(self: Item): int {.inline.} =
|
||||
self.albumImagesCount
|
||||
|
||||
proc bridgeName*(self: Item): string {.inline.} =
|
||||
|
@ -516,6 +524,7 @@ proc toJsonNode*(self: Item): JsonNode =
|
|||
result = %* {
|
||||
"id": self.id,
|
||||
"communityId": self.communityId,
|
||||
"chatId": self.chatId,
|
||||
"responseToMessageWithId": self.responseToMessageWithId,
|
||||
"senderId": self.senderId,
|
||||
"senderDisplayName": self.senderDisplayName,
|
||||
|
@ -661,8 +670,8 @@ proc quotedMessageAlbumMessageImages*(self: Item): seq[string] {.inline.} =
|
|||
proc `quotedMessageAlbumMessageImages=`*(self: Item, value: seq[string]) {.inline.} =
|
||||
self.quotedMessageAlbumMessageImages = value
|
||||
|
||||
proc quotedMessageAlbumImagesCount*(self: Item): int {.inline.} =
|
||||
proc quotedMessageAlbumImagesCount*(self: Item): int {.inline.} =
|
||||
self.quotedMessageAlbumImagesCount
|
||||
|
||||
proc `quotedMessageAlbumImagesCount=`*(self: Item, value: int) {.inline.} =
|
||||
proc `quotedMessageAlbumImagesCount=`*(self: Item, value: int) {.inline.} =
|
||||
self.quotedMessageAlbumImagesCount = value
|
|
@ -16,6 +16,7 @@ type
|
|||
NextMsgIndex
|
||||
NextMsgTimestamp
|
||||
CommunityId
|
||||
ChatId
|
||||
ResponseToMessageWithId
|
||||
SenderId
|
||||
SenderDisplayName
|
||||
|
@ -123,6 +124,7 @@ QtObject:
|
|||
ModelRole.NextMsgIndex.int:"nextMsgIndex",
|
||||
ModelRole.NextMsgTimestamp.int:"nextMsgTimestamp",
|
||||
ModelRole.CommunityId.int:"communityId",
|
||||
ModelRole.ChatId.int:"chatId",
|
||||
ModelRole.ResponseToMessageWithId.int:"responseToMessageWithId",
|
||||
ModelRole.SenderId.int:"senderId",
|
||||
ModelRole.SenderDisplayName.int:"senderDisplayName",
|
||||
|
@ -231,6 +233,8 @@ QtObject:
|
|||
result = newQVariant(0)
|
||||
of ModelRole.CommunityId:
|
||||
result = newQVariant(item.communityId)
|
||||
of ModelRole.ChatId:
|
||||
result = newQVariant(item.chatId)
|
||||
of ModelRole.ResponseToMessageWithId:
|
||||
result = newQVariant(item.responseToMessageWithId)
|
||||
of ModelRole.SenderId:
|
||||
|
|
|
@ -186,7 +186,7 @@ type
|
|||
|
||||
const asyncGetFirstUnseenMessageIdForTaskArg: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[AsyncGetFirstUnseenMessageIdForTaskArg](argEncoded)
|
||||
|
||||
|
||||
let responseJson = %*{
|
||||
"messageId": "",
|
||||
"chatId": arg.chatId,
|
||||
|
@ -338,3 +338,34 @@ const asyncMarkMessageAsUnreadTask: Task = proc(argEncoded: string) {.gcsafe, ni
|
|||
responseJson["error"] = %e.msg
|
||||
|
||||
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)
|
||||
|
|
|
@ -211,7 +211,7 @@ proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage =
|
|||
var bridgeMessageObj: JsonNode
|
||||
if(jsonObj.getProp("bridgeMessage", bridgeMessageObj)):
|
||||
result.bridgeMessage = toBridgeMessage(bridgeMessageObj)
|
||||
|
||||
|
||||
var quotedImagesArr: JsonNode
|
||||
if jsonObj.getProp("albumImages", quotedImagesArr):
|
||||
for element in quotedImagesArr.getElems():
|
||||
|
@ -313,7 +313,7 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto =
|
|||
if jsonObj.getProp("statusLinkPreviews", statusLinkPreviewsArr):
|
||||
for element in statusLinkPreviewsArr.getElems():
|
||||
result.linkPreviews.add(element.toLinkPreview(false))
|
||||
|
||||
|
||||
var parsedTextArr: JsonNode
|
||||
if(jsonObj.getProp("parsedText", parsedTextArr) and parsedTextArr.kind == JArray):
|
||||
for pTextObj in parsedTextArr:
|
||||
|
|
|
@ -64,6 +64,7 @@ const SIGNAL_URLS_UNFURLED* = "urlsUnfurled"
|
|||
const SIGNAL_GET_MESSAGE_FINISHED* = "getMessageFinished"
|
||||
const SIGNAL_URLS_UNFURLING_PLAN_READY* = "urlsUnfurlingPlanReady"
|
||||
const SIGNAL_MESSAGE_MARKED_AS_UNREAD* = "messageMarkedAsUnread"
|
||||
const SIGNAL_COMMUNITY_MEMBER_ALL_MESSAGES* = "communityMemberAllMessages"
|
||||
|
||||
include async_tasks
|
||||
|
||||
|
@ -117,6 +118,7 @@ type
|
|||
deletedBy*: string
|
||||
|
||||
MessagesDeletedArgs* = ref object of Args
|
||||
communityId*: string
|
||||
deletedMessages*: Table[string, seq[string]]
|
||||
|
||||
MessageDeliveredArgs* = ref object of Args
|
||||
|
@ -154,6 +156,10 @@ type
|
|||
message*: MessageDto
|
||||
error*: string
|
||||
|
||||
CommunityMemberMessagesArgs* = ref object of Args
|
||||
communityId*: string
|
||||
messages*: seq[MessageDto]
|
||||
|
||||
QtObject:
|
||||
type Service* = ref object of QObject
|
||||
events: EventEmitter
|
||||
|
@ -274,6 +280,17 @@ QtObject:
|
|||
|
||||
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]) =
|
||||
# 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
|
||||
|
@ -358,8 +375,8 @@ QtObject:
|
|||
let data = MessageRemovedArgs(chatId: rm.chatId, messageId: rm.messageId, deletedBy: rm.deletedBy)
|
||||
self.events.emit(SIGNAL_MESSAGE_REMOVED, data)
|
||||
|
||||
proc handleDeletedMessagesUpdate(self: Service, deletedMessages: Table[string, seq[string]]) =
|
||||
let data = MessagesDeletedArgs(deletedMessages: deletedMessages)
|
||||
proc handleDeletedMessagesUpdate(self: Service, deletedMessages: Table[string, seq[string]], communityId: string) =
|
||||
let data = MessagesDeletedArgs(deletedMessages: deletedMessages, communityId: communityId)
|
||||
self.events.emit(SIGNAL_MESSAGES_DELETED, data)
|
||||
|
||||
proc handleEmojiReactionsUpdate(self: Service, emojiReactions: seq[ReactionDto]) =
|
||||
|
@ -430,7 +447,7 @@ QtObject:
|
|||
self.handleRemovedMessagesUpdate(receivedData.removedMessages)
|
||||
# Handling deleted messages updates
|
||||
if (receivedData.deletedMessages.len > 0):
|
||||
self.handleDeletedMessagesUpdate(receivedData.deletedMessages)
|
||||
self.handleDeletedMessagesUpdate(receivedData.deletedMessages, "")
|
||||
# Handling emoji reactions updates
|
||||
if (receivedData.emojiReactions.len > 0):
|
||||
self.handleEmojiReactionsUpdate(receivedData.emojiReactions)
|
||||
|
@ -542,6 +559,29 @@ QtObject:
|
|||
|
||||
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) =
|
||||
try:
|
||||
let response = status_go.addReaction(chatId, messageId, emojiId)
|
||||
|
@ -1147,3 +1187,26 @@ proc resendChatMessage*(self: Service, messageId: string): string =
|
|||
except Exception as e:
|
||||
error "error: ", procName="resendChatMessage", errName = e.name, errDesription = 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
|
|
@ -87,3 +87,24 @@ proc getTextURLsToUnfurl*(text: string): RpcResponse[JsonNode] =
|
|||
proc unfurlUrls*(urls: seq[string]): RpcResponse[JsonNode] =
|
||||
let payload = %*[urls]
|
||||
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)
|
|
@ -329,6 +329,10 @@ QtObject {
|
|||
chatCommunitySectionModule.removeUserFromCommunity(pubKey);
|
||||
}
|
||||
|
||||
function loadCommunityMemberMessages(communityId, pubKey) {
|
||||
chatCommunitySectionModule.loadCommunityMemberMessages(communityId, pubKey);
|
||||
}
|
||||
|
||||
function banUserFromCommunity(pubKey, deleteAllMessages) {
|
||||
chatCommunitySectionModule.banUserFromCommunity(pubKey, deleteAllMessages);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ SettingsPage {
|
|||
signal unbanUserClicked(string id)
|
||||
signal acceptRequestToJoin(string id)
|
||||
signal declineRequestToJoin(string id)
|
||||
signal viewMemberMessagesClicked(string pubKey, string displayName)
|
||||
|
||||
function goTo(tab: int) {
|
||||
if(root.contentItem) {
|
||||
|
@ -127,6 +128,8 @@ SettingsPage {
|
|||
kickBanPopup.userId = id
|
||||
kickBanPopup.open()
|
||||
}
|
||||
|
||||
onViewMemberMessagesClicked: root.viewMemberMessagesClicked(pubKey, displayName)
|
||||
}
|
||||
|
||||
MembersTabPanel {
|
||||
|
@ -182,6 +185,7 @@ SettingsPage {
|
|||
Layout.fillHeight: true
|
||||
|
||||
onUnbanUserClicked: root.unbanUserClicked(id)
|
||||
onViewMemberMessagesClicked: root.viewMemberMessagesClicked(pubKey, displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ Item {
|
|||
signal kickUserClicked(string id, string name)
|
||||
signal banUserClicked(string id, string name)
|
||||
signal unbanUserClicked(string id)
|
||||
signal viewMemberMessagesClicked(string pubKey, string displayName)
|
||||
|
||||
signal acceptRequestToJoin(string id)
|
||||
signal declineRequestToJoin(string id)
|
||||
|
@ -94,6 +95,10 @@ Item {
|
|||
readonly property bool tabIsShowingRejectButton: root.panelType === MembersTabPanel.TabType.PendingRequests
|
||||
readonly property bool tabIsShowingAcceptButton: root.panelType === MembersTabPanel.TabType.PendingRequests ||
|
||||
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
|
||||
readonly property bool isPending: model.membershipRequestState === Constants.CommunityMembershipRequestState.Pending
|
||||
|
@ -130,6 +135,7 @@ Item {
|
|||
}
|
||||
}
|
||||
readonly property bool showOnHover: isHovered && ctaAllowed
|
||||
readonly property bool canDeleteMessages: itsMe || model.memberRole !== Constants.memberRole.owner
|
||||
|
||||
/// Button visibility ///
|
||||
readonly property bool acceptButtonVisible: tabIsShowingAcceptButton && (isPending || isRejected || isRejectedPending || isAcceptedPending) && showOnHover
|
||||
|
@ -141,6 +147,9 @@ Item {
|
|||
readonly property bool kickPendingButtonVisible: tabIsShowingKickBanButtons && isKickPending
|
||||
readonly property bool banPendingButtonVisible: tabIsShowingKickBanButtons && isBanPending
|
||||
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 ///
|
||||
readonly property bool isPendingState: isAcceptedPending || isRejectedPending || isBanPending || isUnbanPending || isKickPending
|
||||
|
@ -179,6 +188,24 @@ Item {
|
|||
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 {
|
||||
id: kickButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
@ -204,6 +231,8 @@ Item {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: unbanButtonVisible
|
||||
text: qsTr("Unban")
|
||||
type: StatusBaseButton.Type.Danger
|
||||
size: StatusBaseButton.Size.Small
|
||||
onClicked: root.unbanUserClicked(model.pubKey)
|
||||
},
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,3 +26,4 @@ TokenMasterActionPopup 1.0 TokenMasterActionPopup.qml
|
|||
TokenPermissionsPopup 1.0 TokenPermissionsPopup.qml
|
||||
TransferOwnershipPopup 1.0 TransferOwnershipPopup.qml
|
||||
TransferOwnershipAlertPopup 1.0 TransferOwnershipAlertPopup.qml
|
||||
CommunityMemberMessagesPopup 1.0 CommunityMemberMessagesPopup.qml
|
||||
|
|
|
@ -252,7 +252,7 @@ StatusSectionLayout {
|
|||
mintPanel.openNewTokenForm(false/*Collectible owner token*/)
|
||||
}
|
||||
|
||||
onShardIndexEdited: if (root.community.shardIndex != shardIndex) {
|
||||
onShardIndexEdited: if (root.community.shardIndex !== shardIndex) {
|
||||
root.chatCommunitySectionModule.setCommunityShard(shardIndex)
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +277,10 @@ StatusSectionLayout {
|
|||
onUnbanUserClicked: root.rootStore.unbanUserFromCommunity(id)
|
||||
onAcceptRequestToJoin: root.rootStore.acceptRequestToJoinCommunity(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 {
|
||||
|
|
|
@ -1413,6 +1413,15 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Global
|
||||
function onSwitchToCommunityChannelsView(communityId: string) {
|
||||
if (communityId !== model.id)
|
||||
return
|
||||
chatLayoutComponent.currentIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
sendModalPopup: sendModal
|
||||
emojiPopup: statusEmojiPopup.item
|
||||
stickersPopup: statusStickersPopupLoader.item
|
||||
|
|
|
@ -86,6 +86,7 @@ QtObject {
|
|||
Global.openFirstTokenReceivedPopup.connect(openFirstTokenReceivedPopup)
|
||||
Global.openConfirmHideAssetPopup.connect(openConfirmHideAssetPopup)
|
||||
Global.openConfirmHideCollectiblePopup.connect(openConfirmHideCollectiblePopup)
|
||||
Global.openCommunityMemberMessagesPopupRequested.connect(openCommunityMemberMessagesPopup)
|
||||
}
|
||||
|
||||
property var currentPopup
|
||||
|
@ -362,6 +363,15 @@ QtObject {
|
|||
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: [
|
||||
Component {
|
||||
id: removeContactConfirmationDialog
|
||||
|
@ -1135,6 +1145,12 @@ QtObject {
|
|||
"")
|
||||
}
|
||||
}
|
||||
},
|
||||
Component {
|
||||
id: communityMemberMessagesPopup
|
||||
CommunityMemberMessagesPopup {
|
||||
onClosed: destroy()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Loader {
|
|||
property var usersStore
|
||||
property var contactsStore
|
||||
property var chatContentModule
|
||||
property var chatCommunitySectionModule
|
||||
|
||||
property string channelEmoji
|
||||
|
||||
|
@ -96,6 +97,7 @@ Loader {
|
|||
|
||||
// External behavior changers
|
||||
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 placeholderMessage: false
|
||||
|
||||
|
@ -261,7 +263,10 @@ Loader {
|
|||
property string activeMessage
|
||||
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() {
|
||||
if(!root.nextMessageAsJsonObj) {
|
||||
|
@ -568,7 +573,7 @@ Loader {
|
|||
Layout.bottomMargin: 16
|
||||
messageTimestamp: root.messageTimestamp
|
||||
previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp
|
||||
visible: text !== "" && !root.isInPinnedPopup
|
||||
visible: text !== "" && !root.isInPinnedPopup && !root.isViewMemberMessagesePopup
|
||||
}
|
||||
|
||||
StatusMessage {
|
||||
|
@ -910,7 +915,8 @@ Loader {
|
|||
|
||||
quickActions: [
|
||||
Loader {
|
||||
active: d.addReactionAllowed && delegate.hovered
|
||||
active: d.addReactionAllowed && delegate.hovered && !root.isViewMemberMessagesePopup
|
||||
|
||||
visible: active
|
||||
sourceComponent: StatusFlatRoundButton {
|
||||
width: d.chatButtonSize
|
||||
|
@ -925,7 +931,7 @@ Loader {
|
|||
},
|
||||
Loader {
|
||||
active: !root.isInPinnedPopup && delegate.hovered && !delegate.hideQuickActions
|
||||
&& root.rootStore.permissionsStore.viewAndPostCriteriaMet
|
||||
&& !root.isViewMemberMessagesePopup && root.rootStore.permissionsStore.viewAndPostCriteriaMet
|
||||
visible: active
|
||||
sourceComponent: StatusFlatRoundButton {
|
||||
objectName: "replyToMessageButton"
|
||||
|
@ -941,7 +947,7 @@ Loader {
|
|||
},
|
||||
Loader {
|
||||
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
|
||||
sourceComponent: StatusFlatRoundButton {
|
||||
objectName: "editMessageButton"
|
||||
|
@ -969,6 +975,10 @@ Loader {
|
|||
if (!root.rootStore.permissionsStore.viewAndPostCriteriaMet)
|
||||
return false;
|
||||
|
||||
if (root.isViewMemberMessagesePopup) {
|
||||
return false
|
||||
}
|
||||
|
||||
const chatType = root.messageStore.chatType;
|
||||
const pinMessageAllowedForMembers = root.messageStore.isPinMessageAllowedForMembers
|
||||
|
||||
|
@ -1007,7 +1017,7 @@ Loader {
|
|||
}
|
||||
},
|
||||
Loader {
|
||||
active: !root.editModeOn && delegate.hovered && !delegate.hideQuickActions
|
||||
active: !root.editModeOn && delegate.hovered && !delegate.hideQuickActions && !root.isViewMemberMessagesePopup
|
||||
visible: active
|
||||
sourceComponent: StatusFlatRoundButton {
|
||||
objectName: "markAsUnreadButton"
|
||||
|
@ -1048,9 +1058,9 @@ Loader {
|
|||
icon.name: "delete"
|
||||
type: StatusFlatRoundButton.Type.Tertiary
|
||||
tooltip.text: qsTr("Delete")
|
||||
onClicked: {
|
||||
messageStore.warnAndDeleteMessage(root.messageId)
|
||||
}
|
||||
onClicked: root.isViewMemberMessagesePopup
|
||||
? root.chatCommunitySectionModule.deleteCommunityMemberMessages(root.senderId, root.messageId, root.chatId)
|
||||
: messageStore.warnAndDeleteMessage(root.messageId)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -81,6 +81,7 @@ QtObject {
|
|||
signal openSendModal(string address)
|
||||
signal switchToCommunity(string communityId)
|
||||
signal switchToCommunitySettings(string communityId)
|
||||
signal switchToCommunityChannelsView(string communityId)
|
||||
signal createCommunityPopupRequested(bool isDiscordImport)
|
||||
signal importCommunityPopupRequested()
|
||||
signal communityIntroPopupRequested(string communityId, string name, string introMessage,
|
||||
|
@ -101,6 +102,7 @@ QtObject {
|
|||
signal openDeleteSavedAddressesPopup(var params)
|
||||
signal openShowQRPopup(var params)
|
||||
signal openSavedAddressActivityPopup(var params)
|
||||
signal openCommunityMemberMessagesPopupRequested(var store, var chatCommunitySectionModule, var memberPubKey, var displayName)
|
||||
|
||||
function openProfilePopup(publicKey, parentPopup, cb) {
|
||||
root.openProfilePopupRequested(publicKey, parentPopup, cb)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 78bf40994a482e5bf46c4c67ae4deb16065581f8
|
||||
Subproject commit ad342c8887b0cc6fd91cac73919f45ac951efca9
|
Loading…
Reference in New Issue