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