From 23accc50d6f18f063ab4edc4432546a0e6b84b73 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Tue, 1 May 2018 23:32:11 +0300 Subject: [PATCH] Show user avatar for messages on different day or time gap > 15 mins fixes #278 --- include/timeline/TimelineView.h | 39 +++++++++++++++++----- src/timeline/TimelineView.cc | 59 +++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/include/timeline/TimelineView.h b/include/timeline/TimelineView.h index f94d0c47..ab4fbd47 100644 --- a/include/timeline/TimelineView.h +++ b/include/timeline/TimelineView.h @@ -186,6 +186,21 @@ private: void updateLastSender(const QString &user_id, TimelineDirection direction); void notifyForLastEvent(); void notifyForLastEvent(const TimelineEvent &event); + //! Keep track of the sender and the timestamp of the current message. + void saveLastMessageInfo(const QString &sender, const QDateTime &datetime) + { + lastSender_ = sender; + lastMsgTimestamp_ = datetime; + } + void saveFirstMessageInfo(const QString &sender, const QDateTime &datetime) + { + firstSender_ = sender; + firstMsgTimestamp_ = datetime; + } + //! Keep track of the sender and the timestamp of the current message. + void saveMessageInfo(const QString &sender, + uint64_t origin_server_ts, + TimelineDirection direction); TimelineEvent findFirstViewableEvent(const std::vector &events); TimelineEvent findLastViewableEvent(const std::vector &events); @@ -218,7 +233,9 @@ private: // Used to determine whether or not we should prefix a message with the // sender's name. - bool isSenderRendered(const QString &user_id, TimelineDirection direction); + bool isSenderRendered(const QString &user_id, + uint64_t origin_server_ts, + TimelineDirection direction); bool isPendingMessage(const QString &txnid, const QString &sender, const QString &userid); void removePendingMessage(const QString &txnid); @@ -226,6 +243,8 @@ private: bool isDuplicate(const QString &event_id) { return eventIds_.contains(event_id); } void handleNewUserMessage(PendingMessage msg); + bool isDateDifference(const QDateTime &first, + const QDateTime &second = QDateTime::currentDateTime()) const; // Return nullptr if the event couldn't be parsed. TimelineItem *parseMessageEvent(const mtx::events::collections::TimelineEvents &event, @@ -238,8 +257,11 @@ private: ScrollBar *scrollbar_; QWidget *scroll_widget_; - QString lastSender_; QString firstSender_; + QDateTime firstMsgTimestamp_; + QString lastSender_; + QDateTime lastMsgTimestamp_; + QString room_id_; QString prev_batch_token_; QString local_user_; @@ -289,7 +311,7 @@ TimelineView::addUserMessage(const QString &url, const QString &mime, uint64_t size) { - auto with_sender = lastSender_ != local_user_; + auto with_sender = (lastSender_ != local_user_) || isDateDifference(lastMsgTimestamp_); auto trimmed = QFileInfo{filename}.fileName(); // Trim file path. auto widget = new Widget(client_, url, trimmed, size, this); @@ -303,7 +325,8 @@ TimelineView::addUserMessage(const QString &url, QApplication::processEvents(); - lastSender_ = local_user_; + // Keep track of the sender and the timestamp of the current message. + saveLastMessageInfo(local_user_, QDateTime::currentDateTime()); int txn_id = client_->incrementTransactionId(); @@ -343,9 +366,9 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio return nullptr; } - auto with_sender = isSenderRendered(sender, direction); + auto with_sender = isSenderRendered(sender, event.origin_server_ts, direction); - updateLastSender(sender, direction); + saveMessageInfo(sender, event.origin_server_ts, direction); auto item = createTimelineItem(event, with_sender); @@ -368,9 +391,9 @@ TimelineView::processMessageEvent(const Event &event, TimelineDirection directio return nullptr; } - auto with_sender = isSenderRendered(sender, direction); + auto with_sender = isSenderRendered(sender, event.origin_server_ts, direction); - updateLastSender(sender, direction); + saveMessageInfo(sender, event.origin_server_ts, direction); auto item = createTimelineItem(event, with_sender); diff --git a/src/timeline/TimelineView.cc b/src/timeline/TimelineView.cc index 3a8e1c3d..8781f90e 100644 --- a/src/timeline/TimelineView.cc +++ b/src/timeline/TimelineView.cc @@ -323,6 +323,7 @@ TimelineView::renderTopEvents(const std::vector &events) // Reset the sender of the first message in the timeline // cause we're about to insert a new one. firstSender_.clear(); + firstMsgTimestamp_ = QDateTime(); // Parse in reverse order to determine where we should not show sender's // name. @@ -352,7 +353,8 @@ TimelineView::renderTopEvents(const std::vector &events) // If this batch is the first being rendered (i.e the first and the last // events originate from this batch), set the last sender. if (lastSender_.isEmpty() && !items.empty()) - lastSender_ = items.at(0)->descriptionMessage().userid; + saveLastMessageInfo(items.at(0)->descriptionMessage().userid, + items.at(0)->descriptionMessage().datetime); } void @@ -453,12 +455,19 @@ TimelineView::updateLastSender(const QString &user_id, TimelineDirection directi } bool -TimelineView::isSenderRendered(const QString &user_id, TimelineDirection direction) +TimelineView::isSenderRendered(const QString &user_id, + uint64_t origin_server_ts, + TimelineDirection direction) { - if (direction == TimelineDirection::Bottom) - return lastSender_ != user_id; - else - return firstSender_ != user_id; + if (direction == TimelineDirection::Bottom) { + return (lastSender_ != user_id) || + isDateDifference(lastMsgTimestamp_, + QDateTime::fromMSecsSinceEpoch(origin_server_ts)); + } else { + return (firstSender_ != user_id) || + isDateDifference(firstMsgTimestamp_, + QDateTime::fromMSecsSinceEpoch(origin_server_ts)); + } } void @@ -529,7 +538,7 @@ TimelineView::updatePendingMessage(int txn_id, QString event_id) void TimelineView::addUserMessage(mtx::events::MessageType ty, const QString &body) { - auto with_sender = lastSender_ != local_user_; + auto with_sender = (lastSender_ != local_user_) || isDateDifference(lastMsgTimestamp_); TimelineItem *view_item = new TimelineItem(ty, local_user_, body, with_sender, room_id_, scroll_widget_); @@ -540,7 +549,7 @@ TimelineView::addUserMessage(mtx::events::MessageType ty, const QString &body) QApplication::processEvents(); - lastSender_ = local_user_; + saveLastMessageInfo(local_user_, QDateTime::currentDateTime()); int txn_id = client_->incrementTransactionId(); PendingMessage message(ty, txn_id, body, "", "", -1, "", view_item); @@ -774,16 +783,20 @@ TimelineView::removeEvent(const QString &event_id) // If we deleted the last item in the timeline... if (!nextItem && prevItem) - lastSender_ = prevItem->descriptionMessage().userid; + saveLastMessageInfo(prevItem->descriptionMessage().userid, + prevItem->descriptionMessage().datetime); // If we deleted the first item in the timeline... if (!prevItem && nextItem) - firstSender_ = nextItem->descriptionMessage().userid; + saveFirstMessageInfo(nextItem->descriptionMessage().userid, + nextItem->descriptionMessage().datetime); // If we deleted the only item in the timeline... if (!prevItem && !nextItem) { firstSender_.clear(); + firstMsgTimestamp_ = QDateTime(); lastSender_.clear(); + lastMsgTimestamp_ = QDateTime(); } // Finally remove the event. @@ -835,3 +848,29 @@ TimelineView::getEventType(const mtx::events::collections::TimelineEvents &event { return mpark::visit([](auto msg) { return msg.type; }, event); } + +void +TimelineView::saveMessageInfo(const QString &sender, + uint64_t origin_server_ts, + TimelineDirection direction) +{ + updateLastSender(sender, direction); + + if (direction == TimelineDirection::Bottom) + lastMsgTimestamp_ = QDateTime::fromMSecsSinceEpoch(origin_server_ts); + else + firstMsgTimestamp_ = QDateTime::fromMSecsSinceEpoch(origin_server_ts); +} + +bool +TimelineView::isDateDifference(const QDateTime &first, const QDateTime &second) const +{ + // Check if the dates are in a different day. + if (std::abs(first.daysTo(second)) != 0) + return true; + + const uint64_t diffInSeconds = std::abs(first.msecsTo(second)) / 1000; + constexpr uint64_t fifteenMins = 15 * 60; + + return diffInSeconds > fifteenMins; +}