refactor(@desktop/chat-messages): `MessageContextMenuView` component updated

This commit is contained in:
Sale Djenic 2021-12-14 15:19:55 +01:00
parent 42504ad4eb
commit b6b6d6b6c7
24 changed files with 365 additions and 318 deletions

View File

@ -94,4 +94,7 @@ method getContactById*(self: Controller, contactId: string): ContactsDto =
method getContactNameAndImage*(self: Controller, contactId: string):
tuple[name: string, image: string, isIdenticon: bool] =
return self.contactService.getContactNameAndImage(contactId)
return self.contactService.getContactNameAndImage(contactId)
method getNumOfPinnedMessages*(self: Controller): int =
return self.messageService.getNumOfPinnedMessages(self.chatId)

View File

@ -38,4 +38,7 @@ method getContactById*(self: AccessInterface, contactId: string): ContactsDto {.
method getContactNameAndImage*(self: AccessInterface, contactId: string):
tuple[name: string, image: string, isIdenticon: bool] {.base.} =
raise newException(ValueError, "No implementation available")
method getNumOfPinnedMessages*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -71,8 +71,6 @@ proc createChatIdentifierItem(self: Module): Item =
result = initItem(CHAT_IDENTIFIER_MESSAGE_ID, "", chatDto.id, chatName, "", chatIcon, isIdenticon, false, "", "", "",
true, 0, ContentType.ChatIdentifier, -1)
result.chatColorThisMessageBelongsTo = chatDto.color
result.chatTypeThisMessageBelongsTo = chatDto.chatType.int
method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: seq[ReactionDto],
pinnedMessages: seq[PinnedMessageDto]) =
@ -136,4 +134,18 @@ method pinUnpinMessage*(self: Module, messageId: string, pin: bool) =
self.controller.pinUnpinMessage(messageId, pin)
method onPinUnpinMessage*(self: Module, messageId: string, pin: bool) =
self.view.model().pinUnpinMessage(messageId, pin)
self.view.model().pinUnpinMessage(messageId, pin)
method getChatType*(self: Module): int =
let chatDto = self.controller.getChatDetails()
return chatDto.chatType.int
method getChatColor*(self: Module): string =
let chatDto = self.controller.getChatDetails()
return chatDto.color
method amIChatAdmin*(self: Module): bool =
return false
method getNumberOfPinnedMessages*(self: Module): int =
return self.controller.getNumOfPinnedMessages()

View File

@ -9,4 +9,16 @@ method pinUnpinMessage*(self: AccessInterface, messageId: string, pin: bool) {.b
method getNamesReactedWithEmojiIdForMessageId*(self: AccessInterface, messageId: string, emojiId: int): seq[string]
{.base.} =
raise newException(ValueError, "No implementation available")
method getChatType*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")
method getChatColor*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method amIChatAdmin*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getNumberOfPinnedMessages*(self: AccessInterface): int {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -55,4 +55,16 @@ QtObject:
let jsonObj = self.model.getMessageByIndexAsJson(index)
if(jsonObj.isNil):
return ""
return $jsonObj
return $jsonObj
proc getChatType*(self: View): int {.slot.} =
return self.delegate.getChatType()
proc getChatColor*(self: View): string {.slot.} =
return self.delegate.getChatColor()
proc amIChatAdmin*(self: View): bool {.slot.} =
return self.delegate.amIChatAdmin()
proc getNumberOfPinnedMessages*(self: View): int {.slot.} =
return self.delegate.getNumberOfPinnedMessages()

View File

@ -41,9 +41,6 @@ type
reactions: OrderedTable[int, seq[tuple[publicKey: string, reactionId: string]]] # [emojiId, list of [user publicKey reacted with the emojiId, reaction id]]
reactionIds: seq[string]
pinned: bool
# used in case of ContentType.ChatIdentifier only
chatTypeThisMessageBelongsTo: int
chatColorThisMessageBelongsTo: string
proc initItem*(id, responseToMessageWithId, senderId, senderDisplayName, senderLocalName, senderIcon: string,
isSenderIconIdenticon, amISender: bool, outgoingStatus, text, image: string, seen: bool, timestamp: int64,
@ -82,8 +79,6 @@ proc `$`*(self: Item): string =
timestamp:{$self.timestamp},
contentType:{$self.contentType.int},
messageType:{$self.messageType},
chatTypeThisMessageBelongsTo:{self.chatTypeThisMessageBelongsTo},
chatColorThisMessageBelongsTo:{self.chatColorThisMessageBelongsTo},
pinned:{$self.pinned}
)"""
@ -144,19 +139,6 @@ proc pinned*(self: Item): bool {.inline.} =
proc `pinned=`*(self: Item, value: bool) {.inline.} =
self.pinned = value
proc chatTypeThisMessageBelongsTo*(self: Item): int {.inline.} =
self.chatTypeThisMessageBelongsTo
proc `chatTypeThisMessageBelongsTo=`*(self: Item, value: int) {.inline.} =
self.chatTypeThisMessageBelongsTo = value
proc chatColorThisMessageBelongsTo*(self: Item): string {.inline.} =
self.chatColorThisMessageBelongsTo
proc `chatColorThisMessageBelongsTo=`*(self: Item, value: string) {.inline.} =
self.chatColorThisMessageBelongsTo = value
proc shouldAddReaction*(self: Item, emojiId: int, publicKey: string): bool =
for k, values in self.reactions:
if(k != emojiId):

View File

@ -25,8 +25,6 @@ type
# GapTo
Pinned
CountsForReactions
ChatTypeThisMessageBelongsTo
ChatColorThisMessageBelongsTo
QtObject:
type
@ -83,8 +81,6 @@ QtObject:
# ModelRole.GapTo.int:"gapTo",
ModelRole.Pinned.int:"pinned",
ModelRole.CountsForReactions.int:"countsForReactions",
ModelRole.ChatTypeThisMessageBelongsTo.int:"chatTypeThisMessageBelongsTo",
ModelRole.ChatColorThisMessageBelongsTo.int:"chatColorThisMessageBelongsTo",
}.toTable
method data(self: Model, index: QModelIndex, role: int): QVariant =
@ -140,10 +136,6 @@ QtObject:
result = newQVariant(item.pinned)
of ModelRole.CountsForReactions:
result = newQVariant($(%* item.getCountsForReactions))
of ModelRole.ChatTypeThisMessageBelongsTo:
result = newQVariant(item.chatTypeThisMessageBelongsTo)
of ModelRole.ChatColorThisMessageBelongsTo:
result = newQVariant(item.chatColorThisMessageBelongsTo)
proc findIndexForMessageId(self: Model, messageId: string): int =
for i in 0 ..< self.items.len:

View File

@ -52,6 +52,7 @@ QtObject:
threadpool: ThreadPool
msgCursor: Table[string, string]
pinnedMsgCursor: Table[string, string]
numOfPinnedMessagesPerChat: Table[string, int] # [chat_id, num_of_pinned_messages]
proc delete*(self: Service) =
self.QObject.delete
@ -111,6 +112,9 @@ QtObject:
if(responseObj.getProp("pinnedMessages", pinnedMsgArr)):
pinnedMessages = map(pinnedMsgArr.getElems(), proc(x: JsonNode): PinnedMessageDto = x.toPinnedMessageDto())
# set initial number of pinned messages
self.numOfPinnedMessagesPerChat[chatId] = pinnedMessages.len
# handling reactions
var reactionsArr: JsonNode
var reactions: seq[ReactionDto]
@ -198,9 +202,11 @@ QtObject:
var pinned = false
if(pinMessagesObj.getProp("pinned", pinned)):
if(pinned and pin):
self.numOfPinnedMessagesPerChat[chatId] = self.numOfPinnedMessagesPerChat[chatId] + 1
self.events.emit(SIGNAL_MESSAGE_PINNED, data)
else:
if(not pinned and not pin):
self.numOfPinnedMessagesPerChat[chatId] = self.numOfPinnedMessagesPerChat[chatId] - 1
self.events.emit(SIGNAL_MESSAGE_UNPINNED, data)
except Exception as e:
@ -359,4 +365,7 @@ QtObject:
messagesIds: messagesIds
)
self.threadpool.start(arg)
self.threadpool.start(arg)
proc getNumOfPinnedMessages*(self: Service, chatId: string): int =
return self.numOfPinnedMessagesPerChat[chatId]

View File

@ -97,12 +97,8 @@ StatusAppThreePanelLayout {
CommunityUserListPanel {
messageContextMenu: quickActionMessageOptionsMenu
usersModule: {
if(chatCommunitySectionModule.activeItem.isSubItemActive)
chatCommunitySectionModule.prepareChatContentModuleForChatId(chatCommunitySectionModule.activeItem.activeSubItem.id)
else
chatCommunitySectionModule.prepareChatContentModuleForChatId(chatCommunitySectionModule.activeItem.id)
return chatCommunitySectionModule.getChatContentModule().usersModule
let chatContentModule = currentChatContentModule()
return chatContentModule.usersModule
}
}
}
@ -112,8 +108,8 @@ StatusAppThreePanelLayout {
UserListPanel {
messageContextMenu: quickActionMessageOptionsMenu
usersModule: {
chatCommunitySectionModule.prepareChatContentModuleForChatId(chatCommunitySectionModule.activeItem.id)
return chatCommunitySectionModule.getChatContentModule().usersModule
let chatContentModule = currentChatContentModule()
return chatContentModule.usersModule
}
}
}
@ -178,15 +174,13 @@ StatusAppThreePanelLayout {
MessageContextMenuView {
id: quickActionMessageOptionsMenu
chatSectionModule: root.chatCommunitySectionModule
// Not Refactored
store: root.rootStore
// reactionModel: root.rootStore.emojiReactionsModel
onOpenProfileClicked: {
openProfilePopup(displayName, publicKey, icon, "", displayName)
}
onCreateOneToOneChat: {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
root.chatCommunitySectionModule.createOneToOneChat(chatId, ensName)
}
}
}
/*##^##
Designer {
D{i:0;formeditorColor:"#ffffff";formeditorZoom:1.25;height:770;width:1152}
}
##^##*/

View File

@ -17,11 +17,12 @@ Item {
property string publicKey: ""
property string name: ""
property string identicon: ""
property string icon: ""
property bool isIdenticon: true
property int userStatus: Constants.userStatus.offline
property var messageContextMenu
property bool enableMouseArea: true
property bool hovered: false
property color color: {
if (wrapper.hovered) {
return Style.current.menuBackgroundHover
@ -44,7 +45,7 @@ Item {
image: StatusImageSettings {
width: 28
height: 28
source: wrapper.identicon
source: wrapper.icon
isIdenticon: wrapper.isIdenticon
}
icon: StatusIconSettings {
@ -106,15 +107,21 @@ Item {
onClicked: {
if (mouse.button === Qt.LeftButton) {
//TODO remove dynamic scoping
openProfilePopup(wrapper.name, wrapper.publicKey, wrapper.identicon, "", wrapper.name);
openProfilePopup(wrapper.name, wrapper.publicKey, wrapper.icon, "", wrapper.name);
}
else if (mouse.button === Qt.RightButton && !!messageContextMenu) {
// Set parent, X & Y positions for the messageContextMenu
messageContextMenu.parent = rectangle
messageContextMenu.setXPosition = function() { return 0}
messageContextMenu.setYPosition = function() { return rectangle.height}
messageContextMenu.isProfile = true;
messageContextMenu.show(wrapper.name, wrapper.publicKey, wrapper.identicon, "", wrapper.name)
messageContextMenu.isProfile = true
messageContextMenu.myPublicKey = userProfile.pubKey
messageContextMenu.selectedUserPublicKey = wrapper.publicKey
messageContextMenu.selectedUserDisplayName = wrapper.name
messageContextMenu.selectedUserIcon = wrapper.icon
messageContextMenu.isSelectedUserIconIdenticon = wrapper.isIdenticon
messageContextMenu.popup()
}
}
}

View File

@ -50,7 +50,7 @@ Item {
delegate: UserDelegate {
publicKey: model.id
name: model.name
identicon: model.icon
icon: model.icon
isIdenticon: model.isIdenticon
userStatus: model.onlineStatus
messageContextMenu: root.messageContextMenu

View File

@ -55,7 +55,7 @@ Item {
delegate: UserDelegate {
publicKey: model.id
name: model.name
identicon: model.icon
icon: model.icon
isIdenticon: model.isIdenticon
userStatus: model.onlineStatus
messageContextMenu: root.messageContextMenu

View File

@ -215,9 +215,9 @@ ModalPopup {
id: msgContextMenu
pinnedPopup: true
pinnedMessage: true
chatSectionModule: popup.chatSectionModule
store: popup.rootStore
reactionModel: popup.rootStore.emojiReactionsModel
// chatSectionModule: popup.chatSectionModule
// store: popup.rootStore
// reactionModel: popup.rootStore.emojiReactionsModel
onShouldCloseParentPopup: {
popup.close()
}

View File

@ -1,4 +1,5 @@
import QtQuick 2.13
import utils 1.0
QtObject {
id: root
@ -32,4 +33,46 @@ QtObject {
return obj
}
function getChatType () {
if(!messageModule)
return Constants.chatType.unknown
return messageModule.getChatType()
}
function getChatColor () {
if(!messageModule)
return Style.current.blue
return messageModule.getChatColor()
}
function amIChatAdmin () {
if(!messageModule)
return false
return messageModule.amIChatAdmin()
}
function getNumberOfPinnedMessages () {
if(!messageModule)
return 0
return messageModule.getNumberOfPinnedMessages()
}
function pinMessage (messageId) {
if(!messageModule)
return
return messageModule.pinMessage(messageId)
}
function unpinMessage (messageId) {
if(!messageModule)
return
return messageModule.unpinMessage(messageId)
}
}

View File

@ -123,28 +123,6 @@ Item {
}
}
MessageContextMenuView {
id: contextmenu
chatSectionModule: root.parentModule
store: root.rootStore
reactionModel: root.rootStore.emojiReactionsModel
}
StatusImageModal {
id: imagePopup
onClicked: {
if (button === Qt.LeftButton) {
imagePopup.close()
}
else if(button === Qt.RightButton) {
contextmenu.imageSource = imagePopup.imageSource
contextmenu.hideEmojiPicker = true
contextmenu.isRightClickOnImage = true;
contextmenu.show()
}
}
}
StackLayout {
anchors.fill: parent
currentIndex: {

View File

@ -178,6 +178,38 @@ ColumnLayout {
}
}
MessageStore{
id: messageStore
messageModule: chatContentModule.messagesModule
}
MessageContextMenuView {
id: contextmenu
reactionModel: root.rootStore.emojiReactionsModel
onPinMessage: {
messageStore.pinMessage(messageId)
}
onUnpinMessage: {
messageStore.unpinMessage(messageId)
}
}
StatusImageModal {
id: imagePopup
onClicked: {
if (button === Qt.LeftButton) {
imagePopup.close()
}
else if(button === Qt.RightButton) {
contextmenu.imageSource = imagePopup.imageSource
contextmenu.hideEmojiPicker = true
contextmenu.isRightClickOnImage = true;
contextmenu.popup()
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
@ -189,9 +221,7 @@ ColumnLayout {
Layout.fillHeight: true
store: root.rootStore
messageContextMenuInst: contextmenu
messageStore: MessageStore{
messageModule: chatContentModule.messagesModule
}
messageStore: messageStore
}
Item {

View File

@ -296,6 +296,7 @@ Item {
id: msgDelegate
messageStore: root.messageStore
messageContextMenu: messageContextMenuInst
messageId: model.id
responseToMessageWithId: model.responseToMessageWithId
@ -312,10 +313,6 @@ Item {
messageContentType: model.contentType
pinnedMessage: model.pinned
// Used only in case of ChatIdentifier
chatTypeThisMessageBelongsTo: model.chatTypeThisMessageBelongsTo
chatColorThisMessageBelongsTo: model.chatColorThisMessageBelongsTo
// This is possible since we have all data loaded before we load qml.
// When we fetch messages to fulfill a gap we have to set them at once.
prevMessageIndex: index - 1

View File

@ -220,12 +220,12 @@ ScrollView {
// messageStore.timeout = model.timeout;
// messageStore.messageContextMenu = msgCntxtMenu;
// }
MessageContextMenuView {
id: msgCntxtMenu
store: root.store
chatSectionModule: root.chatSectionModule
reactionModel: EmojiReactions { }
}
// MessageContextMenuView {
// id: msgCntxtMenu
// store: root.store
// chatSectionModule: root.chatSectionModule
// reactionModel: EmojiReactions { }
// }
}
}

View File

@ -4,6 +4,7 @@ import utils 1.0
import shared 1.0
MouseArea {
id: mouseArea
z: 50
enabled: !placeholderMessage
@ -23,16 +24,17 @@ MouseArea {
onClicked: {
if (isActivityCenterMessage) {
return clickMessage(false, isSticker, false)
mouseArea.clickMessage(false, isSticker, false)
return
}
if (mouse.button === Qt.RightButton) {
if (!!messageContextMenu) {
if (!!mouseArea.messageContextMenu) {
// Set parent, X & Y positions for the messageContextMenu
messageContextMenu.parent = root
messageContextMenu.setXPosition = function() { return (mouse.x)};
messageContextMenu.setYPosition = function() { return (mouse.y)};
}
clickMessage(false, isSticker, false)
mouseArea.clickMessage(false, isSticker, false)
if (typeof isMessageActive !== "undefined") {
setMessageActive(messageId, true)
}

View File

@ -77,7 +77,7 @@ Rectangle {
buttonsContainer.messageContextMenu.parent = buttonsContainer
buttonsContainer.messageContextMenu.setXPosition = function() { return (-Math.abs(buttonsContainer.width - buttonsContainer.messageContextMenu.emojiContainer.width))}
buttonsContainer.messageContextMenu.setYPosition = function() { return (-buttonsContainer.messageContextMenu.height - 4)}
clickMessage(false, false, false, null, true, false)
buttonsContainer.clickMessage(false, false, false, null, true, false)
}
onHoveredChanged: buttonsContainer.hoverChanged(this.hovered)
}
@ -120,7 +120,7 @@ Rectangle {
id: otherBtn
width: 32
height: 32
visible: showMoreButton
visible: buttonsContainer.showMoreButton
icon.name: "more"
type: StatusFlatRoundButton.Type.Tertiary
//% "More"
@ -133,7 +133,7 @@ Rectangle {
buttonsContainer.messageContextMenu.parent = buttonsContainer
buttonsContainer.messageContextMenu.setXPosition = function() { return (-Math.abs(buttonsContainer.width - 176))}
buttonsContainer.messageContextMenu.setYPosition = function() { return (-buttonsContainer.messageContextMenu.height - 4)}
clickMessage(false, isSticker, false, null, false, true);
buttonsContainer.clickMessage(false, isSticker, false, null, false, true);
}
onHoveredChanged: buttonsContainer.hoverChanged(this.hovered)
}

View File

@ -104,7 +104,7 @@ Loader {
icon: repliedMessageSenderIcon
isIdenticon: repliedMessageSenderIconIsIdenticon
onClickMessage: {
root.clickMessage(true, false, false, null, false, false, isReplyImage)
root.clickMessage(true, false, false, null, false, false, true)
}
}

View File

@ -23,20 +23,29 @@ Item {
property bool headerRepeatCondition: (authorCurrentMsg !== authorPrevMsg ||
shouldRepeatHeader || dateGroupLbl.visible || chatReply.active)
property bool showMoreButton: {
// Not Refactored Yet
return false
// switch (chatTypeThisMessageBelongsTo) {
// case Constants.chatType.oneToOne: return true
// case Constants.chatType.privateGroupChat: return rootStore.chatsModelInst.channelView.activeChannel.isAdmin(userProfile.pubKey) ? true : isCurrentUser
// case Constants.chatType.publicChat: return isCurrentUser
// case Constants.chatType.communityChat: return rootStore.chatsModelInst.communities.activeCommunity.admin ? true : isCurrentUser
// case Constants.chatType.profile: return false
// default: return false
// }
let chatTypeThisMessageBelongsTo = messageStore.getChatType()
switch (chatTypeThisMessageBelongsTo) {
case Constants.chatType.oneToOne:
return true
case Constants.chatType.privateGroupChat:
// Not Refactored Yet
return false
// return rootStore.chatsModelInst.channelView.activeChannel.isAdmin(userProfile.pubKey) ? true : isCurrentUser
case Constants.chatType.publicChat:
return amISender
case Constants.chatType.communityChat:
// Not Refactored Yet
return false
// return rootStore.chatsModelInst.communities.activeCommunity.admin ? true : amISender
case Constants.chatType.profile:
return false
default:
return false
}
}
signal addEmoji(bool isProfileClick, bool isSticker, bool isImage , var image, bool emojiOnly, bool hideEmojiPicker)
signal clickMessage(bool isProfileClick, bool isSticker, bool isImage, var image, bool emojiOnly, bool hideEmojiPicker, bool isReply, bool isRightClickOnImage, string imageSource)
width: parent.width
height: messageContainer.height + messageContainer.anchors.topMargin
@ -60,7 +69,7 @@ Item {
}
ChatButtonsPanel {
contentType: contentType
contentType: messageContentType
parentIsHovered: !isEdit && isHovered
onHoverChanged: {
hovered && setHovered(messageId, hovered)
@ -71,11 +80,11 @@ Item {
// This is not exactly like the design because the hover becomes messed up with the buttons on top of another Message
anchors.topMargin: -Style.current.halfPadding
messageContextMenu: root.messageContextMenu
showMoreButton: showMoreButton
showMoreButton: root.showMoreButton
fromAuthor: senderId
editBtnActive: isText && !isEdit && isCurrentUser && showEdit
onClickMessage: {
parent.parent.parent.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker);
root.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, false, false, "");
}
}
@ -240,7 +249,7 @@ Item {
active: responseTo !== "" && !activityCenterMessage
Component.onCompleted: {
let obj = messageStore.getMessageByIdAsJson(messageId)
let obj = messageStore.getMessageByIdAsJson(responseTo)
if(!obj)
return
@ -259,8 +268,7 @@ Item {
// messageStore.scrollToBottom(isit, root.container);
}
onClickMessage: {
// Not Refactored Yet
// parent.parent.parent.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply);
root.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply, false, "")
}
}
@ -276,7 +284,7 @@ Item {
icon: senderIcon
isIdenticon: isSenderIconIdenticon
onClickMessage: {
parent.parent.parent.parent.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply);
root.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply, false, "")
}
}
@ -290,7 +298,7 @@ Item {
localName: senderLocalName
amISender: amISender
onClickMessage: {
parent.parent.parent.parent.clickMessage(true, false, false, null, false, false, false);
root.clickMessage(true, false, false, null, false, false, false, false, "")
}
}
@ -374,7 +382,7 @@ Item {
StatusChatInput {
id: editTextInput
chatInputPlaceholder: qsTrId("type-a-message-")
chatType: chatTypeThisMessageBelongsTo
chatType: messageStore.getChatType()
isEdit: true
textInput.text: editMessageLoader.sourceText
onSendMessage: {
@ -458,7 +466,7 @@ Item {
onLinkActivated: {
if (activityCenterMessage) {
clickMessage(false, isSticker, false)
root.clickMessage(false, isSticker, false, null, false, false, false, false, "")
}
}
}
@ -482,7 +490,7 @@ Item {
root.messageContextMenu.parent = root
root.messageContextMenu.setXPosition = function() { return (mouse.x)}
root.messageContextMenu.setYPosition = function() { return (mouse.y)}
clickMessage(false, false, true, image, false, true, false, true, imageSource)
root.clickMessage(false, false, true, image, false, true, false, true, imageSource)
}
}
container: root.container
@ -528,7 +536,7 @@ Item {
messageContextMenu: root.messageContextMenu
isActivityCenterMessage: activityCenterMessage
onClickMessage: {
parent.parent.parent.parent.parent.clickMessage(isProfileClick, isSticker, isImage);
root.clickMessage(isProfileClick, isSticker, isImage, null, false, false, false, false, "");
}
onSetMessageActive: {
setMessageActive(messageId, active);

View File

@ -18,41 +18,45 @@ StatusPopupMenu {
id: root
width: emojiContainer.visible ? emojiContainer.width : 176
property var store
// Important:
// We're here in case of ChatSection
// This module is set from `ChatLayout` (each `ChatLayout` has its own chatSectionModule)
property var chatSectionModule
property string messageId
property int contentType
property bool isProfile: false
property bool isSticker: false
property bool emojiOnly: false
property bool hideEmojiPicker: false
property bool pinnedMessage: false
property bool pinnedPopup: false
property bool isText: false
property bool isCurrentUser: false
property bool isRightClickOnImage: false
property string linkUrls: ""
property alias emojiContainer: emojiContainer
property var identicon: ""
property var userName: ""
property string nickname: ""
property var fromAuthor: ""
property var text: ""
property var emojiReactionsReactedByUser: []
property var onClickEdit: function(){}
property var reactionModel
property alias emojiContainer: emojiContainer
property string myPublicKey: ""
property bool amIAdmin: false
property bool isMyMessage: {
return root.messageSenderId !== "" && root.messageSenderId == root.myPublicKey
}
property int chatType: Constants.chatType.publicChat
property string messageId: ""
property string messageSenderId: ""
property int messageContentType: Constants.messageContentType.unknownContentType
property string selectedUserPublicKey: ""
property string selectedUserDisplayName: ""
property string selectedUserIcon: ""
property bool isSelectedUserIconIdenticon: true
property string imageSource: ""
property bool isProfile: false
property bool isRightClickOnImage: false
property bool pinnedPopup: false
property bool isDebugEnabled: false
property bool emojiOnly: false
property bool hideEmojiPicker: true
property bool pinnedMessage: false
property bool canPin: false
property var setXPosition: function() {return 0}
property var setYPosition: function() {return 0}
property bool canPin: {
// Not Refactored Yet
return false
// const nbPinnedMessages = root.store.chatsModelInst.messageView.pinnedMessagesList.count
// return nbPinnedMessages < Constants.maxNumberOfPins
}
signal openProfileClicked(string publicKey, string displayName, string icon) // TODO: optimization, only publicKey is more than enough to be sent from here
signal pinMessage(string messageId)
signal unpinMessage(string messageId)
signal pinnedMessagesLimitReached(string messageId)
signal jumpToMessage(string messageId)
signal shouldCloseParentPopup()
signal createOneToOneChat(string chatId, string ensName)
signal showReplyArea()
onHeightChanged: {
root.y = setYPosition()
@ -62,39 +66,11 @@ StatusPopupMenu {
root.x = setXPosition()
}
signal shouldCloseParentPopup
function show(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, emojiReactionsModel) {
userName = userNameParam || ""
nickname = nicknameParam || ""
fromAuthor = fromAuthorParam || ""
identicon = identiconParam || ""
text = textParam || ""
let newEmojiReactions = []
if (!!emojiReactionsModel) {
emojiReactionsModel.forEach(function (emojiReaction) {
newEmojiReactions[emojiReaction.emojiId] = emojiReaction.currentUserReacted
})
}
emojiReactionsReactedByUser = newEmojiReactions;
/* // copy link feature not ready yet
const numLinkUrls = root.linkUrls.split(" ").length
copyLinkMenu.enabled = numLinkUrls > 1
copyLinkAction.enabled = !!root.linkUrls && numLinkUrls === 1 && !emojiOnly && !root.isProfile
*/
popup()
}
function openProfileClicked() {
openProfilePopup(userName, fromAuthor, identicon, "", nickname);
}
Item {
id: emojiContainer
width: emojiRow.width
height: visible ? emojiRow.height : 0
visible: !hideEmojiPicker && (root.emojiOnly || !root.isProfile)
visible: !root.hideEmojiPicker && (root.emojiOnly || !root.isProfile)
Row {
id: emojiRow
spacing: Style.current.halfPadding
@ -134,14 +110,13 @@ StatusPopupMenu {
anchors.top: parent.top
anchors.topMargin: 4
anchors.horizontalCenter: parent.horizontalCenter
image.source: identicon
image.isIdenticon: true
image.source: root.selectedUserIcon
image.isIdenticon: root.isSelectedUserIconIdenticon
}
StyledText {
id: username
// Not Refactored Yet
// text: Utils.removeStatusEns(isCurrentUser ? root.store.profileModelInst.ens.preferredUsername || userName : userName)
text: selectedUserDisplayName
elide: Text.ElideRight
maximumLineCount: 3
horizontalAlignment: Text.AlignHCenter
@ -162,7 +137,7 @@ StatusPopupMenu {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.openProfileClicked()
root.openProfileClicked(root.selectedUserPublicKey, root.selectedUserDisplayName, root.selectedUserIcon)
root.close()
}
}
@ -173,63 +148,16 @@ StatusPopupMenu {
visible: !root.emojiOnly && !root.hideEmojiPicker
}
/* // copy link feature not ready yet
StatusMenuItem {
id: copyLinkAction
//% "Copy link"
text: qsTrId("copy-link")
onTriggered: {
root.store.chatsModelInst.copyToClipboard(linkUrls.split(" ")[0])
root.close()
}
icon.name: "link"
enabled: false
}
// TODO: replace with StatusPopupMenu
PopupMenu {
id: copyLinkMenu
//% "Copy link"
title: qsTrId("copy-link")
Repeater {
id: linksRepeater
model: root.linkUrls.split(" ")
delegate: MenuItem {
id: popupMenuItem
text: modelData
onTriggered: {
root.store.chatsModelInst.copyToClipboard(modelData)
root.close()
}
contentItem: StyledText {
text: popupMenuItem.text
font: popupMenuItem.font
color: Style.current.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
implicitWidth: 220
implicitHeight: 34
color: popupMenuItem.highlighted ? Style.current.backgroundHover: Style.current.transparent
}
}
}
}
*/
StatusMenuItem {
id: copyImageAction
text: qsTr("Copy image")
onTriggered: {
// Not Refactored Yet
// Not Refactored Yet - Should be in GlobalUtils
// root.store.chatsModelInst.copyImageToClipboard(imageSource ? imageSource : "")
root.close()
}
icon.name: "copy"
enabled: isRightClickOnImage
enabled: root.isRightClickOnImage
}
StatusMenuItem {
@ -240,7 +168,7 @@ StatusPopupMenu {
root.close()
}
icon.name: "download"
enabled: isRightClickOnImage
enabled: root.isRightClickOnImage
}
StatusMenuItem {
@ -248,11 +176,11 @@ StatusPopupMenu {
//% "View Profile"
text: qsTrId("view-profile")
onTriggered: {
root.openProfileClicked()
root.openProfileClicked(root.selectedUserPublicKey, root.selectedUserDisplayName, root.selectedUserIcon)
root.close()
}
icon.name: "profile"
enabled: isProfile
enabled: root.isProfile
}
StatusMenuItem {
@ -264,15 +192,18 @@ StatusPopupMenu {
qsTrId("reply-to")
onTriggered: {
if (root.isProfile) {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
chatSectionModule.createOneToOneChat(fromAuthor, "")
root.createOneToOneChat(root.selectedUserPublicKey, "")
} else {
showReplyArea()
root.showReplyArea()
}
root.close()
}
icon.name: "chat"
enabled: isProfile || (!hideEmojiPicker && !emojiOnly && !isProfile && !isRightClickOnImage)
enabled: root.isProfile ||
(!root.hideEmojiPicker &&
!root.emojiOnly &&
!root.isProfile &&
!root.isRightClickOnImage)
}
StatusMenuItem {
@ -283,16 +214,20 @@ StatusPopupMenu {
onClickEdit();
}
icon.name: "edit"
enabled: isCurrentUser && !hideEmojiPicker && !emojiOnly && !isProfile && !isRightClickOnImage
enabled: root.isMyMessage &&
!root.hideEmojiPicker &&
!root.emojiOnly &&
!root.isProfile &&
!root.isRightClickOnImage
}
StatusMenuItem {
id: copyMessageIdAction
text: qsTr("Copy Message Id")
icon.name: "chat"
enabled: store.isDebugEnabled
enabled: root.isDebugEnabled
onTriggered: {
// Not Refactored Yet
// Not Refactored Yet - Should be in GlobalUtils
// root.store.chatsModelInst.copyToClipboard(SelectedMessage.messageId)
close()
}
@ -301,7 +236,7 @@ StatusPopupMenu {
StatusMenuItem {
id: pinAction
text: {
if (pinnedMessage) {
if (root.pinnedMessage) {
//% "Unpin"
return qsTrId("unpin")
}
@ -310,53 +245,61 @@ StatusPopupMenu {
}
onTriggered: {
if (pinnedMessage) {
// Not Refactored Yet
// root.store.chatsModelInst.messageView.unPinMessage(messageId, root.store.chatsModelInst.channelView.activeChannel.id)
if (root.pinnedMessage) {
root.unpinMessage(root.messageId)
return
}
if (!canPin) {
// Open pin modal so that the user can unpin one
Global.openPopup(pinnedMessagesPopupComponent, {messageToPin: messageId})
if (!root.canPin) {
root.pinnedMessagesLimitReached(root.messageId)
return
}
// Not Refactored Yet
// root.store.chatsModelInst.messageView.pinMessage(messageId, root.store.chatsModelInst.channelView.activeChannel.id)
root.pinMessage(root.messageId)
root.close()
}
icon.name: "pin"
enabled: {
if(isProfile || emojiOnly || isRightClickOnImage)
if(root.isProfile || root.emojiOnly || root.isRightClickOnImage)
return false
// Not Refactored Yet
// switch (root.store.chatsModelInst.channelView.activeChannel.chatType) {
// case Constants.chatType.publicChat: return false
// case Constants.chatType.profile: return false
// case Constants.chatType.oneToOne: return true
// case Constants.chatType.privateGroupChat: return root.store.chatsModelInst.channelView.activeChannel.isAdmin(userProfile.pubKey)
// case Constants.chatType.communityChat: return root.store.chatsModelInst.communities.activeCommunity.admin
// }
return false
switch (root.chatType) {
case Constants.chatType.publicChat:
return false
case Constants.chatType.profile:
return false
case Constants.chatType.oneToOne:
return true
case Constants.chatType.privateGroupChat:
return root.amIAdmin
case Constants.chatType.communityChat:
return root.amIAdmin
default:
return false
}
}
}
StatusMenuSeparator {
visible: deleteMessageAction.enabled && (viewProfileAction.visible
|| sendMessageOrReplyTo.visible || editMessageAction.visible || pinAction.visible)
visible: deleteMessageAction.enabled &&
(viewProfileAction.visible ||
sendMessageOrReplyTo.visible ||
editMessageAction.visible ||
pinAction.visible)
}
StatusMenuItem {
id: deleteMessageAction
enabled: isCurrentUser && !isProfile && !emojiOnly && !pinnedPopup && !isRightClickOnImage &&
(contentType === Constants.messageContentType.messageType ||
contentType === Constants.messageContentType.stickerType ||
contentType === Constants.messageContentType.emojiType ||
contentType === Constants.messageContentType.imageType ||
contentType === Constants.messageContentType.audioType)
enabled: root.isMyMessage &&
!root.isProfile &&
!root.emojiOnly &&
!root.pinnedPopup &&
!root.isRightClickOnImage &&
(root.messageContentType === Constants.messageContentType.messageType ||
root.messageContentType === Constants.messageContentType.stickerType ||
root.messageContentType === Constants.messageContentType.emojiType ||
root.messageContentType === Constants.messageContentType.imageType ||
root.messageContentType === Constants.messageContentType.audioType)
//% "Delete message"
text: qsTrId("delete-message")
onTriggered: {
@ -388,10 +331,11 @@ StatusPopupMenu {
}
StatusMenuItem {
id: jumpToAction
enabled: root.pinnedPopup
text: qsTr("Jump to")
onTriggered: {
positionAtMessage(root.messageId)
root.jumpToMessage(root.messageId)
root.close()
root.shouldCloseParentPopup()
}
@ -404,7 +348,7 @@ StatusPopupMenu {
selectFolder: true
modality: Qt.NonModal
onAccepted: {
// Not Refactored Yet
// Not Refactored Yet - Should be in GlobalUtils
// root.store.chatsModelInst.downloadImage(imageSource ? imageSource : "", fileDialog.fileUrls)
fileDialog.close()
}

View File

@ -17,6 +17,7 @@ Column {
z: (typeof chatLogView === "undefined") ? 1 : (chatLogView.count - index)
property var messageStore
property var messageContextMenu
property string messageId: ""
property string responseToMessageWithId: ""
@ -33,10 +34,6 @@ Column {
property int messageContentType: 1
property bool pinnedMessage: false
// Used only in case of ChatIdentifier
property int chatTypeThisMessageBelongsTo: -1
property string chatColorThisMessageBelongsTo: ""
property int prevMessageIndex: -1
property var prevMessageAsJsonObj
property int nextMessageIndex: -1
@ -112,7 +109,7 @@ Column {
property string replaces: ""
property bool isEdited: false
property bool showEdit: true
property var messageContextMenu
//////////////////////////////////////
@ -166,41 +163,59 @@ Column {
// }
}
property var clickMessage: function(isProfileClick, isSticker = false, isImage = false, image = null, emojiOnly = false, hideEmojiPicker = false, isReply = false, isRightClickOnImage = false, imageSource = "") {
// Not Refactored Yet
// if (placeholderMessage || activityCenterMessage) {
// return
// }
property var clickMessage: function(isProfileClick,
isSticker = false,
isImage = false,
image = null,
emojiOnly = false,
hideEmojiPicker = false,
isReply = false,
isRightClickOnImage = false,
imageSource = "") {
// if (!isProfileClick) {
// SelectedMessage.set(messageId, fromAuthor);
// }
if (placeholderMessage || activityCenterMessage) {
return
}
// messageContextMenu.messageId = root.messageId
// messageContextMenu.contentType = root.contentType
// messageContextMenu.linkUrls = root.linkUrls;
// messageContextMenu.isProfile = !!isProfileClick;
// messageContextMenu.isCurrentUser = root.isCurrentUser
// messageContextMenu.isText = root.isText
// messageContextMenu.isSticker = isSticker;
// messageContextMenu.emojiOnly = emojiOnly;
// messageContextMenu.hideEmojiPicker = hideEmojiPicker;
// messageContextMenu.pinnedMessage = pinnedMessage;
// messageContextMenu.isCurrentUser = isCurrentUser;
// messageContextMenu.isRightClickOnImage = isRightClickOnImage
// messageContextMenu.imageSource = imageSource
// messageContextMenu.onClickEdit = function() {root.isEdit = true}
messageContextMenu.myPublicKey = userProfile.pubKey
messageContextMenu.amIAdmin = messageStore.amIChatAdmin()
messageContextMenu.chatType = messageStore.getChatType()
// if (isReply) {
// let nickname = appMain.getUserNickname(repliedMessageAuthor)
// messageContextMenu.show(repliedMessageAuthor, repliedMessageAuthorPubkey, repliedMessageUserImage || repliedMessageUserIdenticon, plainText, nickname, emojiReactionsModel);
// } else {
// let nickname = appMain.getUserNickname(fromAuthor)
// messageContextMenu.show(userName, fromAuthor, root.profileImageSource || identicon, plainText, nickname, emojiReactionsModel);
// }
messageContextMenu.messageId = root.messageId
messageContextMenu.messageSenderId = root.senderId
messageContextMenu.messageContentType = root.messageContentType
messageContextMenu.pinnedMessage = root.pinnedMessage
messageContextMenu.canPin = messageStore.getNumberOfPinnedMessages() <= Constants.maxNumberOfPins
// messageContextMenu.x = messageContextMenu.setXPosition()
// messageContextMenu.y = messageContextMenu.setYPosition()
messageContextMenu.selectedUserPublicKey = root.senderId
messageContextMenu.selectedUserDisplayName = root.senderDisplayName
messageContextMenu.selectedUserIcon = root.senderIcon
messageContextMenu.isSelectedUserIconIdenticon = root.isSenderIconIdenticon
messageContextMenu.imageSource = imageSource
messageContextMenu.isProfile = !!isProfileClick
messageContextMenu.isRightClickOnImage = isRightClickOnImage
messageContextMenu.emojiOnly = emojiOnly
messageContextMenu.hideEmojiPicker = hideEmojiPicker
if(isReply){
let obj = messageStore.getMessageByIdAsJson(responseTo)
if(!obj)
return
messageContextMenu.messageSenderId = obj.id
messageContextMenu.selectedUserPublicKey = obj.id
messageContextMenu.selectedUserDisplayName = obj.senderDisplayName
messageContextMenu.selectedUserIcon = obj.senderIcon
messageContextMenu.isSelectedUserIconIdenticon = obj.isSenderIconIdenticon
}
messageContextMenu.x = messageContextMenu.setXPosition()
messageContextMenu.y = messageContextMenu.setYPosition()
messageContextMenu.popup()
}
@ -297,8 +312,8 @@ Column {
id: channelIdentifierComponent
ChannelIdentifierView {
chatName: root.senderDisplayName
chatType: root.chatTypeThisMessageBelongsTo
chatColor: root.chatColorThisMessageBelongsTo
chatType: messageStore.getChatType()
chatColor: messageStore.getChatColor()
chatIcon: root.senderIcon
chatIconIsIdenticon: root.isSenderIconIdenticon
}
@ -375,7 +390,11 @@ Column {
messageContextMenu: root.messageContextMenu
container: root
onAddEmoji: {
root.clickMessage(isProfileClick, isSticker, isImage , image, emojiOnly, hideEmojiPicker);
root.clickMessage(isProfileClick, isSticker, isImage , image, emojiOnly, hideEmojiPicker)
}
onClickMessage: {
root.clickMessage(isProfileClick, isSticker, isImage, image, emojiOnly, hideEmojiPicker, isReply, isRightClickOnImage, imageSource)
}
}
}