From 4612d5318b24f1313a47eb590790ce96ec49b3c6 Mon Sep 17 00:00:00 2001 From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> Date: Fri, 10 Feb 2023 17:38:17 -0500 Subject: [PATCH] chatview: refactor msg options popup positioning + load the popup dynamically + calculate the position using the delegate's attached ListView geometry Gitlab: #979 Change-Id: I9d3a8a31b4aba2f195c4d6453e9dca88e99685ae --- src/app/commoncomponents/JamiListView.qml | 7 +- ...ageOptions.qml => MessageOptionsPopup.qml} | 84 ++++++++++-- src/app/commoncomponents/SBSMessageBase.qml | 123 +++--------------- src/app/constant/JamiQmlUtils.qml | 4 - .../mainview/components/ChatViewFooter.qml | 6 +- .../mainview/components/ChatViewHeader.qml | 1 - src/app/nowebengine/EmojiPicker.qml | 2 + src/app/webengine/emojipicker/EmojiPicker.qml | 10 ++ 8 files changed, 111 insertions(+), 126 deletions(-) rename src/app/commoncomponents/{ChatviewMessageOptions.qml => MessageOptionsPopup.qml} (71%) diff --git a/src/app/commoncomponents/JamiListView.qml b/src/app/commoncomponents/JamiListView.qml index e7a2b8ad5..e92c8cda3 100644 --- a/src/app/commoncomponents/JamiListView.qml +++ b/src/app/commoncomponents/JamiListView.qml @@ -26,6 +26,8 @@ import net.jami.Models 1.1 ListView { id: root + property alias verticalScrollBar: verticalScrollBar + layer.mipmap: false clip: true maximumFlickVelocity: 1024 @@ -36,11 +38,6 @@ ListView { attachedFlickableMoving: root.moving } - property bool isScrolling: verticalScrollBar.active - onIsScrollingChanged: { - JamiQmlUtils.isChatviewScrolling = isScrolling - } - Keys.onUpPressed: verticalScrollBar.decrease() Keys.onDownPressed: verticalScrollBar.increase() } diff --git a/src/app/commoncomponents/ChatviewMessageOptions.qml b/src/app/commoncomponents/MessageOptionsPopup.qml similarity index 71% rename from src/app/commoncomponents/ChatviewMessageOptions.qml rename to src/app/commoncomponents/MessageOptionsPopup.qml index 5e149f9d1..acc1657eb 100644 --- a/src/app/commoncomponents/ChatviewMessageOptions.qml +++ b/src/app/commoncomponents/MessageOptionsPopup.qml @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + import QtQuick import QtQuick.Controls import Qt5Compat.GraphicalEffects @@ -32,22 +33,79 @@ Popup { padding: 0 background.visible: false - property string msgId - property string msg - property var emojiReplied - property bool out - property int type + required property string msgId + required property string msgBody + required property var emojiReplied + required property bool isOutgoing + required property int type + required property string transferName + required property Item msgBubble + required property ListView listView + property string transferId: msgId - property string location: Body - property string transferName + property string location: msgBody property bool closeWithoutAnimation: false + property var emojiPicker + + function xPositionProvider(width) { + // Use the width at function scope to retrigger property evaluation. + const listViewWidth = listView.width + if (isOutgoing) { + const leftMargin = msgBubble.mapToItem(listView, 0, 0).x + return width > leftMargin ? -leftMargin : -width + } else { + const rightMargin = listViewWidth - (msgBubble.x + msgBubble.width) + return width > rightMargin ? msgBubble.width - width : msgBubble.width + } + } + function yPositionProvider(height) { + const topOffset = msgBubble.mapToItem(listView, 0, 0).y + if (topOffset < 0) return -topOffset + const bottomOffset = topOffset + height - listView.height + if (bottomOffset > 0) return -bottomOffset + return 0 + } + x: xPositionProvider(width) + y: yPositionProvider(height) signal addMoreEmoji + onAddMoreEmoji: { + JamiQmlUtils.updateMessageBarButtonsPoints() + openEmojiPicker() + } - onOpened: { - root.closeWithoutAnimation = false + function openEmojiPicker() { + var component = WITH_WEBENGINE ? + Qt.createComponent("qrc:/webengine/emojipicker/EmojiPicker.qml") : + Qt.createComponent("qrc:/nowebengine/EmojiPicker.qml") + emojiPicker = component.createObject(root.parent, { listView: listView }) + emojiPicker.emojiIsPicked.connect(function(content) { + if (emojiReplied.includes(content)) { + MessagesAdapter.removeEmojiReaction(CurrentConversation.id, content, msgId) + } else { + MessagesAdapter.addEmojiReaction(CurrentConversation.id, content, msgId) + } + }) + if (emojiPicker !== null) { + root.opacity = 0 + emojiPicker.closed.connect(() => close()) + emojiPicker.x = xPositionProvider(JamiTheme.emojiPickerWidth) + emojiPicker.y = yPositionProvider(JamiTheme.emojiPickerHeight) + emojiPicker.open() + } else { + console.log("Error creating emojiPicker from message options popup"); + } } + // Close the picker when listView vertical properties change. + property real listViewHeight: listView.height + onListViewHeightChanged: close() + property bool isScrolling: listView.verticalScrollBar.active + onIsScrollingChanged: close() + + onOpened: root.closeWithoutAnimation = false + onClosed: if (emojiPicker) emojiPicker.closeEmojiPicker() + function getModel() { var model = ["👍", "👎", "😂"] var cur = [] @@ -132,7 +190,7 @@ Popup { onClicked: { root.closeWithoutAnimation = true root.addMoreEmoji() - close() + //close() } } } @@ -152,7 +210,7 @@ Popup { Layout.fillWidth: true Layout.margins: 5 onClicked: { - UtilsAdapter.setClipboardText(msg) + UtilsAdapter.setClipboardText(msgBody) close() } } @@ -184,7 +242,7 @@ Popup { MessageOptionButton { id: buttonEdit - visible: root.out && type === Interaction.Type.TEXT + visible: root.isOutgoing && type === Interaction.Type.TEXT textButton: JamiStrings.editMessage iconSource: JamiResources.edit_svg Layout.fillWidth: true @@ -198,7 +256,7 @@ Popup { } MessageOptionButton { - visible: root.out && type === Interaction.Type.TEXT + visible: root.isOutgoing && type === Interaction.Type.TEXT textButton: JamiStrings.deleteMessage iconSource: JamiResources.delete_svg Layout.fillWidth: true diff --git a/src/app/commoncomponents/SBSMessageBase.qml b/src/app/commoncomponents/SBSMessageBase.qml index 1914ef066..36f24cf64 100644 --- a/src/app/commoncomponents/SBSMessageBase.qml +++ b/src/app/commoncomponents/SBSMessageBase.qml @@ -55,9 +55,15 @@ Control { readonly property real hPadding: JamiTheme.sbsMessageBasePreferredPadding property bool textHovered: false property alias replyAnimation: selectAnimation - width: ListView.view ? ListView.view.width : 0 + width: listView.width height: mainColumnLayout.implicitHeight + // If the ListView attached properties are not available, + // then the root delegate is likely a Loader. + readonly property ListView listView: ListView.view ? + ListView.view : + parent.ListView.view + rightPadding: hPadding leftPadding: hPadding @@ -184,9 +190,18 @@ Control { height: optionButtonItem.height onClicked: { - messageOptionPopup.open() - messageOptionPopup.x = messageOptionPopup.setXposition(messageOptionPopup.width) - messageOptionPopup.y = messageOptionPopup.setYposition(messageOptionPopup.height) + var component = Qt.createComponent("qrc:/commoncomponents/MessageOptionsPopup.qml") + var obj = component.createObject(bubble, { + "emojiReplied": Qt.binding(() => emojiReaction.emojiTexts), + "isOutgoing": isOutgoing, + "msgId": Id, + "msgBody": Body, + "type": Type, + "transferName": TransferName, + "msgBubble": bubble, + "listView": listView + }) + obj.open() } } @@ -214,103 +229,6 @@ Control { } } - ChatviewMessageOptions { - id: messageOptionPopup - - emojiReplied: emojiReaction.emojiTexts - out: isOutgoing - msgId: Id - msg: Body - type: Type - transferName: TransferName - visible: false - - property bool isScrolling: JamiQmlUtils.isChatviewScrolling - property real rootWidth: root.width - property var emojiPicker - - onIsScrollingChanged: { - messageOptionPopup.close() - if (messageOptionPopup.emojiPicker) - messageOptionPopup.emojiPicker.closeEmojiPicker() - } - - onAddMoreEmoji: { - JamiQmlUtils.updateMessageBarButtonsPoints() - openEmojiPicker() - } - - onRootWidthChanged: { - if (emojiPicker) - emojiPicker.x = setXposition(JamiTheme.emojiPickerWidth) - messageOptionPopup.x = setXposition(width) - messageOptionPopup.y = setYposition(height) - } - - Connections { - target: messageOptionPopup.emojiPicker ? messageOptionPopup.emojiPicker : null - function onEmojiIsPicked(content) { - if (messageOptionPopup.emojiReplied.includes(content)) - MessagesAdapter.removeEmojiReaction(CurrentConversation.id,content,messageOptionPopup.msgId) - else - MessagesAdapter.addEmojiReaction(CurrentConversation.id,content,messageOptionPopup.msgId) - } - } - - function openEmojiPicker() { - var component = WITH_WEBENGINE - ? Qt.createComponent("qrc:/webengine/emojipicker/EmojiPicker.qml") - : Qt.createComponent("qrc:/nowebengine/EmojiPicker.qml") - messageOptionPopup.emojiPicker = component.createObject(msgRowlayout, - { - x: setXposition(JamiTheme.emojiPickerWidth), - y: setYposition(JamiTheme.emojiPickerHeight) - }); - if (messageOptionPopup.emojiPicker !== null) { - messageOptionPopup.emojiPicker.open() - } else { - console.log("Error creating emojiPicker in SBSMessageBase"); - } - } - - function setXposition(width) { - - var distBorders = root.width - bubble.width - width - if (isOutgoing) { - if (distBorders > 0) - x = bubble.x - width - else - x = bubble.x - } else { - if (distBorders > 0) - x = bubble.x + bubble.width - else - x = bubble.x + bubble.width - width - } - return x - } - - function setYposition(height) { - var bottomOffset = 0 - if (JamiQmlUtils.messageBarButtonsRowObj) { - bottomOffset = JamiQmlUtils.messageBarButtonsRowObj.height - } - var mappedCoord = bubble.mapToItem(appWindow.contentItem, 0, 0) - var distBottomScreen = appWindow.height - mappedCoord.y - height - bottomOffset - if (distBottomScreen < 0) { - return distBottomScreen - } - var topOffset = 0 - if (JamiQmlUtils.messagingHeaderRectRowLayout) { - topOffset = JamiQmlUtils.messagingHeaderRectRowLayout.height - } - var distTopScreen = mappedCoord.y - topOffset - if (distTopScreen < 0) - return -distTopScreen - return 0 - } - } - MessageBubble { id: bubble @@ -321,7 +239,8 @@ Control { function getBaseColor() { var baseColor = isOutgoing ? JamiTheme.messageOutBgColor : CurrentConversation.isCoreDialog ? - JamiTheme.messageInBgColor : Qt.lighter(CurrentConversation.color, 1.5) + JamiTheme.messageInBgColor : + Qt.lighter(CurrentConversation.color, 1.5) if (Id === MessagesAdapter.replyToId || Id === MessagesAdapter.editId) { // If we are replying to or editing the message return Qt.darker(baseColor, 1.5) diff --git a/src/app/constant/JamiQmlUtils.qml b/src/app/constant/JamiQmlUtils.qml index fff14ba43..4d051a980 100644 --- a/src/app/constant/JamiQmlUtils.qml +++ b/src/app/constant/JamiQmlUtils.qml @@ -38,10 +38,6 @@ Item { Object.assign(JamiQmlUtils.accountCreationInputParaObject, inputPara) return accountCreationInputParaObject } - //to know if the chatview is being scrolled - property bool isChatviewScrolling - //chatviewHeader - property var messagingHeaderRectRowLayout // MessageBar buttons in mainview points property var mainViewRectObj diff --git a/src/app/mainview/components/ChatViewFooter.qml b/src/app/mainview/components/ChatViewFooter.qml index ce840d554..3f14f7aea 100644 --- a/src/app/mainview/components/ChatViewFooter.qml +++ b/src/app/mainview/components/ChatViewFooter.qml @@ -150,7 +150,11 @@ Rectangle { ? Qt.createComponent("qrc:/webengine/emojipicker/EmojiPicker.qml") : Qt.createComponent("qrc:/nowebengine/EmojiPicker.qml") messageBar.emojiPicker = - component.createObject(messageBar, {x: setXposition(), y: setYposition()}); + component.createObject(messageBar, { + x: setXposition(), + y: setYposition(), + listView: null + }); if (messageBar.emojiPicker === null) { console.log("Error creating emojiPicker in chatViewFooter"); } diff --git a/src/app/mainview/components/ChatViewHeader.qml b/src/app/mainview/components/ChatViewHeader.qml index 468f3da14..9601a0ac3 100644 --- a/src/app/mainview/components/ChatViewHeader.qml +++ b/src/app/mainview/components/ChatViewHeader.qml @@ -260,7 +260,6 @@ Rectangle { } } - Component.onCompleted: JamiQmlUtils.messagingHeaderRectRowLayout = messagingHeaderRectRowLayout } CustomBorder { diff --git a/src/app/nowebengine/EmojiPicker.qml b/src/app/nowebengine/EmojiPicker.qml index 3adca4f94..ceb6528a1 100644 --- a/src/app/nowebengine/EmojiPicker.qml +++ b/src/app/nowebengine/EmojiPicker.qml @@ -21,6 +21,8 @@ import QtQuick Rectangle { id: root + required property ListView listView + signal emojiIsPicked(string content) function openEmojiPicker() {} function closeEmojiPicker() {} diff --git a/src/app/webengine/emojipicker/EmojiPicker.qml b/src/app/webengine/emojipicker/EmojiPicker.qml index bf22e01a9..39b151e33 100644 --- a/src/app/webengine/emojipicker/EmojiPicker.qml +++ b/src/app/webengine/emojipicker/EmojiPicker.qml @@ -23,6 +23,7 @@ import Qt5Compat.GraphicalEffects import QtWebEngine import QtWebChannel +import net.jami.Models 1.1 import net.jami.Constants 1.1 import net.jami.Adapters 1.1 @@ -31,8 +32,17 @@ import "../" Popup { id: root + required property ListView listView + signal emojiIsPicked(string content) + // Close the picker when attached to a listView that receives height/scroll + // property changes. + property real listViewHeight: listView ? listView.height : 0 + onListViewHeightChanged: close() + property bool isScrolling: listView ? listView.verticalScrollBar.active : false + onIsScrollingChanged: close() + function openEmojiPicker() { root.open() emojiPickerWebView.runJavaScript( -- GitLab