import QtGraphicalEffects 1.0 import QtQuick 2.7 import QtQuick.Controls 2.4 import QtQuick.Controls.Material 2.0 import QtQuick.Layouts 1.3 import "../opaque" as Opaque import "../opaque/controls" as Awesome import "../opaque/theme" import "../opaque/fonts" Rectangle { id: root implicitHeight: Math.max(imgProfile.height, rectMessageBubble.height) height: implicitHeight color: Theme.backgroundMainColor property string message property string rawMessage property string from property string handle property string displayName property string messageID property bool fromMe property bool ackd property int timestamp property alias image: imgProfile.source property string error property bool calendarEvent property real logscale: 4 * Math.log10(gcd.themeScale + 1) Connections { target: gcd onAcknowledged: function(mid) { if (mid == messageID) { root.ackd = true } } onGroupSendError: function(mid, error) { if (mid == messageID) { root.error = error } } } Opaque.Portrait { id: imgProfile anchors.left: parent.left anchors.bottom: parent.bottom visible: !fromMe && !calendarEvent size: fromMe || calendarEvent ? 0 : Theme.contactPortraitSize * 0.5 badgeVisible: false portraitBorderColor: Theme.portraitOnlineBorderColor portraitColor: Theme.portraitOnlineBackgroundColor ToolTip.visible: ima.containsMouse //: Click to DM ToolTip.text: qsTr("dm-tooltip") MouseArea { id: ima anchors.fill: parent hoverEnabled: overlay.inGroup onClicked: { gcd.createContact(from) gcd.broadcast("ResetMessagePane") theStack.pane = theStack.messagePane gcd.loadMessagesPane(from) overlayStack.overlay = overlayStack.chatOverlay } } } Rectangle { // THIS IS JUST A PRETTY MESSAGE-HOLDING RECTANGLE id: rectMessageBubble height: (handle.visible ? handle.height : 0) + (10 * gcd.themeScale) + colMessageBubble.height + 8 width: colMessageBubble.width + 6 color: fromMe ? Theme.messageFromMeBackgroundColor : (calendarEvent ? Theme.messageFromOtherBackgroundColor : Theme.messageFromOtherBackgroundColor) radius: 15 * logscale anchors.left: fromMe ? undefined : (calendarEvent ? undefined : imgProfile.right) //parent.left anchors.right: fromMe ? (calendarEvent ? undefined : parent.right) : undefined anchors.horizontalCenter: calendarEvent ? parent.horizontalCenter : undefined anchors.topMargin: 5 // A sharp corner on the side of the "speaker" Rectangle { id: sharpCorner visible: !calendarEvent height: parent.radius width: parent.radius anchors.bottom: rectMessageBubble.bottom anchors.left: fromMe ? undefined : parent.left anchors.right: fromMe ? parent.right : undefined color: parent.color } Label { id: handle visible: !fromMe && !calendarEvent text: displayName color: Theme.messageFromOtherTextColor elide: Text.ElideRight width: parent.width - 20 // padding font.pixelSize: Theme.chatSize * gcd.themeScale font.weight: Font.Bold font.family: Fonts.applicationFontBold.name font.styleName: "Bold" leftPadding: 10 * gcd.themeScale topPadding: 10 * gcd.themeScale } Column { id: colMessageBubble width: Math.max(lbl.width, ts.width + ack.width + 10) anchors.top: fromMe ? parent.top : (calendarEvent ? parent.top : handle.bottom) anchors.topMargin: 10 * gcd.themeScale TextEdit { // this is used as a helper to calculate the message box width id: dummy visible: false padding: 6 * gcd.themeScale leftPadding: 10 * gcd.themeScale font.pixelSize: gcd.themeScale * Theme.chatSize wrapMode: TextEdit.NoWrap text: lbl.text textFormat: Text.RichText } TextEdit { // this is the actual text display id: lbl text: parse(message, 12, true) color: fromMe ? Theme.messageFromMeTextColor : Theme.messageFromOtherTextColor padding: 6 * gcd.themeScale leftPadding: 10 * gcd.themeScale font.pixelSize: gcd.themeScale * Theme.chatSize selectByMouse: gcd.os != "android" readOnly: true width: Math.min(dummy.width, root.parent.width - (imgProfile.visible ? imgProfile.width : 0) - 40) wrapMode: TextEdit.Wrap textFormat: Text.RichText } Row { id: rowBottom anchors.right: parent.right visible: !calendarEvent Opaque.ScalingLabel { // TIMESTAMP id: ts text: Qt.formatDateTime(new Date(root.timestamp*1000), "h:mm ap") color: fromMe ? Theme.messageFromMeTextColor : Theme.messageFromOtherTextColor font.pixelSize: Theme.chatMetaTextSize * gcd.themeScale rightPadding: 10 } Image { // ACKNOWLEDGEMENT ICON id: ack source: root.error != "" ? gcd.assetPath + "core/fontawesome/regular/window-close.webp" : (root.ackd ? gcd.assetPath + "core/fontawesome/regular/check-circle.webp" : gcd.assetPath + "core/fontawesome/regular/hourglass.svg") height: Theme.chatMetaTextSize * gcd.themeScale width: Theme.chatMetaTextSize * gcd.themeScale anchors.bottom: parent.bottom sourceSize.height: Theme.chatMetaTextSize * gcd.themeScale visible: fromMe ToolTip.visible: ma.containsMouse ToolTip.delay: 200 //: Could not send this message ToolTip.text: root.error != "" ? qsTr("could-not-send-msg-error") + ":" + root.error : (root.ackd ? qsTr("acknowledged-label") : qsTr("pending-label")) MouseArea { id: ma anchors.fill: parent hoverEnabled: true } } } } TextEdit { id: copyhelper visible: false text: root.rawMessage } MouseArea { anchors.fill: gcd.os == "android" ? parent : null onPressAndHold: { copyhelper.selectAll() copyhelper.copy() gcd.popup("message copied") } } } }