From 92c58b0ea09f7ee88103d6c264a52e1a74e21e8a Mon Sep 17 00:00:00 2001 From: James Graham Date: Sun, 25 Jan 2026 13:01:31 +0000 Subject: [PATCH] Improve time handling in NeoChat This introduces a new NeoChatDateTime object that wraps a QDateTime. The intent is that it can be passed to QML and has a series of functions that format the QDateTime into the various string representations we need. This means we only have to send the single object to QML and then the correct string can be grabbed from there, simplifying the backend. It is also easy to add a new representation if needed as a function with a QString output and Q_PROPERTY can be added and then it will be available. --- autotests/eventhandlertest.cpp | 39 +-------- src/libneochat/CMakeLists.txt | 1 + src/libneochat/eventhandler.cpp | 21 +---- src/libneochat/eventhandler.h | 38 +------- src/libneochat/neochatdatetime.cpp | 48 +++++++++++ src/libneochat/neochatdatetime.h | 86 +++++++++++++++++++ src/messagecontent/AuthorComponent.qml | 13 +-- .../models/eventmessagecontentmodel.cpp | 23 ++--- .../models/eventmessagecontentmodel.h | 3 +- .../models/messagecontentmodel.cpp | 18 ++-- .../models/messagecontentmodel.h | 16 ++-- src/timeline/MessageDelegate.qml | 6 +- src/timeline/StateDelegate.qml | 6 +- .../models/mediamessagefiltermodel.cpp | 6 +- src/timeline/models/messagefiltermodel.cpp | 11 ++- src/timeline/models/messagemodel.cpp | 25 ++---- src/timeline/models/messagemodel.h | 3 +- 17 files changed, 191 insertions(+), 172 deletions(-) create mode 100644 src/libneochat/neochatdatetime.cpp create mode 100644 src/libneochat/neochatdatetime.h diff --git a/autotests/eventhandlertest.cpp b/autotests/eventhandlertest.cpp index 2c9da178f..ff6dbfc06 100644 --- a/autotests/eventhandlertest.cpp +++ b/autotests/eventhandlertest.cpp @@ -40,7 +40,6 @@ private Q_SLOTS: void nullSingleLineDisplayName(); void time(); void nullTime(); - void timeString(); void highlighted(); void nullHighlighted(); void hidden(); @@ -100,12 +99,12 @@ void EventHandlerTest::time() { const auto event = room->messageEvents().at(0).get(); - QCOMPARE(EventHandler::time(room, event), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC))); + QCOMPARE(EventHandler::dateTime(room, event), QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC))); const auto txID = room->postJson("m.room.message"_L1, event->fullJson()); QCOMPARE(room->pendingEvents().size(), 1); const auto pendingIt = room->findPendingEvent(txID); - QCOMPARE(EventHandler::time(room, pendingIt->event(), true), pendingIt->lastUpdated()); + QCOMPARE(EventHandler::dateTime(room, pendingIt->event(), true), pendingIt->lastUpdated()); room->discardMessage(txID); QCOMPARE(room->pendingEvents().size(), 0); @@ -114,40 +113,10 @@ void EventHandlerTest::time() void EventHandlerTest::nullTime() { QTest::ignoreMessage(QtWarningMsg, "time called with room set to nullptr."); - QCOMPARE(EventHandler::time(nullptr, nullptr), QDateTime()); + QCOMPARE(EventHandler::dateTime(nullptr, nullptr), QDateTime()); QTest::ignoreMessage(QtWarningMsg, "time called with event set to nullptr."); - QCOMPARE(EventHandler::time(room, nullptr), QDateTime()); -} - -void EventHandlerTest::timeString() -{ - const auto event = room->messageEvents().at(0).get(); - - KFormat format; - - QCOMPARE(EventHandler::timeString(room, event, false), - QLocale().toString(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().time(), QLocale::ShortFormat)); - QCOMPARE(EventHandler::timeString(room, event, true), - format.formatRelativeDate(QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::UTC)).toLocalTime().date(), QLocale::ShortFormat)); - QCOMPARE(EventHandler::timeString(room, event, u"hh:mm"_s), - QDateTime::fromMSecsSinceEpoch(1432735824654, QTimeZone(QTimeZone::LocalTime)).toString(u"hh:mm"_s)); - - const auto txID = room->postJson("m.room.message"_L1, event->fullJson()); - QCOMPARE(room->pendingEvents().size(), 1); - const auto pendingIt = room->findPendingEvent(txID); - - QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::ShortFormat, true), - QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::ShortFormat)); - QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::ShortFormat, true), - format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::ShortFormat)); - QCOMPARE(EventHandler::timeString(room, pendingIt->event(), false, QLocale::LongFormat, true), - QLocale().toString(pendingIt->lastUpdated().toLocalTime().time(), QLocale::LongFormat)); - QCOMPARE(EventHandler::timeString(room, pendingIt->event(), true, QLocale::LongFormat, true), - format.formatRelativeDate(pendingIt->lastUpdated().toLocalTime().date(), QLocale::LongFormat)); - - room->discardMessage(txID); - QCOMPARE(room->pendingEvents().size(), 0); + QCOMPARE(EventHandler::dateTime(room, nullptr), QDateTime()); } void EventHandlerTest::highlighted() diff --git a/src/libneochat/CMakeLists.txt b/src/libneochat/CMakeLists.txt index be18088b7..309d98927 100644 --- a/src/libneochat/CMakeLists.txt +++ b/src/libneochat/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(LibNeoChat PRIVATE filetransferpseudojob.cpp filetype.cpp linkpreviewer.cpp + neochatdatetime.cpp roomlastmessageprovider.cpp spacehierarchycache.cpp texthandler.cpp diff --git a/src/libneochat/eventhandler.cpp b/src/libneochat/eventhandler.cpp index 68fd31a01..9d8b41030 100644 --- a/src/libneochat/eventhandler.cpp +++ b/src/libneochat/eventhandler.cpp @@ -93,7 +93,7 @@ QString EventHandler::singleLineAuthorDisplayname(const NeoChatRoom *room, const return displayName; } -QDateTime EventHandler::time(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending) +NeoChatDateTime EventHandler::dateTime(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending) { if (room == nullptr) { qCWarning(EventHandling) << "time called with room set to nullptr."; @@ -114,25 +114,6 @@ QDateTime EventHandler::time(const NeoChatRoom *room, const Quotient::RoomEvent return event->originTimestamp(); } -QString EventHandler::timeString(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool relative, QLocale::FormatType format, bool isPending) -{ - auto ts = time(room, event, isPending); - if (ts.isValid()) { - if (relative) { - KFormat formatter; - return formatter.formatRelativeDate(ts.toLocalTime().date(), format); - } else { - return QLocale().toString(ts.toLocalTime().time(), format); - } - } - return {}; -} - -QString EventHandler::timeString(const NeoChatRoom *room, const Quotient::RoomEvent *event, const QString &format, bool isPending) -{ - return time(room, event, isPending).toLocalTime().toString(format); -} - bool EventHandler::isHighlighted(const NeoChatRoom *room, const Quotient::RoomEvent *event) { if (room == nullptr) { diff --git a/src/libneochat/eventhandler.h b/src/libneochat/eventhandler.h index baee8d48c..d48f0dbf3 100644 --- a/src/libneochat/eventhandler.h +++ b/src/libneochat/eventhandler.h @@ -7,6 +7,8 @@ #include #include +#include "neochatdatetime.h" + namespace Quotient { namespace EventContent @@ -64,41 +66,7 @@ public: /** * @brief Return a QDateTime object for the event timestamp. */ - static QDateTime time(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending = false); - - /** - * @brief Return a QString for the event timestamp. - * - * This is intended to return a string that is read for display in the UI without - * any further manipulation required. - * - * @param relative whether the string is realtive to the current date, i.e. - * Yesterday or Wednesday, etc. - * @param format the QLocale::FormatType to use. - * @param isPending whether the event is pending as this cannot be derived from - * just the event object. - * @param lastUpdated the time the event was last updated locally as this cannot be - * obtained from the event. - */ - static QString timeString(const NeoChatRoom *room, - const Quotient::RoomEvent *event, - bool relative, - QLocale::FormatType format = QLocale::ShortFormat, - bool isPending = false); - - /** - * @brief Return a QString for the event timestamp. - * - * This is intended to return a string that is read for display in the UI without - * any further manipulation required. - * - * @param format the format to use as a string. - * @param isPending whether the event is pending as this cannot be derived from - * just the event object. - * @param lastUpdated the time the event was last updated locally as this cannot be - * obtained from the event. - */ - static QString timeString(const NeoChatRoom *room, const Quotient::RoomEvent *event, const QString &format, bool isPending = false); + static NeoChatDateTime dateTime(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending = false); /** * @brief Whether the event should be highlighted in the timeline. diff --git a/src/libneochat/neochatdatetime.cpp b/src/libneochat/neochatdatetime.cpp new file mode 100644 index 000000000..ae541a95c --- /dev/null +++ b/src/libneochat/neochatdatetime.cpp @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2026 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +#include "neochatdatetime.h" + +#include + +using namespace Qt::Literals::StringLiterals; + +NeoChatDateTime::NeoChatDateTime(QDateTime dateTime) + : m_dateTime(dateTime) +{ +} + +QDateTime NeoChatDateTime::dateTime() const +{ + return m_dateTime; +} + +QString NeoChatDateTime::hourMinuteString() const +{ + return m_dateTime.toLocalTime().toString(u"hh:mm"_s); +} + +QString NeoChatDateTime::shortDateTime() const +{ + return QLocale().toString(m_dateTime.toLocalTime(), QLocale::ShortFormat); +} + +QString NeoChatDateTime::relativeDate() const +{ + KFormat formatter; + return formatter.formatRelativeDate(m_dateTime.toLocalTime().date(), QLocale::ShortFormat); +} + +QString NeoChatDateTime::relativeDateTime() const +{ + KFormat formatter; + const auto relativePart = formatter.formatRelativeDate(m_dateTime.toLocalTime().date(), QLocale::ShortFormat); + return u"%1, %2"_s.arg(relativePart, hourMinuteString()); +} + +bool NeoChatDateTime::operator==(const QDateTime &right) const +{ + return m_dateTime == right; +} + +#include "moc_neochatdatetime.cpp" diff --git a/src/libneochat/neochatdatetime.h b/src/libneochat/neochatdatetime.h new file mode 100644 index 000000000..94b5b11cf --- /dev/null +++ b/src/libneochat/neochatdatetime.h @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: 2026 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +#pragma once + +#include +#include + +/** + * @class NeoChatDateTime + * + * This class is a helper for converting a QDateTime into the various format required in NeoChat. + * + * The intention is that this can be passed to QML and then the various Q_Properties + * can be called to get the date/time in the desired format reading for viewing in + * the UI. + */ +class NeoChatDateTime +{ + Q_GADGET + QML_ELEMENT + + /** + * @brief The base QDateTime used to generate the other values. + */ + Q_PROPERTY(QDateTime dateTime READ dateTime CONSTANT) + + /** + * @brief The time formatted as "hh:mm". + */ + Q_PROPERTY(QString hourMinuteString READ hourMinuteString CONSTANT) + + /** + * @brief The date and time formatted as per QLocale::ShortFormat for your locale. + */ + Q_PROPERTY(QString shortDateTime READ shortDateTime CONSTANT) + + /** + * @brief The date formatted as relative to now. + * + * If the date falls within one week before or after the current date + * then a relative date string will be returned, such as: + * - Yesterday + * - Today + * - Tomorrow + * - Last Tuesday + * - Next Wednesday + * + * If the date falls outside this period then the format QLocale::ShortFormat + * for your locale is used. + */ + Q_PROPERTY(QString relativeDate READ relativeDate CONSTANT) + + /** + * @brief The time and date formatted as relative to now. + * + * The format is "RelativeDate, hh::mm" + * + * If the date falls within one week before or after the current date + * then a relative date string will be returned, such as: + * - Yesterday + * - Today + * - Tomorrow + * - Last Tuesday + * - Next Wednesday + * + * If the date falls outside this period then the format QLocale::ShortFormat + * for your locale is used. + */ + Q_PROPERTY(QString relativeDateTime READ relativeDateTime CONSTANT) + +public: + NeoChatDateTime(QDateTime dateTime = {}); + + QDateTime dateTime() const; + + QString hourMinuteString() const; + QString shortDateTime() const; + QString relativeDate() const; + QString relativeDateTime() const; + + bool operator==(const QDateTime &right) const; + +private: + QDateTime m_dateTime; +}; diff --git a/src/messagecontent/AuthorComponent.qml b/src/messagecontent/AuthorComponent.qml index 381d8541c..ef1cd281b 100644 --- a/src/messagecontent/AuthorComponent.qml +++ b/src/messagecontent/AuthorComponent.qml @@ -27,14 +27,9 @@ RowLayout { required property var author /** - * @brief The timestamp of the message. + * @brief The timestamp of the event as a NeoChatDateTime. */ - required property var time - - /** - * @brief The timestamp of the message as a string. - */ - required property string timeString + required property NeoChatDateTime dateTime Layout.fillWidth: true Layout.maximumWidth: Message.maxContentWidth @@ -83,11 +78,11 @@ RowLayout { } QQC2.Label { id: timeLabel - text: root.timeString + text: root.dateTime.hourMinuteString horizontalAlignment: Text.AlignRight color: Kirigami.Theme.disabledTextColor QQC2.ToolTip.visible: timeHoverHandler.hovered - QQC2.ToolTip.text: root.time.toLocaleString(Qt.locale(), Locale.ShortFormat) + QQC2.ToolTip.text: root.dateTime.shortDateTime QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay HoverHandler { diff --git a/src/messagecontent/models/eventmessagecontentmodel.cpp b/src/messagecontent/models/eventmessagecontentmodel.cpp index 19dc47196..d01f34a19 100644 --- a/src/messagecontent/models/eventmessagecontentmodel.cpp +++ b/src/messagecontent/models/eventmessagecontentmodel.cpp @@ -16,6 +16,7 @@ #include "contentprovider.h" #include "eventhandler.h" #include "models/reactionmodel.h" +#include "neochatdatetime.h" #include "neochatroom.h" #include "texthandler.h" @@ -123,22 +124,13 @@ void EventMessageContentModel::initializeModel() resetModel(); } -QDateTime EventMessageContentModel::time() const +NeoChatDateTime EventMessageContentModel::dateTime() const { const auto event = m_room->getEvent(m_eventId); if (event.first == nullptr) { - return MessageContentModel::time(); + return MessageContentModel::dateTime(); }; - return EventHandler::time(m_room, event.first, m_currentState == Pending); -} - -QString EventMessageContentModel::timeString() const -{ - const auto event = m_room->getEvent(m_eventId); - if (event.first == nullptr) { - return MessageContentModel::timeString(); - }; - return EventHandler::timeString(m_room, event.first, u"hh:mm"_s, m_currentState == Pending); + return EventHandler::dateTime(m_room, event.first, m_currentState == Pending); } QString EventMessageContentModel::authorId() const @@ -254,12 +246,7 @@ void EventMessageContentModel::resetModel() return; } - m_components += MessageComponent{MessageComponentType::Author, - QString(), - { - {u"time"_s, EventHandler::time(m_room, event.first, m_currentState == Pending)}, - {u"timeString"_s, EventHandler::timeString(m_room, event.first, u"hh:mm"_s, m_currentState == Pending)}, - }}; + m_components += MessageComponent{MessageComponentType::Author, {}, {}}; m_components += messageContentComponents(); endResetModel(); diff --git a/src/messagecontent/models/eventmessagecontentmodel.h b/src/messagecontent/models/eventmessagecontentmodel.h index 666e41a6c..3c677bc5a 100644 --- a/src/messagecontent/models/eventmessagecontentmodel.h +++ b/src/messagecontent/models/eventmessagecontentmodel.h @@ -52,8 +52,7 @@ Q_SIGNALS: private: void initializeModel(); - QDateTime time() const override; - QString timeString() const override; + NeoChatDateTime dateTime() const override; QString authorId() const override; QString threadRootId() const override; diff --git a/src/messagecontent/models/messagecontentmodel.cpp b/src/messagecontent/models/messagecontentmodel.cpp index fa79c5e43..016208307 100644 --- a/src/messagecontent/models/messagecontentmodel.cpp +++ b/src/messagecontent/models/messagecontentmodel.cpp @@ -10,6 +10,7 @@ #include "chatbarcache.h" #include "contentprovider.h" #include "neochatconnection.h" +#include "neochatdatetime.h" #include "texthandler.h" using namespace Quotient; @@ -79,16 +80,11 @@ QString MessageContentModel::eventId() const return m_eventId; } -QDateTime MessageContentModel::time() const +NeoChatDateTime MessageContentModel::dateTime() const { return QDateTime::currentDateTime(); } -QString MessageContentModel::timeString() const -{ - return time().toLocalTime().toString(u"hh:mm"_s); -} - QString MessageContentModel::authorId() const { return m_room->localMember().id(); @@ -136,11 +132,8 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const if (role == EventIdRole) { return eventId(); } - if (role == TimeRole) { - return time(); - } - if (role == TimeStringRole) { - return timeString(); + if (role == DateTimeRole) { + return QVariant::fromValue(dateTime()); } if (role == AuthorRole) { return QVariant::fromValue(author()); @@ -199,8 +192,7 @@ QHash MessageContentModel::roleNamesStatic() roles[MessageContentModel::ComponentTypeRole] = "componentType"; roles[MessageContentModel::ComponentAttributesRole] = "componentAttributes"; roles[MessageContentModel::EventIdRole] = "eventId"; - roles[MessageContentModel::TimeRole] = "time"; - roles[MessageContentModel::TimeStringRole] = "timeString"; + roles[MessageContentModel::DateTimeRole] = "dateTime"; roles[MessageContentModel::AuthorRole] = "author"; roles[MessageContentModel::FileTransferInfoRole] = "fileTransferInfo"; roles[MessageContentModel::ItineraryModelRole] = "itineraryModel"; diff --git a/src/messagecontent/models/messagecontentmodel.h b/src/messagecontent/models/messagecontentmodel.h index b14dcc166..b6e07b3f3 100644 --- a/src/messagecontent/models/messagecontentmodel.h +++ b/src/messagecontent/models/messagecontentmodel.h @@ -21,6 +21,8 @@ #include "neochatroom.h" #include "neochatroommember.h" +class NeoChatDateTime; + /** * @class MessageContentModel * @@ -47,8 +49,7 @@ public: ComponentTypeRole = Qt::UserRole, /**< The type of component to visualise the message. */ ComponentAttributesRole, /**< The attributes of the component. */ EventIdRole, /**< The matrix event ID of the event. */ - TimeRole, /**< The timestamp for when the event was sent (as a QDateTime). */ - TimeStringRole, /**< The timestamp for when the event was sent as a string (in QLocale::ShortFormat). */ + DateTimeRole, /**< The timestamp for when the event was sent (as a NeoChatDateTime). */ AuthorRole, /**< The author of the event. */ FileTransferInfoRole, /**< FileTransferInfo for any downloading files. */ ItineraryModelRole, /**< The itinerary model for a file. */ @@ -125,18 +126,11 @@ protected: QString m_eventId; /** - * @brief QDateTime for the message. + * @brief NeoChatDateTime for the message. * * The default implementation returns the current time. */ - virtual QDateTime time() const; - - /** - * @brief Time for the message as a string in the from "hh:mm". - * - * The default implementation returns the current time. - */ - virtual QString timeString() const; + virtual NeoChatDateTime dateTime() const; /** * @brief The author of the message. diff --git a/src/timeline/MessageDelegate.qml b/src/timeline/MessageDelegate.qml index 67a34b83d..8637730f9 100644 --- a/src/timeline/MessageDelegate.qml +++ b/src/timeline/MessageDelegate.qml @@ -50,9 +50,9 @@ MessageDelegateBase { required property MessageContentModel contentModel /** - * @brief The date of the event as a string. + * @brief The timestamp of the event as a NeoChatDateTime. */ - required property string section + required property NeoChatDateTime dateTime /** * @brief A model with the first 5 other user read markers for this message. @@ -203,7 +203,7 @@ MessageDelegateBase { sectionComponent: Kirigami.ListSectionHeader { horizontalPadding: 0 - text: root.section + text: root.dateTime.relativeDate } readMarkerComponent: AvatarFlow { diff --git a/src/timeline/StateDelegate.qml b/src/timeline/StateDelegate.qml index 873f9c4f9..0a33c9f30 100644 --- a/src/timeline/StateDelegate.qml +++ b/src/timeline/StateDelegate.qml @@ -49,9 +49,9 @@ TimelineDelegate { required property bool showSection /** - * @brief The date of the event as a string. + * @brief The timestamp of the event as a NeoChatDateTime. */ - required property string section + required property NeoChatDateTime dateTime /** * @brief A model with the first 5 other user read markers for this message. @@ -80,7 +80,7 @@ TimelineDelegate { Layout.fillWidth: true visible: root.showSection horizontalPadding: 0 - text: root.section + text: root.dateTime.relativeDate } RowLayout { Layout.fillWidth: true diff --git a/src/timeline/models/mediamessagefiltermodel.cpp b/src/timeline/models/mediamessagefiltermodel.cpp index c1652d6d5..3a254b710 100644 --- a/src/timeline/models/mediamessagefiltermodel.cpp +++ b/src/timeline/models/mediamessagefiltermodel.cpp @@ -7,6 +7,7 @@ #include #include "messagefiltermodel.h" +#include "neochatdatetime.h" #include "timelinemessagemodel.h" using namespace Qt::StringLiterals; @@ -34,8 +35,9 @@ QVariant MediaMessageFilterModel::data(const QModelIndex &index, int role) const // We need to catch this one and return true if the next media object was // on a different day. if (role == TimelineMessageModel::ShowSectionRole) { - const auto day = mapToSource(index).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date(); - const auto previousEventDay = mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date(); + const auto day = mapToSource(index).data(TimelineMessageModel::DateTimeRole).value().dateTime().toLocalTime().date(); + const auto previousEventDay = + mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::DateTimeRole).value().dateTime().toLocalTime().date(); return day != previousEventDay; } diff --git a/src/timeline/models/messagefiltermodel.cpp b/src/timeline/models/messagefiltermodel.cpp index 6ae5a5b6b..82427cfe1 100644 --- a/src/timeline/models/messagefiltermodel.cpp +++ b/src/timeline/models/messagefiltermodel.cpp @@ -9,6 +9,7 @@ #include "enums/delegatetype.h" #include "messagemodel.h" #include "models/timelinemodel.h" +#include "neochatdatetime.h" using namespace Quotient; @@ -179,9 +180,13 @@ bool MessageFilterModel::showAuthor(QModelIndex index) const if (data(i, TimelineMessageModel::SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) { return data(i, TimelineMessageModel::AuthorRole) != data(index, TimelineMessageModel::AuthorRole) || data(i, TimelineMessageModel::DelegateTypeRole) == DelegateType::State - || data(i, TimelineMessageModel::TimeRole).toDateTime().msecsTo(data(index, TimelineMessageModel::TimeRole).toDateTime()) > 600000 - || data(i, TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date().day() - != data(index, TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date().day(); + || data(i, TimelineMessageModel::DateTimeRole) + .value() + .dateTime() + .msecsTo(data(index, TimelineMessageModel::DateTimeRole).value().dateTime()) + > 600000 + || data(i, TimelineMessageModel::DateTimeRole).value().dateTime().toLocalTime().date().day() + != data(index, TimelineMessageModel::DateTimeRole).value().dateTime().toLocalTime().date().day(); } } diff --git a/src/timeline/models/messagemodel.cpp b/src/timeline/models/messagemodel.cpp index 40f94a1e3..2fddc2575 100644 --- a/src/timeline/models/messagemodel.cpp +++ b/src/timeline/models/messagemodel.cpp @@ -17,8 +17,9 @@ #include "enums/messagecomponenttype.h" #include "eventhandler.h" #include "events/pollevent.h" -#include "models/reactionmodel.h" #include "models/eventmessagecontentmodel.h" +#include "models/reactionmodel.h" +#include "neochatdatetime.h" #include "neochatroommember.h" using namespace Quotient; @@ -110,11 +111,8 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const switch (role) { case DelegateTypeRole: return DelegateType::ReadMarker; - case TimeRole: { - const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime(); - static const KFormat format; - return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat); - } + case DateTimeRole: + return data(index(m_lastReadEventIndex.row() + 1, 0), DateTimeRole); case SpecialMarksRole: // Check if all the earlier events in the timeline are hidden. If so hide this. for (auto r = row - 1; r >= 0; --r) { @@ -230,12 +228,8 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const return {}; } - if (role == TimeRole) { - return EventHandler::time(eventRoom, &event.value().get(), isPending); - } - - if (role == SectionRole) { - return EventHandler::timeString(eventRoom, &event.value().get(), true, QLocale::ShortFormat, isPending); + if (role == DateTimeRole) { + return QVariant::fromValue(EventHandler::dateTime(eventRoom, &event.value().get(), isPending)); } if (role == IsThreadedRole) { @@ -267,8 +261,8 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const // While the row is removed the subsequent row indexes are not changed so we need to skip over the removed index. // See - https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows if (data(i, SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) { - const auto day = data(idx, TimeRole).toDateTime().toLocalTime().date().dayOfYear(); - const auto previousEventDay = data(i, TimeRole).toDateTime().toLocalTime().date().dayOfYear(); + const auto day = data(idx, DateTimeRole).value().dateTime().toLocalTime().date().dayOfYear(); + const auto previousEventDay = data(i, DateTimeRole).value().dateTime().toLocalTime().date().dayOfYear(); return day != previousEventDay; } } @@ -342,8 +336,7 @@ QHash MessageModel::roleNames() const QHash roles = QAbstractItemModel::roleNames(); roles[DelegateTypeRole] = "delegateType"; roles[EventIdRole] = "eventId"; - roles[TimeRole] = "time"; - roles[SectionRole] = "section"; + roles[DateTimeRole] = "dateTime"; roles[AuthorRole] = "author"; roles[HighlightRole] = "isHighlighted"; roles[SpecialMarksRole] = "marks"; diff --git a/src/timeline/models/messagemodel.h b/src/timeline/models/messagemodel.h index 6fb02c3c4..76f49a27c 100644 --- a/src/timeline/models/messagemodel.h +++ b/src/timeline/models/messagemodel.h @@ -60,8 +60,7 @@ public: enum EventRoles { DelegateTypeRole = Qt::UserRole + 1, /**< The delegate type of the message. */ EventIdRole, /**< The matrix event ID of the event. */ - TimeRole, /**< The timestamp for when the event was sent (as a QDateTime). */ - SectionRole, /**< The date of the event as a string. */ + DateTimeRole, /**< The timestamp for when the event was sent (as a NeoChatDateTime). */ AuthorRole, /**< The author of the event. */ HighlightRole, /**< Whether the event should be highlighted. */ SpecialMarksRole, /**< Whether the event is hidden or not. */