From 04a57dfdbb8177f1c9b382f711f8f00abf66f413 Mon Sep 17 00:00:00 2001 From: cberthet <capucine.berthet@savoirfairelinux.com> Date: Fri, 1 Dec 2023 15:16:58 -0500 Subject: [PATCH] ConversationBubble: add time inside bubble GitLab: #1325 Change-Id: Ib52222f4adae911e0975f4d7e8bc60739fb63cfb --- .../commoncomponents/CallMessageDelegate.qml | 10 +- .../DataTransferMessageDelegate.qml | 53 +++++++- src/app/commoncomponents/MessageBubble.qml | 1 + src/app/commoncomponents/SBSMessageBase.qml | 113 ++++++++++++++---- .../commoncomponents/TextMessageDelegate.qml | 51 ++------ src/app/commoncomponents/TimestampInfo.qml | 6 +- .../mainview/components/MessageListView.qml | 4 +- src/app/messagesadapter.cpp | 3 +- 8 files changed, 156 insertions(+), 85 deletions(-) diff --git a/src/app/commoncomponents/CallMessageDelegate.qml b/src/app/commoncomponents/CallMessageDelegate.qml index 423b7c851..0cefc116d 100644 --- a/src/app/commoncomponents/CallMessageDelegate.qml +++ b/src/app/commoncomponents/CallMessageDelegate.qml @@ -56,13 +56,6 @@ SBSMessageBase { visible: isActive || ConfId === "" || Duration > 0 property var baseColor: isOutgoing? CurrentConversation.color : JamiTheme.messageInBgColor - bubble.color: { - if (ConfId === "" && Duration === 0) { - // If missed, we can add a darker pattern - return Qt.lighter(root.baseColor, 1.15) - } - return root.baseColor - } innerContent.children: [ RowLayout { @@ -73,9 +66,10 @@ SBSMessageBase { Label { id: callLabel - padding: 10 + Layout.margins: 8 Layout.fillWidth: true + Layout.rightMargin: root.timeWidth + 16 text: { if (root.isActive) diff --git a/src/app/commoncomponents/DataTransferMessageDelegate.qml b/src/app/commoncomponents/DataTransferMessageDelegate.qml index bbedbabc7..ec247abff 100644 --- a/src/app/commoncomponents/DataTransferMessageDelegate.qml +++ b/src/app/commoncomponents/DataTransferMessageDelegate.qml @@ -79,6 +79,9 @@ Loader { formattedTime: root.formattedTime formattedDay: root.formattedTime extraHeight: progressBar.visible ? 18 : 0 + Component.onCompleted: bubble.timestampItem.visible = false + + innerContent.children: [ RowLayout { id: transferItem @@ -257,6 +260,7 @@ Loader { id: localMediaMsgItem isOutgoing: Author === CurrentAccount.uri + property var transferStats: MessagesAdapter.getTransferStats(Id, Status) showTime: root.showTime seq: root.seq author: Author @@ -266,7 +270,21 @@ Loader { readers: Readers formattedTime: MessagesAdapter.getFormattedTime(Timestamp) formattedDay: MessagesAdapter.getFormattedDay(Timestamp) - bubble.visible: false + + Component.onCompleted: { + if (transferStats.totalSize !== undefined) { + var totalSize = transferStats.totalSize !== 0 ? transferStats.totalSize : TotalSize + var txt = UtilsAdapter.humanFileSize(totalSize) + } + bubble.timestampItem.timeLabel.text += " - " + txt + + bubble.color = "transparent" + bubble.timestampItem.timeColor = JamiTheme.whiteColor + bubble.timestampItem.timeLabel.opacity = 1 + bubble.z = 1 + + } + innerContent.children: [ Loader { id: localMediaCompLoader @@ -296,6 +314,7 @@ Loader { } Component { id: animatedImageComp + AnimatedImage { id: animatedImg @@ -337,6 +356,22 @@ Loader { } cursorShape: Qt.PointingHandCursor } + + LinearGradient { + id: gradient + anchors.fill: parent + start: Qt.point(0, height / 3) + gradient: Gradient { + GradientStop { + position: 0.0 + color: JamiTheme.transparentColor + } + GradientStop { + position: 1.0 + color: JamiTheme.darkGreyColorOpacityFade + } + } + } } } @@ -394,6 +429,22 @@ Loader { } cursorShape: Qt.PointingHandCursor } + + LinearGradient { + id: gradient + anchors.fill: parent + start: Qt.point(0, height / 3) + gradient: Gradient { + GradientStop { + position: 0.0 + color: JamiTheme.transparentColor + } + GradientStop { + position: 1.0 + color: JamiTheme.darkGreyColorOpacityFade + } + } + } } } } diff --git a/src/app/commoncomponents/MessageBubble.qml b/src/app/commoncomponents/MessageBubble.qml index 4293409c7..119c562eb 100644 --- a/src/app/commoncomponents/MessageBubble.qml +++ b/src/app/commoncomponents/MessageBubble.qml @@ -37,6 +37,7 @@ Rectangle { Rectangle { id: mask + visible: type !== MsgSeq.single && !isReply z: -1 radius: 5 diff --git a/src/app/commoncomponents/SBSMessageBase.qml b/src/app/commoncomponents/SBSMessageBase.qml index 3c0f0ff84..11b767ef4 100644 --- a/src/app/commoncomponents/SBSMessageBase.qml +++ b/src/app/commoncomponents/SBSMessageBase.qml @@ -49,7 +49,7 @@ Control { property int timestamp: Timestamp readonly property real senderMargin: 64 readonly property real avatarSize: 20 - readonly property real msgRadius: 20 + readonly property real msgRadius: 10 readonly property real hPadding: JamiTheme.sbsMessageBasePreferredPadding property bool textHovered: false property alias replyAnimation: selectAnimation @@ -59,8 +59,11 @@ Control { property real textContentWidth property real textContentHeight property bool isReply: ReplyTo !== "" + property real timeWidth: timestampItem.width + property real editedWidth: editedRow.visible ? editedRow.width + 10 : 0 property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth + property bool bigMsg // If the ListView attached properties are not available, // then the root delegate is likely a Loader. @@ -86,11 +89,8 @@ Control { spacing: 0 TimestampInfo { - id: timestampItem - + id: dateItem showDay: root.showDay - showTime: root.showTime - formattedTime: root.formattedTime formattedDay: root.formattedDay Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -101,12 +101,10 @@ Control { id: usernameblock Layout.preferredHeight: (seq === MsgSeq.first || seq === MsgSeq.single) ? 10 : 0 visible: !isReply - Layout.topMargin: (seq === MsgSeq.first || seq === MsgSeq.single) && !isOutgoing && !root.showTime ? 20 : 0 Label { id: username text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) - font.bold: true visible: (seq === MsgSeq.first || seq === MsgSeq.single) && !isOutgoing font.pointSize: JamiTheme.smallFontSize color: JamiTheme.chatviewSecondaryInformationColor @@ -212,7 +210,7 @@ Control { RowLayout { id: msgRowlayout - Layout.preferredHeight: innerContent.height + root.extraHeight + (emojiReactions.emojis === "" ? 0 : emojiReactions.height - 8) + Layout.preferredHeight: innerContent.height + root.extraHeight + (emojiReactions.emojis === "" ? 0 : emojiReactions.height - 8) + (IsEmojiOnly && (root.seq === MsgSeq.last || root.seq === MsgSeq.single) && emojiReactions.emojis === "" ? 15 : 0) Layout.topMargin: ((seq === MsgSeq.first || seq === MsgSeq.single) && !root.isReply) ? 6 : 0 Item { @@ -238,19 +236,7 @@ Control { Layout.fillHeight: true Layout.fillWidth: true - MouseArea { - id: bubbleArea - - anchors.fill: bubble - hoverEnabled: true - onClicked: function (mouse) { - if (root.hoveredLink) { - MessagesAdapter.openUrl(root.hoveredLink); - } - } - property bool bubbleHovered: containsMouse || textHovered - } Column { id: innerContent @@ -351,18 +337,93 @@ Control { id: bubble property bool isEdited: PreviousBodies.length !== 0 - visible: !IsEmojiOnly z: -1 out: isOutgoing type: seq isReply: root.isReply - color: root.getBaseColor() + color: IsEmojiOnly ? "transparent" : root.getBaseColor() radius: msgRadius anchors.right: isOutgoing ? parent.right : undefined anchors.top: parent.top - width: Type === Interaction.Type.TEXT && !isEdited ? root.textContentWidth : innerContent.childrenRect.width - height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) + property real timePosition: JamiTheme.emojiMargins + emojiReactions.width + 8 + property alias timestampItem: timestampItem + + width: (Type === Interaction.Type.TEXT ? root.textContentWidth : innerContent.childrenRect.width) + height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) + (root.bigMsg ? 15 : 0) + + TimestampInfo { + id: timestampItem + + showTime: IsEmojiOnly && !(root.seq === MsgSeq.last || root.seq === MsgSeq.single) ? false : true + formattedTime: root.formattedTime + + timeColor: IsEmojiOnly ? (JamiTheme.darkTheme ? "white" : "dark") : (UtilsAdapter.luma(bubble.color) ? "white" : "dark") + timeLabel.opacity: 0.5 + + anchors.bottom: parent.bottom + anchors.right: IsEmojiOnly ? (isOutgoing ? parent.right : undefined) : parent.right + anchors.left: (IsEmojiOnly && !isOutgoing) ? parent.left : undefined + anchors.leftMargin: (IsEmojiOnly && !isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0 + anchors.rightMargin: IsEmojiOnly ? ((isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0) : 10 + timeLabel.Layout.bottomMargin: { + if (IsEmojiOnly) + return -15; + if (root.bigMsg) + return 5; + return 9; + } + } + + RowLayout { + id: editedRow + anchors.left: root.bigMsg ? bubble.left : timestampItem.left + anchors.bottom: parent.bottom + anchors.bottomMargin: root.bigMsg ? 6 : 10 + anchors.leftMargin: root.bigMsg ? 10 : - timestampItem.width - 10 + visible: bubble.isEdited + z: 1 + + ResponsiveImage { + id: editedImage + source: JamiResources.round_edit_24dp_svg + width: 12 + height: 12 + color: editedLabel.color + opacity: 0.5 + } + + Text { + id: editedLabel + text: JamiStrings.edited + color: UtilsAdapter.luma(bubble.color) ? "white" : "dark" + opacity: 0.5 + font.pixelSize: JamiTheme.timestampFont + } + + TapHandler { + acceptedButtons: Qt.LeftButton + onTapped: { + viewCoordinator.presentDialog(appWindow, "commoncomponents/EditedPopup.qml", { + "previousBodies": PreviousBodies + }); + } + } + } + + MouseArea { + id: bubbleArea + + anchors.fill: parent + hoverEnabled: true + + onClicked: function (mouse) { + if (root.hoveredLink) { + MessagesAdapter.openUrl(root.hoveredLink); + } + } + property bool bubbleHovered: containsMouse || textHovered + } } EmojiReactions { @@ -376,7 +437,7 @@ Control { borderColor: root.getBaseColor() maxWidth: 2 / 3 * maxMsgWidth - JamiTheme.emojiMargins - state: root.isOutgoing ? "anchorsRight" : (emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight") + state: root.isOutgoing ? "anchorsRight" : (IsEmojiOnly ? "anchorsLeft" :(emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight")) TapHandler { onTapped: { @@ -519,7 +580,7 @@ Control { orientation: ListView.Horizontal Layout.preferredHeight: { if (showTime || seq === MsgSeq.last) - return contentHeight + timestampItem.contentHeight; + return contentHeight + dateItem.contentHeight; else if (readsMultiple.visible) return JamiTheme.avatarReadReceiptSize; return 0; diff --git a/src/app/commoncomponents/TextMessageDelegate.qml b/src/app/commoncomponents/TextMessageDelegate.qml index b97ea6f05..7004c2580 100644 --- a/src/app/commoncomponents/TextMessageDelegate.qml +++ b/src/app/commoncomponents/TextMessageDelegate.qml @@ -33,6 +33,8 @@ SBSMessageBase { property string colorUrl: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark property string colorText: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark + bigMsg: textEditId.lineCount > 1 + Connections { target: bubble function onColorChanged(color) { @@ -52,14 +54,14 @@ SBSMessageBase { formattedDay: MessagesAdapter.getFormattedDay(Timestamp) extraHeight: extraContent.active && !isRemoteImage ? msgRadius : -isRemoteImage textHovered: textHoverhandler.hovered - textContentWidth: textEditId.width + textContentWidth: textEditId.width + (bigMsg ? 0 : root.timeWidth + root.editedWidth) textContentHeight: textEditId.height innerContent.children: [ TextEdit { id: textEditId - padding: isEmojiOnly ? 0 : JamiTheme.preferredMarginSize + padding: isEmojiOnly ? 0 : 10 anchors.right: isOutgoing ? parent.right : undefined text: { if (Body !== "" && ParsedBody.length === 0) { @@ -80,9 +82,11 @@ SBSMessageBase { else if (isEmojiOnly) Math.min((2 / 3) * root.maxMsgWidth, implicitWidth, innerContent.width - senderMargin - (innerContent.width - senderMargin) % (JamiTheme.chatviewEmojiSize + 2)); else - Math.min((2 / 3) * root.maxMsgWidth, implicitWidth, innerContent.width - senderMargin); + Math.max(Math.min((2 / 3) * root.maxMsgWidth - ( bigMsg ? 0 : root.timeWidth + root.editedWidth), implicitWidth + 5, innerContent.width - senderMargin + 5), bigMsg ? root.timeWidth + root.editedWidth + 14: 0) ; } + anchors.rightMargin: bigMsg ? 0 : root.timeWidth + root.editedWidth + wrapMode: Label.WrapAtWordBoundaryOrAnywhere selectByMouse: true font.pointSize: isEmojiOnly ? JamiTheme.chatviewEmojiSize : JamiTheme.mediumFontSize @@ -126,48 +130,7 @@ SBSMessageBase { selectOnly: parent.readOnly } }, - RowLayout { - id: editedRow - - anchors.right: isOutgoing ? parent.right : undefined - visible: PreviousBodies.length !== 0 - - ResponsiveImage { - id: editedImage - - Layout.leftMargin: JamiTheme.preferredMarginSize - Layout.bottomMargin: JamiTheme.preferredMarginSize - source: JamiResources.round_edit_24dp_svg - width: JamiTheme.editedFontSize - height: JamiTheme.editedFontSize - layer { - enabled: true - effect: ColorOverlay { - color: editedLabel.color - } - } - } - - Text { - id: editedLabel - - Layout.rightMargin: JamiTheme.preferredMarginSize - Layout.bottomMargin: JamiTheme.preferredMarginSize - - text: JamiStrings.edited - color: root.colorText - font.pointSize: JamiTheme.editedFontSize - TapHandler { - acceptedButtons: Qt.LeftButton - onTapped: { - viewCoordinator.presentDialog(appWindow, "commoncomponents/EditedPopup.qml", { - "previousBodies": PreviousBodies - }); - } - } - } - }, Loader { id: extraContent diff --git a/src/app/commoncomponents/TimestampInfo.qml b/src/app/commoncomponents/TimestampInfo.qml index 5e9b6ce7b..14d0f92b1 100644 --- a/src/app/commoncomponents/TimestampInfo.qml +++ b/src/app/commoncomponents/TimestampInfo.qml @@ -31,6 +31,8 @@ ColumnLayout { property string formattedTime property string formattedDay property real detailsOpacity: 0.6 + property color timeColor: JamiTheme.chatviewSecondaryInformationColor + property alias timeLabel: formattedTimeLabel spacing: 0 @@ -97,8 +99,8 @@ ColumnLayout { Layout.topMargin: 30 Layout.bottomMargin: 30 Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom - color: JamiTheme.chatviewSecondaryInformationColor - visible: showTime || showDay + color: root.timeColor + visible: showTime Layout.preferredHeight: visible * implicitHeight font.pointSize: JamiTheme.smallFontSize } diff --git a/src/app/mainview/components/MessageListView.qml b/src/app/mainview/components/MessageListView.qml index bfff14cae..6ab323677 100644 --- a/src/app/mainview/components/MessageListView.qml +++ b/src/app/mainview/components/MessageListView.qml @@ -109,7 +109,7 @@ JamiListView { function isFirst() { if (!nItem) return true else { - if (item.showTime || item.isReply || nItem.isEmojiOnly ) { + if (item.showTime || item.isReply ) { return true } else if (nItem.author !== item.author) { return true @@ -121,7 +121,7 @@ JamiListView { function isLast() { if (!pItem) return true else { - if (pItem.showTime || pItem.isReply || pItem.isEmojiOnly) { + if (pItem.showTime || pItem.isReply) { return true } else if (pItem.author !== item.author) { return true diff --git a/src/app/messagesadapter.cpp b/src/app/messagesadapter.cpp index 0a6ccae43..4f2760e50 100644 --- a/src/app/messagesadapter.cpp +++ b/src/app/messagesadapter.cpp @@ -716,8 +716,7 @@ MessagesAdapter::getFormattedTime(const quint64 timestamp) auto curLocal = QLocale(curLang); auto curTime = QDateTime::fromSecsSinceEpoch(timestamp).time(); QString timeLocale; - timeLocale = curLocal.toString(curTime, curLocal.ShortFormat); - + timeLocale = curLocal.toString(curTime, curLocal.ShortFormat).toLower(); return timeLocale; } return QObject::tr("just now"); -- GitLab