From 4c92cb9936fd8a6cd86c44632bc9a1f992a2ef15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Fri, 23 Feb 2024 16:37:46 -0500 Subject: [PATCH] chatview: add check for last sent message Change-Id: I233d5df05432371adf6b2bdf8e8de25bd7e65058 --- resources/icons/Receive.svg | 10 ++++++ src/app/commoncomponents/SBSMessageBase.qml | 40 ++++++++++++--------- src/app/net/jami/Constants/JamiTheme.qml | 1 + src/libclient/api/interaction.h | 5 +++ src/libclient/api/messagelistmodel.h | 4 +++ src/libclient/messagelistmodel.cpp | 30 +++++++++++++++- 6 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 resources/icons/Receive.svg diff --git a/resources/icons/Receive.svg b/resources/icons/Receive.svg new file mode 100644 index 000000000..1be71fbd7 --- /dev/null +++ b/resources/icons/Receive.svg @@ -0,0 +1,10 @@ +<svg id="Receive" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12"> + <defs> + <clipPath id="clip-path"> + <rect id="Rectangle_429" data-name="Rectangle 429" width="12" height="12" fill="none"/> + </clipPath> + </defs> + <g id="Group_225" data-name="Group 225" clip-path="url(#clip-path)"> + <path id="Path_333" data-name="Path 333" d="M6.43,8.784,3.007,5.362,4.06,4.309l2.37,2.37,4.314-4.314A5.966,5.966,0,0,0,6,0c-.032,0-.061.008-.094.01A5.98,5.98,0,0,0,.094,5.074,5.911,5.911,0,0,0,0,6a5.911,5.911,0,0,0,.094.926A5.98,5.98,0,0,0,5.906,11.99c.032,0,.061.01.094.01a6,6,0,0,0,5.533-8.32Z" fill="#60c880"/> + </g> +</svg> diff --git a/src/app/commoncomponents/SBSMessageBase.qml b/src/app/commoncomponents/SBSMessageBase.qml index 0f61ff34f..e458ec671 100644 --- a/src/app/commoncomponents/SBSMessageBase.qml +++ b/src/app/commoncomponents/SBSMessageBase.qml @@ -98,7 +98,6 @@ Control { Layout.fillHeight: true } - Label { id: username @@ -300,10 +299,7 @@ Control { anchors.verticalCenter: parent.verticalCenter anchors.right: isOutgoing ? optionButtonItem.right : undefined anchors.left: !isOutgoing ? optionButtonItem.left : undefined - visible: CurrentAccount.type !== Profile.Type.SIP - && root.type !== Interaction.Type.CALL - && Body !== "" - && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered) + visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered) source: JamiResources.more_vert_24dp_svg width: optionButtonItem.width / 2 height: optionButtonItem.height @@ -358,10 +354,7 @@ Control { anchors.rightMargin: 5 anchors.right: isOutgoing ? more.left : undefined anchors.left: !isOutgoing ? more.right : undefined - visible: CurrentAccount.type !== Profile.Type.SIP - && root.type !== Interaction.Type.CALL - && Body !== "" - && (bubbleArea.bubbleHovered || hovered || more.hovered || bgHandler.hovered) + visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || bgHandler.hovered) onClicked: { MessagesAdapter.editId = ""; @@ -389,14 +382,14 @@ Control { property bool bubbleHovered property string imgSource - width: (root.type === Interaction.Type.TEXT ? root.textContentWidth + ( IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth): innerContent.childrenRect.width) + width: (root.type === Interaction.Type.TEXT ? root.textContentWidth + (IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth) : innerContent.childrenRect.width) height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) + (root.bigMsg ? 15 : 0) HoverHandler { target: root enabled: root.type === Interaction.Type.DATA_TRANSFER onHoveredChanged: { - root.hoveredLink = enabled && hovered ? bubble.imgSource : "" + root.hoveredLink = enabled && hovered ? bubble.imgSource : ""; } } @@ -406,12 +399,12 @@ Control { showTime: IsEmojiOnly && !(root.seq === MsgSeq.last || root.seq === MsgSeq.single) ? false : true formattedTime: root.formattedTime - timeColor: IsEmojiOnly || root.timeUnderBubble? (JamiTheme.darkTheme ? "white" : "dark") : (UtilsAdapter.luma(bubble.color) ? "white" : "dark") + timeColor: IsEmojiOnly || root.timeUnderBubble ? (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|| root.timeUnderBubble) && !isOutgoing) ? parent.left : undefined + anchors.left: ((IsEmojiOnly || root.timeUnderBubble) && !isOutgoing) ? parent.left : undefined anchors.leftMargin: (IsEmojiOnly && !isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0 anchors.rightMargin: IsEmojiOnly ? ((isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0) : (root.timeUnderBubble ? 0 : 10) timeLabel.Layout.bottomMargin: { @@ -432,7 +425,7 @@ Control { anchors.left: root.bigMsg ? bubble.left : timestampItem.left anchors.bottom: parent.bottom anchors.bottomMargin: root.bigMsg || bubble.isDeleted ? 6 : 10 - anchors.leftMargin: root.bigMsg ? 10 : - timestampItem.width - 16 + anchors.leftMargin: root.bigMsg ? 10 : -timestampItem.width - 16 visible: bubble.isEdited z: 1 ResponsiveImage { @@ -489,7 +482,7 @@ Control { borderColor: root.getBaseColor() maxWidth: 2 / 3 * maxMsgWidth - JamiTheme.emojiMargins - state: root.isOutgoing ? "anchorsRight" : (IsEmojiOnly ? "anchorsLeft" :(emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight")) + state: root.isOutgoing ? "anchorsRight" : (IsEmojiOnly ? "anchorsLeft" : (emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight")) TapHandler { onTapped: { @@ -597,7 +590,7 @@ Control { radius: width / 2 width: 12 height: 12 - border.color: JamiTheme.tintedBlue + border.color: JamiTheme.sending border.width: 1 color: JamiTheme.transparentColor visible: isOutgoing && Status === Interaction.Status.SENDING @@ -605,6 +598,21 @@ Control { anchors.bottom: parent.bottom } + ResponsiveImage { + id: sent + + containerHeight: 12 + containerWidth: 12 + + width: 12 + height: 12 + + visible: IsLastSent && !readsOne.visible + anchors.bottom: parent.bottom + + source: JamiResources.receive_svg + } + ReadStatus { id: readsOne diff --git a/src/app/net/jami/Constants/JamiTheme.qml b/src/app/net/jami/Constants/JamiTheme.qml index e976bb7de..0a228c101 100644 --- a/src/app/net/jami/Constants/JamiTheme.qml +++ b/src/app/net/jami/Constants/JamiTheme.qml @@ -588,6 +588,7 @@ Item { property real cornerIconSize: 40 + property color sending: darkTheme ? "#8c8c8c" : "#7f7f7f" property color wizardIconColor: darkTheme ? "#8c8c8c" : "#7f7f7f" // InfoBox diff --git a/src/libclient/api/interaction.h b/src/libclient/api/interaction.h index acfbead61..7d2f68dae 100644 --- a/src/libclient/api/interaction.h +++ b/src/libclient/api/interaction.h @@ -413,6 +413,11 @@ struct Info Info& operator=(const Info& other) = delete; Info& operator=(Info&& other) = default; + bool sent() const + { + return status == Status::SUCCESS || status == Status::DISPLAYED || status == Status::TRANSFER_FINISHED; + } + void init(const MapStringString& message, const QString& accountURI) { type = to_type(message["type"]); diff --git a/src/libclient/api/messagelistmodel.h b/src/libclient/api/messagelistmodel.h index 582b1dde9..f765702e6 100644 --- a/src/libclient/api/messagelistmodel.h +++ b/src/libclient/api/messagelistmodel.h @@ -57,6 +57,7 @@ struct Info; X(FileExtension) \ X(Readers) \ X(IsEmojiOnly) \ + X(IsLastSent) \ X(Index) namespace MessageList { @@ -146,6 +147,9 @@ private: QMap<QString, QStringList> messageToReaders_; // {"messageId": ["peer1", "peer2"]} QMap<QString, QSet<QString>> replyTo_; + QString lastSent_; + int lastSentIdx_ {-1}; + iterator find(const QString& msgId); int move(iterator it, const QString& newParentId); QVariant data(int idx, int role = Qt::DisplayRole) const; diff --git a/src/libclient/messagelistmodel.cpp b/src/libclient/messagelistmodel.cpp index e466448ab..51f93090f 100644 --- a/src/libclient/messagelistmodel.cpp +++ b/src/libclient/messagelistmodel.cpp @@ -146,6 +146,14 @@ MessageListModel::insert(const QString& id, const interaction::Info& interaction } beginInsertRows(QModelIndex(), index, index); interactions_.emplace(interactions_.cbegin() + index, id, interaction); + // Update last sent if the message is outgoing and successful. + if (interaction.sent() && index > lastSentIdx_) { + auto oldIdx = indexOfMessage(lastSent_); + lastSentIdx_ = index; + lastSent_ = id; + auto modelIndex = QAbstractListModel::index(oldIdx, 0); + Q_EMIT dataChanged(modelIndex, modelIndex, {Role::IsLastSent}); + } endInsertRows(); return true; } @@ -160,6 +168,14 @@ MessageListModel::append(const QString& id, const interaction::Info& interaction } beginInsertRows(QModelIndex(), interactions_.size(), interactions_.size()); interactions_.emplace_back(id, interaction); + // Update last sent if the message is outgoing and successful. + if (interaction.sent()) { + auto oldIdx = indexOfMessage(lastSent_); + lastSentIdx_ = interactions_.size() - 1; + lastSent_ = id; + auto modelIndex = QAbstractListModel::index(oldIdx, 0); + Q_EMIT dataChanged(modelIndex, modelIndex, {Role::IsLastSent}); + } endInsertRows(); return true; } @@ -218,8 +234,18 @@ MessageListModel::updateStatus(const QString& id, it->second.body = newBody; roles.push_back(Role::Body); } - auto modelIndex = QAbstractListModel::index(indexOfMessage(id), 0); + // Update last sent if the message is outgoing and successful. + auto idx = indexOfMessage(id); + auto modelIndex = QAbstractListModel::index(idx, 0); Q_EMIT dataChanged(modelIndex, modelIndex, roles); + if (it->second.sent() && idx > lastSentIdx_) { + auto oldIdx = indexOfMessage(lastSent_); + lastSentIdx_ = idx; + lastSent_ = id; + Q_EMIT dataChanged(modelIndex, modelIndex, {Role::IsLastSent}); + modelIndex = QAbstractListModel::index(oldIdx, 0); + Q_EMIT dataChanged(modelIndex, modelIndex, {Role::IsLastSent}); + } return true; } @@ -486,6 +512,8 @@ MessageListModel::dataForItem(const item_t& item, int, int role) const } return QVariant(item.second.body); } + case Role::IsLastSent: + return QVariant(item.first == lastSent_); case Role::Timestamp: return QVariant::fromValue(item.second.timestamp); case Role::Duration: -- GitLab