mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-07-04 23:55:27 +02:00
chatview: timestamp improvements
New timestamp computation and sequencing ( by day and hour) GitLab: #827 Change-Id: Ie170f31c075dc37f00d393272410329dc045f2d3
This commit is contained in:
parent
c3e8e38e99
commit
d6ed9adf32
14 changed files with 366 additions and 255 deletions
1
qml.qrc
1
qml.qrc
|
@ -203,5 +203,6 @@
|
|||
<file>src/app/mainview/components/CustomizeTipBox.qml</file>
|
||||
<file>src/app/mainview/components/BackupTipBox.qml</file>
|
||||
<file>src/app/mainview/components/InformativeTipBox.qml</file>
|
||||
<file>src/app/commoncomponents/TimestampInfo.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -27,24 +27,36 @@ Column {
|
|||
id: root
|
||||
|
||||
property bool showTime: false
|
||||
property int seq: MsgSeq.single
|
||||
property alias font: textLabel.font
|
||||
|
||||
property bool showDay: false
|
||||
property int timestamp: Timestamp
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
property int seq: MsgSeq.single//a changer par textlabel
|
||||
width: ListView.view ? ListView.view.width : 0
|
||||
|
||||
spacing: 2
|
||||
topPadding: 12
|
||||
bottomPadding: 12
|
||||
|
||||
ColumnLayout {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
TimestampInfo {
|
||||
id:timestampItem
|
||||
|
||||
showDay: root.showDay
|
||||
showTime: root.showTime
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedDay
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: msg
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
width: childrenRect.width
|
||||
height: JamiTheme.contactMessageAvatarSize + 12
|
||||
radius: JamiTheme.contactMessageAvatarSize / 2 + 6
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: "transparent"
|
||||
border.width: 1
|
||||
border.color: CurrentConversation.isCoreDialog ? JamiTheme.messageInBgColor : CurrentConversation.color
|
||||
|
@ -54,20 +66,18 @@ Column {
|
|||
|
||||
Avatar {
|
||||
Layout.leftMargin: 6
|
||||
|
||||
width: JamiTheme.contactMessageAvatarSize
|
||||
height: JamiTheme.contactMessageAvatarSize
|
||||
visible: ActionUri !== ""
|
||||
|
||||
imageId: ActionUri !== CurrentAccount.uri ? ActionUri : CurrentAccount.id
|
||||
showPresenceIndicator: false
|
||||
mode: ActionUri !== CurrentAccount.uri ? Avatar.Mode.Contact : Avatar.Mode.Account
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.rightMargin: 6
|
||||
|
||||
id: textLabel
|
||||
|
||||
Layout.rightMargin: 6
|
||||
width: parent.width
|
||||
text: Body
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
|
@ -77,24 +87,7 @@ Column {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -31,7 +31,12 @@ Loader {
|
|||
id: root
|
||||
|
||||
property var mediaInfo
|
||||
property bool showTime: false
|
||||
property bool showTime
|
||||
property bool showDay
|
||||
property int timestamp: Timestamp
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
|
||||
property int seq: MsgSeq.single
|
||||
property string author: Author
|
||||
|
||||
|
@ -70,7 +75,9 @@ Loader {
|
|||
transferName: TransferName
|
||||
transferId: Id
|
||||
readers: Readers
|
||||
formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
timestamp: root.timestamp
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedTime
|
||||
extraHeight: progressBar.visible ? 18 : 0
|
||||
innerContent.children: [
|
||||
RowLayout {
|
||||
|
@ -247,6 +254,7 @@ Loader {
|
|||
transferId: Id
|
||||
readers: Readers
|
||||
formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
bubble.visible: false
|
||||
innerContent.children: [
|
||||
Loader {
|
||||
|
@ -332,7 +340,7 @@ Loader {
|
|||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: "file:///" + Body
|
||||
property real aspectRatio: implicitWidth / implicitHeight
|
||||
property real aspectRatio: width / implicitHeight
|
||||
property real adjustedWidth: Math.min(maxSize,
|
||||
Math.max(minSize,
|
||||
innerContent.width - senderMargin))
|
||||
|
|
|
@ -29,39 +29,38 @@ Column {
|
|||
id: root
|
||||
|
||||
property bool showTime: false
|
||||
property bool showDay: false
|
||||
property int seq: MsgSeq.single
|
||||
property alias font: textLabel.font
|
||||
|
||||
property int timestamp: Timestamp
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
width: ListView.view ? ListView.view.width : 0
|
||||
|
||||
spacing: 2
|
||||
topPadding: 12
|
||||
bottomPadding: 12
|
||||
ColumnLayout {
|
||||
|
||||
width: parent.width
|
||||
|
||||
TimestampInfo {
|
||||
id:timestampItem
|
||||
|
||||
showDay: root.showDay
|
||||
showTime: root.showTime
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedDay
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
id: textLabel
|
||||
width: parent.width
|
||||
|
||||
text: Body
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
Layout.alignment: 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
|
||||
|
|
|
@ -37,26 +37,26 @@ Control {
|
|||
|
||||
// these MUST be set but we won't use the 'required' keyword yet
|
||||
property bool isOutgoing
|
||||
property bool showTime
|
||||
property bool showTime: false
|
||||
property bool showDay: false
|
||||
property int seq
|
||||
property string author
|
||||
property string transferId
|
||||
property string registeredNameText
|
||||
property string transferName
|
||||
property string formattedTime
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
property string location
|
||||
property string id: Id
|
||||
property string hoveredLink
|
||||
property var readers: []
|
||||
|
||||
property int timestamp: Timestamp
|
||||
readonly property real senderMargin: 64
|
||||
readonly property real avatarSize: 20
|
||||
readonly property real msgRadius: 20
|
||||
readonly property real hPadding: JamiTheme.sbsMessageBasePreferredPadding
|
||||
|
||||
width: ListView.view ? ListView.view.width : 0
|
||||
height: mainColumnLayout.implicitHeight
|
||||
|
||||
rightPadding: hPadding
|
||||
leftPadding: hPadding
|
||||
|
||||
|
@ -64,11 +64,21 @@ Control {
|
|||
id: mainColumnLayout
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: parent.width - hPadding * 2
|
||||
|
||||
spacing: 0
|
||||
|
||||
TimestampInfo {
|
||||
id: timestampItem
|
||||
|
||||
showDay: root.showDay
|
||||
showTime: root.showTime
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedDay
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
id: usernameblock
|
||||
|
@ -78,7 +88,7 @@ Control {
|
|||
id: username
|
||||
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author)
|
||||
font.bold: true
|
||||
visible: (seq === MsgSeq.first || seq === MsgSeq.single) && !isOutgoing
|
||||
visible:(seq === MsgSeq.first || seq === MsgSeq.single) && !isOutgoing
|
||||
font.pixelSize: JamiTheme.usernameBlockFontSize
|
||||
color: JamiTheme.chatviewUsernameColor
|
||||
lineHeight: JamiTheme.usernameBlockLineHeight
|
||||
|
@ -107,13 +117,11 @@ Control {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: itemMouseArea
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: function (mouse) {
|
||||
if (mouse.button === Qt.RightButton
|
||||
|
@ -194,6 +202,7 @@ Control {
|
|||
id: readsOne
|
||||
|
||||
visible: root.readers.length === 1 && CurrentAccount.sendReadReceipt
|
||||
|
||||
width: {
|
||||
if (root.readers.length === 0)
|
||||
return 0
|
||||
|
@ -216,28 +225,12 @@ Control {
|
|||
orientation: ListView.Horizontal
|
||||
Layout.preferredHeight: {
|
||||
if (showTime || seq === MsgSeq.last)
|
||||
return contentHeight + formattedTimeLabel.contentHeight
|
||||
return contentHeight + timestampItem.contentHeight
|
||||
else if (readsMultiple.visible)
|
||||
return JamiTheme.avatarReadReceiptSize
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
Label {
|
||||
id: formattedTimeLabel
|
||||
|
||||
text: formattedTime
|
||||
color: JamiTheme.timestampColor
|
||||
visible: showTime || seq === MsgSeq.last
|
||||
height: visible * implicitHeight
|
||||
font.pointSize: 9
|
||||
topPadding : 4
|
||||
anchors.rightMargin: status.width
|
||||
anchors.right: !isOutgoing ? undefined : readsMultiple.left
|
||||
anchors.left: isOutgoing ? undefined : parent.left
|
||||
anchors.leftMargin: avatarBlockWidth + 6
|
||||
}
|
||||
|
||||
ReadStatus {
|
||||
id: readsMultiple
|
||||
visible: root.readers.length > 1 && CurrentAccount.sendReadReceipt
|
||||
|
@ -254,7 +247,6 @@ Control {
|
|||
anchors.topMargin: 1
|
||||
readers: root.readers
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import QtQuick
|
|||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
@ -31,25 +30,21 @@ SBSMessageBase {
|
|||
id : root
|
||||
|
||||
property bool isRemoteImage
|
||||
|
||||
property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth
|
||||
|
||||
isOutgoing: Author === ""
|
||||
author: Author
|
||||
readers: Readers
|
||||
timestamp: Timestamp
|
||||
formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
formattedDay: MessagesAdapter.getFormattedDay(Timestamp)
|
||||
extraHeight: extraContent.active && !isRemoteImage ? msgRadius : -isRemoteImage
|
||||
|
||||
innerContent.children: [
|
||||
TextEdit {
|
||||
|
||||
padding: JamiTheme.preferredMarginSize
|
||||
anchors.right: isOutgoing ? parent.right : undefined
|
||||
|
||||
text: Body
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
||||
width: {
|
||||
if (extraContent.active)
|
||||
Math.max(extraContent.width,
|
||||
|
@ -62,9 +57,7 @@ SBSMessageBase {
|
|||
height: implicitHeight
|
||||
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
|
||||
selectByMouse: true
|
||||
|
||||
font.pixelSize: JamiTheme.chatviewFontSize
|
||||
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.MarkdownText
|
||||
|
|
106
src/app/commoncomponents/TimestampInfo.qml
Normal file
106
src/app/commoncomponents/TimestampInfo.qml
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Savoir-faire Linux Inc.
|
||||
* Author: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "../mainview/components/"
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
ColumnLayout{
|
||||
id: root
|
||||
|
||||
property bool showTime
|
||||
property bool showDay
|
||||
property string formattedTime
|
||||
property string formattedDay
|
||||
property real detailsOpacity: 0.6
|
||||
|
||||
Connections {
|
||||
target: MessagesAdapter.messageListModel
|
||||
function onTimestampUpdate() {
|
||||
if (showTime || showDay) {
|
||||
formattedTime = MessagesAdapter.getFormattedTime(Timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
visible: showDay
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: JamiTheme.dayTimestampTopMargin
|
||||
|
||||
Rectangle {
|
||||
id: line
|
||||
|
||||
height: 1
|
||||
opacity: detailsOpacity
|
||||
color:JamiTheme.timestampColor
|
||||
width: chatView.width - JamiTheme.timestampLinePadding
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: dayRectangle
|
||||
|
||||
width: borderRectangle.width
|
||||
height: borderRectangle.height
|
||||
radius: 5
|
||||
color: JamiTheme.chatviewBgColor
|
||||
Layout.fillHeight: true
|
||||
anchors.centerIn: parent
|
||||
|
||||
Rectangle {
|
||||
id: borderRectangle
|
||||
|
||||
border { color: JamiTheme.timestampColor; width: 1}
|
||||
opacity: detailsOpacity
|
||||
width: formattedDayLabel.width + JamiTheme.dayTimestampVPadding
|
||||
height: formattedDayLabel.height + JamiTheme.dayTimestampHPadding
|
||||
radius: dayRectangle.radius
|
||||
color: JamiTheme.transparentColor
|
||||
}
|
||||
|
||||
Text {
|
||||
id: formattedDayLabel
|
||||
|
||||
color: JamiTheme.chatviewTextColor
|
||||
anchors { verticalCenter: parent.verticalCenter; horizontalCenter: parent.horizontalCenter}
|
||||
text: formattedDay
|
||||
font.pointSize: JamiTheme.timestampFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: formattedTimeLabel
|
||||
|
||||
text: formattedTime
|
||||
Layout.bottomMargin: JamiTheme.timestampBottomMargin
|
||||
Layout.topMargin: JamiTheme.timestampTopMargin
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: JamiTheme.timestampColor
|
||||
visible: showTime
|
||||
height: visible * implicitHeight
|
||||
font.pointSize: JamiTheme.timestampFont
|
||||
}
|
||||
}
|
|
@ -321,6 +321,16 @@ Item {
|
|||
property real lineEditContextMenuItemsWidth: 100
|
||||
property real lineEditContextMenuSeparatorsHeight: 2
|
||||
|
||||
//TimestampInfo
|
||||
property int timestampLinePadding: 40
|
||||
property int dayTimestampTopMargin: 30
|
||||
property int timestampBottomMargin: 42
|
||||
property int timestampTopMargin: 20
|
||||
property int dayTimestampHPadding: 16
|
||||
property real dayTimestampVPadding: 32
|
||||
property real timestampFont: calcSize(12)
|
||||
property int timestampIntervalTime: 120
|
||||
|
||||
|
||||
// Jami switch
|
||||
property real switchIndicatorRadius: 30
|
||||
|
|
|
@ -44,105 +44,95 @@ JamiListView {
|
|||
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 computeTimestampVisibility(item1, item1Index, item2, item2Index) {
|
||||
if (item1 && item2) {
|
||||
if (item1Index < item2Index) {
|
||||
item1.showTime = item1.timestamp - item2.timestamp > JamiTheme.timestampIntervalTime
|
||||
item1.showDay = item1.formattedDay !== item2.formattedDay
|
||||
}else {
|
||||
item2.showTime = item2.timestamp - item1.timestamp > JamiTheme.timestampIntervalTime
|
||||
item2.showDay = item2.formattedDay !== item1.formattedDay
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function computeSequencing(computeItem, computeItemIndex) {
|
||||
if (root === undefined)
|
||||
return
|
||||
var cItem = {
|
||||
'author': computeItem.author,
|
||||
'showTime': computeItem.showTime
|
||||
function computeChatview(item,itemIndex) {
|
||||
if (!root ) return
|
||||
var rootItem = root.itemAtIndex(0)
|
||||
var pItem = root.itemAtIndex(itemIndex - 1)
|
||||
var pItemIndex = itemIndex - 1
|
||||
var nItem = root.itemAtIndex(itemIndex + 1)
|
||||
var nItemIndex = itemIndex + 1
|
||||
//Middle insertion
|
||||
if (pItem && nItem) {
|
||||
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex)
|
||||
computeSequencing(nItemIndex, nItem, root.itemAtIndex(itemIndex + 2), item)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
//top buffer insertion = scroll up
|
||||
if (pItem && !nItem) {
|
||||
if (!isSeq(pItem, cItem)) {
|
||||
computeItem.seq = MsgSeq.single
|
||||
} else {
|
||||
computeItem.seq = MsgSeq.last
|
||||
rAdjustSeq(pItem)
|
||||
computeTimestampVisibility(item, itemIndex, pItem, pItemIndex)
|
||||
computeSequencing(pItemIndex, pItem, item, root.itemAtIndex(itemIndex - 2))
|
||||
}
|
||||
} else if (nItem && !pItem) {
|
||||
if (!isSeq(cItem, nItem)) {
|
||||
computeItem.seq = MsgSeq.single
|
||||
} else {
|
||||
setSeq(MsgSeq.first)
|
||||
adjustSeq(nItem)
|
||||
//bottom buffer insertion = scroll down
|
||||
if (!pItem && nItem) {
|
||||
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex)
|
||||
computeSequencing(nItemIndex, nItem, root.itemAtIndex(itemIndex + 2), item)
|
||||
}
|
||||
} 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
|
||||
//index 0 insertion = new message
|
||||
if (itemIndex === 0) {
|
||||
Qt.callLater(computeSequencing, itemIndex, item, root.itemAtIndex(itemIndex + 1), null)
|
||||
if (! computeTimestampVisibility(item, itemIndex, nItem, nItemIndex)) {
|
||||
Qt.callLater(computeChatview, item, itemIndex)
|
||||
}
|
||||
} else {
|
||||
if (!isSeq(pItem, cItem)) {
|
||||
computeItem.seq = MsgSeq.first
|
||||
adjustSeq(pItem)
|
||||
} else {
|
||||
computeItem.seq = MsgSeq.last
|
||||
rAdjustSeq(nItem)
|
||||
}
|
||||
//top element
|
||||
if(itemIndex === root.count - 1 && CurrentConversation.allMessagesLoaded) {
|
||||
item.showTime = true
|
||||
item.showDay = true
|
||||
}
|
||||
}
|
||||
|
||||
if (computeItem.seq === MsgSeq.last) {
|
||||
computeItem.showTime = true
|
||||
function computeSequencing(index, item, nItem, pItem) {
|
||||
if (root === undefined || !item)
|
||||
return
|
||||
|
||||
function isFirst() {
|
||||
if (!nItem) return true
|
||||
else{
|
||||
if (item.showTime) {
|
||||
return true
|
||||
}
|
||||
if (nItem.author !== item.author) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isLast() {
|
||||
if (!pItem) return true
|
||||
else{
|
||||
if (pItem.showTime) {
|
||||
return true
|
||||
}
|
||||
if (pItem.author !== item.author) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if (isLast() && isFirst())
|
||||
item.seq = MsgSeq.single
|
||||
if (!isLast() && isFirst())
|
||||
item.seq = MsgSeq.first
|
||||
if (isLast() && !isFirst())
|
||||
item.seq = MsgSeq.last
|
||||
if (!isLast() && !isFirst())
|
||||
item.seq = MsgSeq.middle
|
||||
}
|
||||
|
||||
// fade-in mechanism
|
||||
|
@ -189,6 +179,7 @@ JamiListView {
|
|||
width: parent.width
|
||||
// this offscreen caching is pretty huge
|
||||
// displayMarginEnd may be removed
|
||||
|
||||
displayMarginBeginning: 2048
|
||||
displayMarginEnd: 2048
|
||||
maximumFlickVelocity: 2048
|
||||
|
@ -216,65 +207,55 @@ JamiListView {
|
|||
id: delegateChooser
|
||||
|
||||
role: "Type"
|
||||
|
||||
DelegateChoice {
|
||||
id: delegateChoice
|
||||
|
||||
roleValue: Interaction.Type.TEXT
|
||||
|
||||
TextMessageDelegate {
|
||||
Component.onCompleted: {
|
||||
if (index) {
|
||||
computeTimestampVisibility(this, index)
|
||||
computeSequencing(this, index)
|
||||
} else {
|
||||
Qt.callLater(computeTimestampVisibility, this, index)
|
||||
Qt.callLater(computeSequencing, this, index)
|
||||
}
|
||||
computeChatview(this,index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: Interaction.Type.CALL
|
||||
|
||||
GeneratedMessageDelegate {
|
||||
Component.onCompleted: {
|
||||
if (index)
|
||||
computeTimestampVisibility(this, index)
|
||||
else
|
||||
Qt.callLater(computeTimestampVisibility, this, index)
|
||||
computeChatview(this,index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: Interaction.Type.CONTACT
|
||||
|
||||
ContactMessageDelegate {
|
||||
Component.onCompleted: {
|
||||
if (index)
|
||||
computeTimestampVisibility(this, index)
|
||||
else
|
||||
Qt.callLater(computeTimestampVisibility, this, index)
|
||||
computeChatview(this,index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DelegateChoice {
|
||||
roleValue: Interaction.Type.INITIAL
|
||||
|
||||
GeneratedMessageDelegate {
|
||||
font.bold: true
|
||||
Component.onCompleted: {
|
||||
if (index)
|
||||
computeTimestampVisibility(this, index)
|
||||
else
|
||||
Qt.callLater(computeTimestampVisibility, this, index)
|
||||
computeChatview(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)
|
||||
}
|
||||
computeChatview(this,index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -581,21 +581,41 @@ MessagesAdapter::getFormattedTime(const quint64 timestamp)
|
|||
{
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
const auto seconds = now.toSecsSinceEpoch() - timestamp;
|
||||
auto interval = qFloor(seconds / (3600 * 24));
|
||||
if (interval > 5)
|
||||
return QLocale::system().toString(QDateTime::fromSecsSinceEpoch(timestamp),
|
||||
QLocale::ShortFormat);
|
||||
if (interval > 1)
|
||||
return QObject::tr("%1 days ago").arg(interval);
|
||||
if (interval == 1)
|
||||
return QObject::tr("one day ago");
|
||||
interval = qFloor(seconds / 3600);
|
||||
if (interval > 1)
|
||||
return QObject::tr("%1 hours ago").arg(interval);
|
||||
if (interval == 1)
|
||||
return QObject::tr("one hour ago");
|
||||
interval = qFloor(seconds / 60);
|
||||
if (interval > 1)
|
||||
return QObject::tr("%1 minutes ago").arg(interval);
|
||||
auto interval = qFloor(seconds / 60);
|
||||
|
||||
if (interval > 1) {
|
||||
auto curLang = settingsManager_->getValue(Settings::Key::LANG);
|
||||
auto curLocal(QLocale(curLang.toString()));
|
||||
auto curTime = QDateTime::fromSecsSinceEpoch(timestamp).time();
|
||||
QString timeLocale;
|
||||
if (curLang == "SYSTEM")
|
||||
timeLocale = QLocale::system().toString(curTime, QLocale::system().ShortFormat);
|
||||
else
|
||||
timeLocale = curLocal.toString(curTime, curLocal.ShortFormat);
|
||||
|
||||
return timeLocale;
|
||||
}
|
||||
return QObject::tr("just now");
|
||||
}
|
||||
|
||||
QString
|
||||
MessagesAdapter::getFormattedDay(const quint64 timestamp)
|
||||
{
|
||||
auto now = QDate::currentDate();
|
||||
auto before = QDateTime::fromSecsSinceEpoch(timestamp).date();
|
||||
if (before == now)
|
||||
return QObject::tr("Today");
|
||||
if (before.daysTo(now) == 1)
|
||||
return QObject::tr("Yesterday");
|
||||
|
||||
auto curLang = settingsManager_->getValue(Settings::Key::LANG);
|
||||
auto curLocal(QLocale(curLang.toString()));
|
||||
auto curDate = QDateTime::fromSecsSinceEpoch(timestamp).date();
|
||||
QString dateLocale;
|
||||
if (curLang == "SYSTEM")
|
||||
dateLocale = QLocale::system().toString(curDate, QLocale::system().ShortFormat);
|
||||
else
|
||||
dateLocale = curLocal.toString(curDate, curLocal.ShortFormat);
|
||||
|
||||
return dateLocale;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ protected:
|
|||
Q_INVOKABLE QVariantMap isLocalImage(const QString& mimeName);
|
||||
Q_INVOKABLE QVariantMap getMediaInfo(const QString& msg);
|
||||
Q_INVOKABLE bool isRemoteImage(const QString& msg);
|
||||
Q_INVOKABLE QString getFormattedDay(const quint64 timestamp);
|
||||
Q_INVOKABLE QString getFormattedTime(const quint64 timestamp);
|
||||
Q_INVOKABLE void parseMessageUrls(const QString& messageId,
|
||||
const QString& msg,
|
||||
|
|
|
@ -62,7 +62,6 @@ RowLayout {
|
|||
Layout.preferredWidth: root.itemWidth
|
||||
Layout.preferredHeight: JamiTheme.preferredFieldHeight
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
font.pointSize: JamiTheme.buttonFontSize
|
||||
font.kerning: true
|
||||
|
||||
|
@ -91,7 +90,6 @@ RowLayout {
|
|||
|
||||
MaterialToolTip {
|
||||
id: toolTip
|
||||
|
||||
parent: textField
|
||||
visible: textField.hovered && (root.tooltipText.length > 0)
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
|
|
|
@ -36,7 +36,11 @@ using reverseIterator = MessageListModel::reverseIterator;
|
|||
|
||||
MessageListModel::MessageListModel(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{}
|
||||
, timestampTimer_(new QTimer(this))
|
||||
{
|
||||
connect(timestampTimer_, &QTimer::timeout, this, &MessageListModel::timestampUpdate);
|
||||
timestampTimer_->start(1000);
|
||||
}
|
||||
|
||||
QPair<iterator, bool>
|
||||
MessageListModel::emplace(const QString& msgId, interaction::Info message, bool beginning)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "api/interaction.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace lrc {
|
||||
namespace api {
|
||||
|
@ -125,6 +126,8 @@ public:
|
|||
void emitDataChanged(iterator it, VectorInt roles = {});
|
||||
void emitDataChanged(const QString& msgId, VectorInt roles = {});
|
||||
|
||||
Q_SIGNAL void timestampUpdate();
|
||||
|
||||
protected:
|
||||
using Role = MessageList::Role;
|
||||
|
||||
|
@ -144,6 +147,8 @@ private:
|
|||
iterator insertMessage(iterator it, item_t& message);
|
||||
void removeMessage(int index, iterator it);
|
||||
void moveMessage(int from, int to);
|
||||
|
||||
QTimer* timestampTimer_ {nullptr};
|
||||
};
|
||||
} // namespace api
|
||||
} // namespace lrc
|
||||
|
|
Loading…
Add table
Reference in a new issue