diff --git a/qml.qrc b/qml.qrc
index 67fb8da2..71bf3277 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -161,10 +161,12 @@
src/commoncomponents/BackButton.qml
src/commoncomponents/JamiSwitch.qml
src/mainview/components/ReadOnlyFooter.qml
- src/commoncomponents/MessageDelegate.qml
+ src/commoncomponents/TextMessageDelegate.qml
src/mainview/components/MessageListView.qml
src/commoncomponents/MessageBubble.qml
src/constant/MsgSeq.qml
src/commoncomponents/SBSMessageBase.qml
+ src/commoncomponents/GeneratedMessageDelegate.qml
+ src/commoncomponents/DataTransferMessageDelegate.qml
diff --git a/src/commoncomponents/MessageDelegate.qml b/src/commoncomponents/DataTransferMessageDelegate.qml
similarity index 57%
rename from src/commoncomponents/MessageDelegate.qml
rename to src/commoncomponents/DataTransferMessageDelegate.qml
index 210530e9..287aab36 100644
--- a/src/commoncomponents/MessageDelegate.qml
+++ b/src/commoncomponents/DataTransferMessageDelegate.qml
@@ -1,7 +1,8 @@
-/*
+/*
* Copyright (C) 2021 by Savoir-faire Linux
* Author: Trevor Tabah
* Author: Andreas Traczyk
+ * Author: Mingrui Zhang
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,272 +25,48 @@ import QtGraphicalEffects 1.15
import QtWebEngine 1.10
import net.jami.Models 1.1
-import net.jami.Adapters 1.1
import net.jami.Constants 1.1
+import net.jami.Adapters 1.1
-Control {
+Loader {
id: root
- readonly property ListView listView: ListView.view
-
- readonly property bool isGenerated: Type === Interaction.Type.CALL ||
- Type === Interaction.Type.CONTACT
- readonly property string author: Author
- readonly property var body: Body
- readonly property var timestamp: Timestamp
- readonly property bool isOutgoing: model.Author === ""
- readonly property var formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
- readonly property var linkInfo: LinkPreviewInfo
property var mediaInfo
-
- readonly property real senderMargin: 64
- readonly property real avatarSize: 32
- readonly property real msgRadius: 18
- readonly property real hMargin: 12
-
property bool showTime: false
property int seq: MsgSeq.single
- width: parent ? parent.width : 0
- height: loader.height
+ width: ListView.view ? ListView.view.width : 0
- // message interaction
- property string hoveredLink
- MouseArea {
- id: itemMouseArea
- anchors.fill: parent
- acceptedButtons: Qt.LeftButton
- onClicked: {
- if (root.hoveredLink)
- Qt.openUrlExternally(root.hoveredLink)
+ sourceComponent: {
+ if (Status === Interaction.Status.TRANSFER_FINISHED) {
+ mediaInfo = MessagesAdapter.getMediaInfo(Body)
+ if (Object.keys(mediaInfo).length !== 0)
+ return localMediaMsgComp
}
+ return dataTransferMsgComp
}
- Loader {
- id: loader
-
- width: root.width
- height: sourceComponent.height
-
- sourceComponent: {
- switch (Type) {
- case Interaction.Type.TEXT: return textMsgComp
- case Interaction.Type.CALL:
- case Interaction.Type.CONTACT: return generatedMsgComp
- case Interaction.Type.DATA_TRANSFER:
- if (Status === Interaction.Status.TRANSFER_FINISHED) {
- mediaInfo = MessagesAdapter.getMediaInfo(Body)
- if (Object.keys(mediaInfo).length !== 0)
- return localMediaMsgComp
- }
- return dataTransferMsgComp
- default:
- // if this happens, adjust FilteredMsgListModel
- console.warn("Invalid message type has not been filtered.")
- return null
- }
- }
- }
-
- Component {
- id: textMsgComp
-
- SBSMessageBase {
- property real maxMsgWidth: root.width - senderMargin - 2 * hMargin - avatarBlockWidth
- property bool isRemoteImage
- isOutgoing: root.isOutgoing
- showTime: root.showTime
- seq: root.seq
- author: root.author
- formattedTime: root.formattedTime
- extraHeight: extraContent.active && !isRemoteImage ? msgRadius : -isRemoteImage
- innerContent.children: [
- TextEdit {
- padding: 10
- anchors.right: isOutgoing ? parent.right : undefined
- text: '' + body + ''
- width: {
- if (extraContent.active)
- Math.max(extraContent.width,
- Math.min(implicitWidth - avatarBlockWidth,
- extraContent.minSize) - senderMargin)
- else
- Math.min(implicitWidth, innerContent.width - senderMargin)
- }
- height: implicitHeight
- wrapMode: Label.WrapAtWordBoundaryOrAnywhere
- selectByMouse: true
- font.pointSize: 11
- font.hintingPreference: Font.PreferNoHinting
- renderType: Text.NativeRendering
- textFormat: TextEdit.RichText
- onLinkHovered: root.hoveredLink = hoveredLink
- onLinkActivated: Qt.openUrlExternally(hoveredLink)
- readOnly: true
- color: isOutgoing ?
- JamiTheme.messageOutTxtColor :
- JamiTheme.messageInTxtColor
- },
- Loader {
- id: extraContent
- width: sourceComponent.width
- height: sourceComponent.height
- anchors.right: isOutgoing ? parent.right : undefined
- property real minSize: 192
- property real maxSize: 320
- active: linkInfo.url !== undefined
- sourceComponent: ColumnLayout {
- id: previewContent
- spacing: 12
- Component.onCompleted: {
- isRemoteImage = MessagesAdapter.isRemoteImage(linkInfo.url)
- }
- HoverHandler {
- target: previewContent
- onHoveredChanged: {
- root.hoveredLink = hovered ? linkInfo.url : ""
- }
- cursorShape: Qt.PointingHandCursor
- }
- AnimatedImage {
- id: img
- cache: true
- source: isRemoteImage ?
- linkInfo.url :
- (hasImage ? linkInfo.image : "")
- fillMode: Image.PreserveAspectCrop
- mipmap: true
- antialiasing: true
- autoTransform: true
- asynchronous: true
- readonly property bool hasImage: linkInfo.image !== null
- property real aspectRatio: implicitWidth / implicitHeight
- property real adjustedWidth: Math.min(extraContent.maxSize,
- Math.max(extraContent.minSize,
- maxMsgWidth))
- Layout.preferredWidth: adjustedWidth
- Layout.preferredHeight: Math.ceil(adjustedWidth / aspectRatio)
- Rectangle {
- color: JamiTheme.previewImageBackgroundColor
- z: -1
- anchors.fill: parent
- }
- layer.enabled: isRemoteImage
- layer.effect: OpacityMask {
- maskSource: MessageBubble {
- Rectangle { height: msgRadius; width: parent.width }
- out: isOutgoing
- type: seq
- width: img.width
- height: img.height
- radius: msgRadius
- }
- }
- }
- Column {
- opacity: img.status !== Image.Loading
- visible: !isRemoteImage
- Layout.preferredWidth: img.width - 2 * hMargin
- Layout.leftMargin: hMargin
- Layout.rightMargin: hMargin
- spacing: 6
- Label {
- width: parent.width
- font.pointSize: 10
- font.hintingPreference: Font.PreferNoHinting
- wrapMode: Label.WrapAtWordBoundaryOrAnywhere
- renderType: Text.NativeRendering
- textFormat: TextEdit.RichText
- color: JamiTheme.previewTitleColor
- visible: linkInfo.title !== null
- text: linkInfo.title
- }
- Label {
- width: parent.width
- font.pointSize: 11
- font.hintingPreference: Font.PreferNoHinting
- wrapMode: Label.WrapAtWordBoundaryOrAnywhere
- renderType: Text.NativeRendering
- textFormat: TextEdit.RichText
- color: JamiTheme.previewSubtitleColor
- visible: linkInfo.description !== null
- text: '' + linkInfo.description + ''
- }
- Label {
- width: parent.width
- font.pointSize: 10
- font.hintingPreference: Font.PreferNoHinting
- wrapMode: Label.WrapAtWordBoundaryOrAnywhere
- renderType: Text.NativeRendering
- textFormat: TextEdit.RichText
- color: JamiTheme.previewSubtitleColor
- text: linkInfo.domain
- }
- }
- }
- }
- ]
- Component.onCompleted: {
- if (!Linkified) {
- MessagesAdapter.parseMessageUrls(Id, Body)
- }
- }
- }
- }
-
- Component {
- id: generatedMsgComp
-
- Column {
- width: root.width
- spacing: 2
- topPadding: 12
- bottomPadding: 12
-
- Label {
- width: parent.width
- text: body
- horizontalAlignment: Qt.AlignHCenter
- font.pointSize: 12
- color: JamiTheme.chatviewTextColor
- }
-
- Item {
- id: infoCell
-
- width: parent.width
- height: childrenRect.height
-
- Label {
- text: formattedTime
- color: JamiTheme.timestampColor
- visible: showTime || seq === MsgSeq.last
- height: visible * implicitHeight
- font.pointSize: 9
-
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
- }
- }
+ opacity: 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+ onLoaded: opacity = 1
Component {
id: dataTransferMsgComp
SBSMessageBase {
id: dataTransferItem
+
property var transferStats: MessagesAdapter.getTransferStats(Id, Status)
property bool canOpen: Status === Interaction.Status.TRANSFER_FINISHED || isOutgoing
property real maxMsgWidth: root.width - senderMargin -
- 2 * hMargin - avatarBlockWidth
+ 2 * hPadding - avatarBlockWidth
- buttonsLoader.width - 24 - 6 - 24
- isOutgoing: root.isOutgoing
+
+ isOutgoing: Author === ""
showTime: root.showTime
seq: root.seq
- author: root.author
- formattedTime: root.formattedTime
+ author: Author
+ formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
extraHeight: progressBar.visible ? 18 : 0
innerContent.children: [
RowLayout {
@@ -300,9 +77,8 @@ Control {
target: parent
enabled: canOpen
onHoveredChanged: {
- root.hoveredLink = enabled && hovered ?
- ("file:///" + body) :
- ""
+ dataTransferItem.hoveredLink = enabled && hovered ?
+ ("file:///" + Body) : ""
}
cursorShape: enabled ?
Qt.PointingHandCursor :
@@ -393,7 +169,7 @@ Control {
topPadding: 10
text: CurrentConversation.isSwarm ?
TransferName :
- body
+ Body
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
font.weight: Font.DemiBold
font.pointSize: 11
@@ -404,10 +180,10 @@ Control {
JamiTheme.messageInTxtColor
MouseArea {
anchors.fill: parent
+ propagateComposedEvents: true
cursorShape: canOpen ?
Qt.PointingHandCursor :
Qt.ArrowCursor
- onClicked: if(canOpen) itemMouseArea.clicked(mouse)
}
}
Label {
@@ -450,11 +226,13 @@ Control {
id: localMediaMsgComp
SBSMessageBase {
- isOutgoing: root.isOutgoing
+ id: localMediaMsgItem
+
+ isOutgoing: Author === ""
showTime: root.showTime
seq: root.seq
- author: root.author
- formattedTime: root.formattedTime
+ author: Author
+ formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
bubble.visible: false
innerContent.children: [
Loader {
@@ -522,7 +300,7 @@ Control {
antialiasing: true
autoTransform: false
asynchronous: true
- source: "file:///" + body
+ source: "file:///" + Body
property real aspectRatio: implicitWidth / implicitHeight
property real adjustedWidth: Math.min(maxSize,
Math.max(minSize,
@@ -547,7 +325,7 @@ Control {
HoverHandler {
target : parent
onHoveredChanged: {
- root.hoveredLink = hovered ? img.source : ""
+ localMediaMsgItem.hoveredLink = hovered ? img.source : ""
}
cursorShape: Qt.PointingHandCursor
}
@@ -557,8 +335,4 @@ Control {
]
}
}
-
- opacity: 0
- Behavior on opacity { NumberAnimation { duration: 40 } }
- Component.onCompleted: opacity = 1
}
diff --git a/src/commoncomponents/GeneratedMessageDelegate.qml b/src/commoncomponents/GeneratedMessageDelegate.qml
new file mode 100644
index 00000000..b69335c2
--- /dev/null
+++ b/src/commoncomponents/GeneratedMessageDelegate.qml
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Trevor Tabah
+ * Author: Andreas Traczyk
+ * Author: Mingrui Zhang
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+
+Column {
+ id: root
+
+ property bool showTime: false
+ property int seq: MsgSeq.single
+
+ width: ListView.view ? ListView.view.width : 0
+
+ spacing: 2
+ topPadding: 12
+ bottomPadding: 12
+
+ Label {
+ width: parent.width
+ text: Body
+ horizontalAlignment: Qt.AlignHCenter
+ font.pointSize: 12
+ color: JamiTheme.chatviewTextColor
+ }
+
+ Item {
+ id: infoCell
+
+ width: parent.width
+ height: childrenRect.height
+
+ Label {
+ text: MessagesAdapter.getFormattedTime(Timestamp)
+ color: JamiTheme.timestampColor
+ visible: showTime || seq === MsgSeq.last
+ height: visible * implicitHeight
+ font.pointSize: 9
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ opacity: 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+ Component.onCompleted: opacity = 1
+}
diff --git a/src/commoncomponents/SBSMessageBase.qml b/src/commoncomponents/SBSMessageBase.qml
index 0c9cafa7..ac211408 100644
--- a/src/commoncomponents/SBSMessageBase.qml
+++ b/src/commoncomponents/SBSMessageBase.qml
@@ -25,7 +25,7 @@ import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
-ColumnLayout {
+Control {
id: root
property alias avatarBlockWidth: avatarBlock.width
@@ -39,77 +39,99 @@ ColumnLayout {
property int seq
property string author
property string formattedTime
+ property string hoveredLink
readonly property real senderMargin: 64
readonly property real avatarSize: 32
readonly property real msgRadius: 18
- readonly property real hMargin: 12
+ readonly property real hPadding: 12
- anchors.left: parent.left
- anchors.right: parent.right
- anchors.leftMargin: hMargin
- anchors.rightMargin: hMargin
- spacing: 2
+ width: ListView.view ? ListView.view.width : 0
+ height: mainColumnLayout.implicitHeight
- RowLayout {
- Layout.preferredHeight: innerContent.height + root.extraHeight
- Layout.topMargin: (seq === MsgSeq.first || seq === MsgSeq.single) ? 6 : 0
- spacing: 0
- Item {
- id: avatarBlock
- Layout.preferredWidth: isOutgoing ? 0 : avatar.width + hMargin
- Layout.preferredHeight: isOutgoing ? 0 : bubble.height
- Avatar {
- id: avatar
- visible: !isOutgoing && (seq === MsgSeq.last || seq === MsgSeq.single)
- anchors.bottom: parent.bottom
- width: avatarSize
- height: avatarSize
- imageId: author
- showPresenceIndicator: false
- mode: Avatar.Mode.Contact
+ rightPadding: hPadding
+ leftPadding: hPadding
+
+ contentItem: ColumnLayout {
+ id: mainColumnLayout
+
+ anchors.centerIn: parent
+
+ width: parent.width
+
+ spacing: 2
+
+ RowLayout {
+ Layout.preferredHeight: innerContent.height + root.extraHeight
+ Layout.topMargin: (seq === MsgSeq.first || seq === MsgSeq.single) ? 6 : 0
+ spacing: 0
+ Item {
+ id: avatarBlock
+ Layout.preferredWidth: isOutgoing ? 0 : avatar.width + hPadding
+ Layout.preferredHeight: isOutgoing ? 0 : bubble.height
+ Avatar {
+ id: avatar
+ visible: !isOutgoing && (seq === MsgSeq.last || seq === MsgSeq.single)
+ anchors.bottom: parent.bottom
+ width: avatarSize
+ height: avatarSize
+ imageId: author
+ showPresenceIndicator: false
+ mode: Avatar.Mode.Contact
+ }
+ }
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Column {
+ id: innerContent
+ width: parent.width
+ // place actual content here
+ }
+ MessageBubble {
+ id: bubble
+ z:-1
+ out: isOutgoing
+ type: seq
+ color: isOutgoing ?
+ JamiTheme.messageOutBgColor :
+ JamiTheme.messageInBgColor
+ radius: msgRadius
+ anchors.right: isOutgoing ? parent.right : undefined
+ width: innerContent.childrenRect.width
+ height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0)
+ }
}
}
Item {
+ id: infoCell
+
Layout.fillWidth: true
- Layout.fillHeight: true
- Column {
- id: innerContent
- width: parent.width
- // place actual content here
- }
- MessageBubble {
- id: bubble
- z:-1
- out: isOutgoing
- type: seq
- color: isOutgoing ?
- JamiTheme.messageOutBgColor :
- JamiTheme.messageInBgColor
- radius: msgRadius
- anchors.right: isOutgoing ? parent.right : undefined
- width: innerContent.childrenRect.width
- height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0)
+ Layout.preferredHeight: childrenRect.height
+
+ Label {
+ text: formattedTime
+ color: JamiTheme.timestampColor
+ visible: showTime || seq === MsgSeq.last
+ height: visible * implicitHeight
+ font.pointSize: 9
+
+ anchors.right: !isOutgoing ? undefined : parent.right
+ anchors.rightMargin: 8
+ anchors.left: isOutgoing ? undefined : parent.left
+ anchors.leftMargin: avatarBlockWidth + 6
}
}
}
- Item {
- id: infoCell
- Layout.preferredWidth: parent.width
- Layout.preferredHeight: childrenRect.height
-
- Label {
- text: formattedTime
- color: JamiTheme.timestampColor
- visible: showTime || seq === MsgSeq.last
- height: visible * implicitHeight
- font.pointSize: 9
-
- anchors.right: !isOutgoing ? undefined : parent.right
- anchors.rightMargin: 8
- anchors.left: isOutgoing ? undefined : parent.left
- anchors.leftMargin: avatarBlockWidth + 6
+ MouseArea {
+ id: itemMouseArea
+ anchors.fill: parent
+ z: -1
+ acceptedButtons: Qt.LeftButton
+ onClicked: {
+ if (root.hoveredLink)
+ Qt.openUrlExternally(root.hoveredLink)
}
}
}
diff --git a/src/commoncomponents/TextMessageDelegate.qml b/src/commoncomponents/TextMessageDelegate.qml
new file mode 100644
index 00000000..61b71702
--- /dev/null
+++ b/src/commoncomponents/TextMessageDelegate.qml
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2021 by Savoir-faire Linux
+ * Author: Trevor Tabah
+ * Author: Andreas Traczyk
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import QtGraphicalEffects 1.15
+
+import net.jami.Models 1.1
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+
+SBSMessageBase {
+ id : root
+
+ property bool isRemoteImage
+ property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth
+
+ isOutgoing: Author === ""
+ author: Author
+ formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
+ extraHeight: extraContent.active && !isRemoteImage ? msgRadius : -isRemoteImage
+ innerContent.children: [
+ TextEdit {
+ padding: 10
+ anchors.right: isOutgoing ? parent.right : undefined
+ text: '' + Body + ''
+ width: {
+ if (extraContent.active)
+ Math.max(extraContent.width,
+ Math.min(implicitWidth - avatarBlockWidth,
+ extraContent.minSize) - senderMargin)
+ else
+ Math.min(implicitWidth, innerContent.width - senderMargin)
+ }
+ height: implicitHeight
+ wrapMode: Label.WrapAtWordBoundaryOrAnywhere
+ selectByMouse: true
+ font.pointSize: 11
+ font.hintingPreference: Font.PreferNoHinting
+ renderType: Text.NativeRendering
+ textFormat: TextEdit.RichText
+ onLinkHovered: root.hoveredLink = hoveredLink
+ onLinkActivated: Qt.openUrlExternally(hoveredLink)
+ readOnly: true
+ color: isOutgoing ?
+ JamiTheme.messageOutTxtColor :
+ JamiTheme.messageInTxtColor
+ },
+ Loader {
+ id: extraContent
+ width: sourceComponent.width
+ height: sourceComponent.height
+ anchors.right: isOutgoing ? parent.right : undefined
+ property real minSize: 192
+ property real maxSize: 320
+ active: LinkPreviewInfo.url !== undefined
+ sourceComponent: ColumnLayout {
+ id: previewContent
+ spacing: 12
+ Component.onCompleted: {
+ isRemoteImage = MessagesAdapter.isRemoteImage(LinkPreviewInfo.url)
+ }
+ HoverHandler {
+ target: previewContent
+ onHoveredChanged: {
+ root.hoveredLink = hovered ? LinkPreviewInfo.url : ""
+ }
+ cursorShape: Qt.PointingHandCursor
+ }
+ AnimatedImage {
+ id: img
+ cache: true
+ source: isRemoteImage ?
+ LinkPreviewInfo.url :
+ (hasImage ? LinkPreviewInfo.image : "")
+
+ fillMode: Image.PreserveAspectCrop
+ mipmap: true
+ antialiasing: true
+ autoTransform: true
+ asynchronous: true
+ readonly property bool hasImage: LinkPreviewInfo.image !== null
+ property real aspectRatio: implicitWidth / implicitHeight
+ property real adjustedWidth: Math.min(extraContent.maxSize,
+ Math.max(extraContent.minSize,
+ maxMsgWidth))
+ Layout.preferredWidth: adjustedWidth
+ Layout.preferredHeight: Math.ceil(adjustedWidth / aspectRatio)
+ Rectangle {
+ color: JamiTheme.previewImageBackgroundColor
+ z: -1
+ anchors.fill: parent
+ }
+ layer.enabled: isRemoteImage
+ layer.effect: OpacityMask {
+ maskSource: MessageBubble {
+ Rectangle { height: msgRadius; width: parent.width }
+ out: isOutgoing
+ type: seq
+ width: img.width
+ height: img.height
+ radius: msgRadius
+ }
+ }
+ }
+ Column {
+ opacity: img.status !== Image.Loading
+ visible: !isRemoteImage
+ Layout.preferredWidth: img.width - 2 * hPadding
+ Layout.leftMargin: hPadding
+ Layout.rightMargin: hPadding
+ spacing: 6
+ Label {
+ width: parent.width
+ font.pointSize: 10
+ font.hintingPreference: Font.PreferNoHinting
+ wrapMode: Label.WrapAtWordBoundaryOrAnywhere
+ renderType: Text.NativeRendering
+ textFormat: TextEdit.RichText
+ color: JamiTheme.previewTitleColor
+ visible: LinkPreviewInfo.title !== null
+ text: LinkPreviewInfo.title
+ }
+ Label {
+ width: parent.width
+ font.pointSize: 11
+ font.hintingPreference: Font.PreferNoHinting
+ wrapMode: Label.WrapAtWordBoundaryOrAnywhere
+ renderType: Text.NativeRendering
+ textFormat: TextEdit.RichText
+ color: JamiTheme.previewSubtitleColor
+ visible: LinkPreviewInfo.description !== null
+ text: '' + LinkPreviewInfo.description + ''
+ }
+ Label {
+ width: parent.width
+ font.pointSize: 10
+ font.hintingPreference: Font.PreferNoHinting
+ wrapMode: Label.WrapAtWordBoundaryOrAnywhere
+ renderType: Text.NativeRendering
+ textFormat: TextEdit.RichText
+ color: JamiTheme.previewSubtitleColor
+ text: LinkPreviewInfo.domain
+ }
+ }
+ }
+ }
+ ]
+
+ opacity: 0
+ Behavior on opacity { NumberAnimation { duration: 100 } }
+ Component.onCompleted: {
+ if (!Linkified) {
+ MessagesAdapter.parseMessageUrls(Id, Body)
+ }
+ opacity = 1
+ }
+}
diff --git a/src/mainview/components/MessageListView.qml b/src/mainview/components/MessageListView.qml
index 2224edc1..a320174b 100644
--- a/src/mainview/components/MessageListView.qml
+++ b/src/mainview/components/MessageListView.qml
@@ -20,6 +20,7 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
+import Qt.labs.qmlmodels 1.0
import net.jami.Models 1.1
import net.jami.Adapters 1.1
@@ -30,6 +31,118 @@ import "../../commoncomponents"
ListView {
id: root
+ function getDistanceToBottom() {
+ const scrollDiff = ScrollBar.vertical.position -
+ (1.0 - ScrollBar.vertical.size)
+ return Math.abs(scrollDiff) * contentHeight
+ }
+
+ function loadMoreMsgsIfNeeded() {
+ if (atYBeginning && !CurrentConversation.allMessagesLoaded)
+ MessagesAdapter.loadMoreMessages()
+ }
+
+ // sequencing/timestamps (2-sided style)
+ function computeTimestampVisibility(item, itemIndex) {
+ if (root === undefined)
+ return
+ var nItem = root.itemAtIndex(itemIndex - 1)
+ if (nItem && itemIndex !== root.count - 1) {
+ item.showTime = (nItem.timestamp - item.timestamp) > 60 &&
+ nItem.formattedTime !== item.formattedTime
+ } else {
+ item.showTime = true
+ var pItem = root.itemAtIndex(itemIndex + 1)
+ if (pItem) {
+ pItem.showTime = (item.timestamp - pItem.timestamp) > 60 &&
+ pItem.formattedTime !== item.formattedTime
+ }
+ }
+ }
+
+ function computeSequencing(computeItem, computeItemIndex) {
+ if (root === undefined)
+ return
+ var cItem = {
+ 'author': computeItem.author,
+ 'showTime': computeItem.showTime
+ }
+ var pItem = root.itemAtIndex(computeItemIndex + 1)
+ var nItem = root.itemAtIndex(computeItemIndex - 1)
+
+ let isSeq = (item0, item1) =>
+ item0.author === item1.author && !item0.showTime
+
+ let setSeq = function (newSeq, item) {
+ if (item === undefined)
+ computeItem.seq = newSeq
+ else
+ item.seq = newSeq
+ }
+
+ let rAdjustSeq = function (item) {
+ if (item.seq === MsgSeq.last)
+ item.seq = MsgSeq.middle
+ else if (item.seq === MsgSeq.single)
+ setSeq(MsgSeq.first, item)
+ }
+
+ let adjustSeq = function (item) {
+ if (item.seq === MsgSeq.first)
+ item.seq = MsgSeq.middle
+ else if (item.seq === MsgSeq.single)
+ setSeq(MsgSeq.last, item)
+ }
+
+ if (pItem && !nItem) {
+ if (!isSeq(pItem, cItem)) {
+ computeItem.seq = MsgSeq.single
+ } else {
+ computeItem.seq = MsgSeq.last
+ rAdjustSeq(pItem)
+ }
+ } else if (nItem && !pItem) {
+ if (!isSeq(cItem, nItem)) {
+ computeItem.seq = MsgSeq.single
+ } else {
+ setSeq(MsgSeq.first)
+ adjustSeq(nItem)
+ }
+ } else if (!nItem && !pItem) {
+ computeItem.seq = MsgSeq.single
+ } else {
+ if (isSeq(pItem, nItem)) {
+ if (isSeq(pItem, cItem)) {
+ computeItem.seq = MsgSeq.middle
+ } else {
+ computeItem.seq = MsgSeq.single
+
+ if (pItem.seq === MsgSeq.first)
+ pItem.seq = MsgSeq.single
+ else if (item.seq === MsgSeq.middle)
+ pItem.seq = MsgSeq.last
+
+ if (nItem.seq === MsgSeq.last)
+ nItem.seq = MsgSeq.single
+ else if (nItem.seq === MsgSeq.middle)
+ nItem.seq = MsgSeq.first
+ }
+ } else {
+ if (!isSeq(pItem, cItem)) {
+ computeItem.seq = MsgSeq.first
+ adjustSeq(pItem)
+ } else {
+ computeItem.seq = MsgSeq.last
+ rAdjustSeq(nItem)
+ }
+ }
+ }
+
+ if (computeItem.seq === MsgSeq.last) {
+ computeItem.showTime = true
+ }
+ }
+
// fade-in mechanism
Component.onCompleted: fadeAnimation.start()
Rectangle {
@@ -74,135 +187,64 @@ ListView {
model: MessagesAdapter.messageListModel
- delegate: MessageDelegate {
- // sequencing/timestamps (2-sided style)
- function computeTimestampVisibility() {
- if (listView === undefined)
- return
- var nItem = listView.itemAtIndex(index - 1)
- if (nItem && index !== listView.count - 1) {
- showTime = (nItem.timestamp - timestamp) > 60 &&
- nItem.formattedTime !== formattedTime
- } else {
- showTime = true
- var pItem = listView.itemAtIndex(index + 1)
- if (pItem) {
- pItem.showTime = (timestamp - pItem.timestamp) > 60 &&
- pItem.formattedTime !== formattedTime
- }
- }
- }
+ delegate: DelegateChooser {
+ id: delegateChooser
- function computeSequencing() {
- if (listView === undefined)
- return
- var cItem = {
- 'author': author,
- 'isGenerated': isGenerated,
- 'showTime': showTime
- }
- var pItem = listView.itemAtIndex(index + 1)
- var nItem = listView.itemAtIndex(index - 1)
-
- let isSeq = (item0, item1) =>
- item0.author === item1.author &&
- !(item0.isGenerated || item1.isGenerated) &&
- !item0.showTime
-
- let setSeq = function (newSeq, item) {
- if (item === undefined)
- seq = isGenerated ? MsgSeq.single : newSeq
- else
- item.seq = item.isGenerated ? MsgSeq.single : newSeq
- }
-
- let rAdjustSeq = function (item) {
- if (item.seq === MsgSeq.last)
- item.seq = MsgSeq.middle
- else if (item.seq === MsgSeq.single)
- setSeq(MsgSeq.first, item)
- }
-
- let adjustSeq = function (item) {
- if (item.seq === MsgSeq.first)
- item.seq = MsgSeq.middle
- else if (item.seq === MsgSeq.single)
- setSeq(MsgSeq.last, item)
- }
-
- if (pItem && !nItem) {
- if (!isSeq(pItem, cItem)) {
- seq = MsgSeq.single
- } else {
- seq = MsgSeq.last
- rAdjustSeq(pItem)
- }
- } else if (nItem && !pItem) {
- if (!isSeq(cItem, nItem)) {
- seq = MsgSeq.single
- } else {
- setSeq(MsgSeq.first)
- adjustSeq(nItem)
- }
- } else if (!nItem && !pItem) {
- seq = MsgSeq.single
- } else {
- if (isSeq(pItem, nItem)) {
- if (isSeq(pItem, cItem)) {
- seq = MsgSeq.middle
+ role: "Type"
+ DelegateChoice {
+ roleValue: Interaction.Type.TEXT
+ TextMessageDelegate {
+ Component.onCompleted: {
+ if (index) {
+ computeTimestampVisibility(this, index)
+ computeSequencing(this, index)
} else {
- seq = MsgSeq.single
-
- if (pItem.seq === MsgSeq.first)
- pItem.seq = MsgSeq.single
- else if (item.seq === MsgSeq.middle)
- pItem.seq = MsgSeq.last
-
- if (nItem.seq === MsgSeq.last)
- nItem.seq = MsgSeq.single
- else if (nItem.seq === MsgSeq.middle)
- nItem.seq = MsgSeq.first
- }
- } else {
- if (!isSeq(pItem, cItem)) {
- seq = MsgSeq.first
- adjustSeq(pItem)
- } else {
- seq = MsgSeq.last
- rAdjustSeq(nItem)
+ Qt.callLater(computeTimestampVisibility, this, index)
+ Qt.callLater(computeSequencing, this, index)
}
}
}
-
- if (seq === MsgSeq.last) {
- showTime = true
+ }
+ DelegateChoice {
+ roleValue: Interaction.Type.CALL
+ GeneratedMessageDelegate {
+ Component.onCompleted: {
+ if (index)
+ computeTimestampVisibility(this, index)
+ else
+ Qt.callLater(computeTimestampVisibility, this, index)
+ }
}
}
-
- Component.onCompleted: {
- if (index) {
- computeTimestampVisibility()
- computeSequencing()
- } else {
- Qt.callLater(computeTimestampVisibility)
- Qt.callLater(computeSequencing)
+ DelegateChoice {
+ roleValue: Interaction.Type.CONTACT
+ GeneratedMessageDelegate {
+ Component.onCompleted: {
+ if (index)
+ computeTimestampVisibility(this, index)
+ else
+ Qt.callLater(computeTimestampVisibility, this, index)
+ }
+ }
+ }
+ DelegateChoice {
+ roleValue: Interaction.Type.DATA_TRANSFER
+ DataTransferMessageDelegate {
+ Component.onCompleted: {
+ if (index) {
+ computeTimestampVisibility(this, index)
+ computeSequencing(this, index)
+ } else {
+ Qt.callLater(computeTimestampVisibility, this, index)
+ Qt.callLater(computeSequencing, this, index)
+ }
+ }
}
}
- }
-
- function getDistanceToBottom() {
- const scrollDiff = ScrollBar.vertical.position -
- (1.0 - ScrollBar.vertical.size)
- return Math.abs(scrollDiff) * contentHeight
}
onAtYBeginningChanged: loadMoreMsgsIfNeeded()
- function loadMoreMsgsIfNeeded() {
- if (atYBeginning && !CurrentConversation.allMessagesLoaded)
- MessagesAdapter.loadMoreMessages()
- }
-
Connections {
target: MessagesAdapter