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.
This commit is contained in:
@@ -40,7 +40,6 @@ private Q_SLOTS:
|
|||||||
void nullSingleLineDisplayName();
|
void nullSingleLineDisplayName();
|
||||||
void time();
|
void time();
|
||||||
void nullTime();
|
void nullTime();
|
||||||
void timeString();
|
|
||||||
void highlighted();
|
void highlighted();
|
||||||
void nullHighlighted();
|
void nullHighlighted();
|
||||||
void hidden();
|
void hidden();
|
||||||
@@ -100,12 +99,12 @@ void EventHandlerTest::time()
|
|||||||
{
|
{
|
||||||
const auto event = room->messageEvents().at(0).get();
|
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());
|
const auto txID = room->postJson("m.room.message"_L1, event->fullJson());
|
||||||
QCOMPARE(room->pendingEvents().size(), 1);
|
QCOMPARE(room->pendingEvents().size(), 1);
|
||||||
const auto pendingIt = room->findPendingEvent(txID);
|
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);
|
room->discardMessage(txID);
|
||||||
QCOMPARE(room->pendingEvents().size(), 0);
|
QCOMPARE(room->pendingEvents().size(), 0);
|
||||||
@@ -114,40 +113,10 @@ void EventHandlerTest::time()
|
|||||||
void EventHandlerTest::nullTime()
|
void EventHandlerTest::nullTime()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtWarningMsg, "time called with room set to nullptr.");
|
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.");
|
QTest::ignoreMessage(QtWarningMsg, "time called with event set to nullptr.");
|
||||||
QCOMPARE(EventHandler::time(room, nullptr), QDateTime());
|
QCOMPARE(EventHandler::dateTime(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandlerTest::highlighted()
|
void EventHandlerTest::highlighted()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ target_sources(LibNeoChat PRIVATE
|
|||||||
filetransferpseudojob.cpp
|
filetransferpseudojob.cpp
|
||||||
filetype.cpp
|
filetype.cpp
|
||||||
linkpreviewer.cpp
|
linkpreviewer.cpp
|
||||||
|
neochatdatetime.cpp
|
||||||
roomlastmessageprovider.cpp
|
roomlastmessageprovider.cpp
|
||||||
spacehierarchycache.cpp
|
spacehierarchycache.cpp
|
||||||
texthandler.cpp
|
texthandler.cpp
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ QString EventHandler::singleLineAuthorDisplayname(const NeoChatRoom *room, const
|
|||||||
return displayName;
|
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) {
|
if (room == nullptr) {
|
||||||
qCWarning(EventHandling) << "time called with room set to 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();
|
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)
|
bool EventHandler::isHighlighted(const NeoChatRoom *room, const Quotient::RoomEvent *event)
|
||||||
{
|
{
|
||||||
if (room == nullptr) {
|
if (room == nullptr) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <Quotient/events/eventcontent.h>
|
#include <Quotient/events/eventcontent.h>
|
||||||
|
|
||||||
|
#include "neochatdatetime.h"
|
||||||
|
|
||||||
namespace Quotient
|
namespace Quotient
|
||||||
{
|
{
|
||||||
namespace EventContent
|
namespace EventContent
|
||||||
@@ -64,41 +66,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief Return a QDateTime object for the event timestamp.
|
* @brief Return a QDateTime object for the event timestamp.
|
||||||
*/
|
*/
|
||||||
static QDateTime time(const NeoChatRoom *room, const Quotient::RoomEvent *event, bool isPending = false);
|
static NeoChatDateTime dateTime(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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Whether the event should be highlighted in the timeline.
|
* @brief Whether the event should be highlighted in the timeline.
|
||||||
|
|||||||
48
src/libneochat/neochatdatetime.cpp
Normal file
48
src/libneochat/neochatdatetime.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#include "neochatdatetime.h"
|
||||||
|
|
||||||
|
#include <KFormat>
|
||||||
|
|
||||||
|
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"
|
||||||
86
src/libneochat/neochatdatetime.h
Normal file
86
src/libneochat/neochatdatetime.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 James Graham <james.h.graham@protonmail.com>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
};
|
||||||
@@ -27,14 +27,9 @@ RowLayout {
|
|||||||
required property var author
|
required property var author
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The timestamp of the message.
|
* @brief The timestamp of the event as a NeoChatDateTime.
|
||||||
*/
|
*/
|
||||||
required property var time
|
required property NeoChatDateTime dateTime
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The timestamp of the message as a string.
|
|
||||||
*/
|
|
||||||
required property string timeString
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.maximumWidth: Message.maxContentWidth
|
Layout.maximumWidth: Message.maxContentWidth
|
||||||
@@ -83,11 +78,11 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
QQC2.Label {
|
QQC2.Label {
|
||||||
id: timeLabel
|
id: timeLabel
|
||||||
text: root.timeString
|
text: root.dateTime.hourMinuteString
|
||||||
horizontalAlignment: Text.AlignRight
|
horizontalAlignment: Text.AlignRight
|
||||||
color: Kirigami.Theme.disabledTextColor
|
color: Kirigami.Theme.disabledTextColor
|
||||||
QQC2.ToolTip.visible: timeHoverHandler.hovered
|
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
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "contentprovider.h"
|
#include "contentprovider.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "models/reactionmodel.h"
|
#include "models/reactionmodel.h"
|
||||||
|
#include "neochatdatetime.h"
|
||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "texthandler.h"
|
#include "texthandler.h"
|
||||||
|
|
||||||
@@ -123,22 +124,13 @@ void EventMessageContentModel::initializeModel()
|
|||||||
resetModel();
|
resetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime EventMessageContentModel::time() const
|
NeoChatDateTime EventMessageContentModel::dateTime() const
|
||||||
{
|
{
|
||||||
const auto event = m_room->getEvent(m_eventId);
|
const auto event = m_room->getEvent(m_eventId);
|
||||||
if (event.first == nullptr) {
|
if (event.first == nullptr) {
|
||||||
return MessageContentModel::time();
|
return MessageContentModel::dateTime();
|
||||||
};
|
};
|
||||||
return EventHandler::time(m_room, event.first, m_currentState == Pending);
|
return EventHandler::dateTime(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString EventMessageContentModel::authorId() const
|
QString EventMessageContentModel::authorId() const
|
||||||
@@ -254,12 +246,7 @@ void EventMessageContentModel::resetModel()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_components += MessageComponent{MessageComponentType::Author,
|
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 += messageContentComponents();
|
m_components += messageContentComponents();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ Q_SIGNALS:
|
|||||||
private:
|
private:
|
||||||
void initializeModel();
|
void initializeModel();
|
||||||
|
|
||||||
QDateTime time() const override;
|
NeoChatDateTime dateTime() const override;
|
||||||
QString timeString() const override;
|
|
||||||
QString authorId() const override;
|
QString authorId() const override;
|
||||||
QString threadRootId() const override;
|
QString threadRootId() const override;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "chatbarcache.h"
|
#include "chatbarcache.h"
|
||||||
#include "contentprovider.h"
|
#include "contentprovider.h"
|
||||||
#include "neochatconnection.h"
|
#include "neochatconnection.h"
|
||||||
|
#include "neochatdatetime.h"
|
||||||
#include "texthandler.h"
|
#include "texthandler.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -79,16 +80,11 @@ QString MessageContentModel::eventId() const
|
|||||||
return m_eventId;
|
return m_eventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime MessageContentModel::time() const
|
NeoChatDateTime MessageContentModel::dateTime() const
|
||||||
{
|
{
|
||||||
return QDateTime::currentDateTime();
|
return QDateTime::currentDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MessageContentModel::timeString() const
|
|
||||||
{
|
|
||||||
return time().toLocalTime().toString(u"hh:mm"_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MessageContentModel::authorId() const
|
QString MessageContentModel::authorId() const
|
||||||
{
|
{
|
||||||
return m_room->localMember().id();
|
return m_room->localMember().id();
|
||||||
@@ -136,11 +132,8 @@ QVariant MessageContentModel::data(const QModelIndex &index, int role) const
|
|||||||
if (role == EventIdRole) {
|
if (role == EventIdRole) {
|
||||||
return eventId();
|
return eventId();
|
||||||
}
|
}
|
||||||
if (role == TimeRole) {
|
if (role == DateTimeRole) {
|
||||||
return time();
|
return QVariant::fromValue(dateTime());
|
||||||
}
|
|
||||||
if (role == TimeStringRole) {
|
|
||||||
return timeString();
|
|
||||||
}
|
}
|
||||||
if (role == AuthorRole) {
|
if (role == AuthorRole) {
|
||||||
return QVariant::fromValue<NeochatRoomMember *>(author());
|
return QVariant::fromValue<NeochatRoomMember *>(author());
|
||||||
@@ -199,8 +192,7 @@ QHash<int, QByteArray> MessageContentModel::roleNamesStatic()
|
|||||||
roles[MessageContentModel::ComponentTypeRole] = "componentType";
|
roles[MessageContentModel::ComponentTypeRole] = "componentType";
|
||||||
roles[MessageContentModel::ComponentAttributesRole] = "componentAttributes";
|
roles[MessageContentModel::ComponentAttributesRole] = "componentAttributes";
|
||||||
roles[MessageContentModel::EventIdRole] = "eventId";
|
roles[MessageContentModel::EventIdRole] = "eventId";
|
||||||
roles[MessageContentModel::TimeRole] = "time";
|
roles[MessageContentModel::DateTimeRole] = "dateTime";
|
||||||
roles[MessageContentModel::TimeStringRole] = "timeString";
|
|
||||||
roles[MessageContentModel::AuthorRole] = "author";
|
roles[MessageContentModel::AuthorRole] = "author";
|
||||||
roles[MessageContentModel::FileTransferInfoRole] = "fileTransferInfo";
|
roles[MessageContentModel::FileTransferInfoRole] = "fileTransferInfo";
|
||||||
roles[MessageContentModel::ItineraryModelRole] = "itineraryModel";
|
roles[MessageContentModel::ItineraryModelRole] = "itineraryModel";
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
#include "neochatroom.h"
|
#include "neochatroom.h"
|
||||||
#include "neochatroommember.h"
|
#include "neochatroommember.h"
|
||||||
|
|
||||||
|
class NeoChatDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class MessageContentModel
|
* @class MessageContentModel
|
||||||
*
|
*
|
||||||
@@ -47,8 +49,7 @@ public:
|
|||||||
ComponentTypeRole = Qt::UserRole, /**< The type of component to visualise the message. */
|
ComponentTypeRole = Qt::UserRole, /**< The type of component to visualise the message. */
|
||||||
ComponentAttributesRole, /**< The attributes of the component. */
|
ComponentAttributesRole, /**< The attributes of the component. */
|
||||||
EventIdRole, /**< The matrix event ID of the event. */
|
EventIdRole, /**< The matrix event ID of the event. */
|
||||||
TimeRole, /**< The timestamp for when the event was sent (as a QDateTime). */
|
DateTimeRole, /**< The timestamp for when the event was sent (as a NeoChatDateTime). */
|
||||||
TimeStringRole, /**< The timestamp for when the event was sent as a string (in QLocale::ShortFormat). */
|
|
||||||
AuthorRole, /**< The author of the event. */
|
AuthorRole, /**< The author of the event. */
|
||||||
FileTransferInfoRole, /**< FileTransferInfo for any downloading files. */
|
FileTransferInfoRole, /**< FileTransferInfo for any downloading files. */
|
||||||
ItineraryModelRole, /**< The itinerary model for a file. */
|
ItineraryModelRole, /**< The itinerary model for a file. */
|
||||||
@@ -125,18 +126,11 @@ protected:
|
|||||||
QString m_eventId;
|
QString m_eventId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief QDateTime for the message.
|
* @brief NeoChatDateTime for the message.
|
||||||
*
|
*
|
||||||
* The default implementation returns the current time.
|
* The default implementation returns the current time.
|
||||||
*/
|
*/
|
||||||
virtual QDateTime time() const;
|
virtual NeoChatDateTime dateTime() 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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The author of the message.
|
* @brief The author of the message.
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ MessageDelegateBase {
|
|||||||
required property MessageContentModel contentModel
|
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.
|
* @brief A model with the first 5 other user read markers for this message.
|
||||||
@@ -203,7 +203,7 @@ MessageDelegateBase {
|
|||||||
|
|
||||||
sectionComponent: Kirigami.ListSectionHeader {
|
sectionComponent: Kirigami.ListSectionHeader {
|
||||||
horizontalPadding: 0
|
horizontalPadding: 0
|
||||||
text: root.section
|
text: root.dateTime.relativeDate
|
||||||
}
|
}
|
||||||
|
|
||||||
readMarkerComponent: AvatarFlow {
|
readMarkerComponent: AvatarFlow {
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ TimelineDelegate {
|
|||||||
required property bool showSection
|
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.
|
* @brief A model with the first 5 other user read markers for this message.
|
||||||
@@ -80,7 +80,7 @@ TimelineDelegate {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
visible: root.showSection
|
visible: root.showSection
|
||||||
horizontalPadding: 0
|
horizontalPadding: 0
|
||||||
text: root.section
|
text: root.dateTime.relativeDate
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <Quotient/room.h>
|
#include <Quotient/room.h>
|
||||||
|
|
||||||
#include "messagefiltermodel.h"
|
#include "messagefiltermodel.h"
|
||||||
|
#include "neochatdatetime.h"
|
||||||
#include "timelinemessagemodel.h"
|
#include "timelinemessagemodel.h"
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
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
|
// We need to catch this one and return true if the next media object was
|
||||||
// on a different day.
|
// on a different day.
|
||||||
if (role == TimelineMessageModel::ShowSectionRole) {
|
if (role == TimelineMessageModel::ShowSectionRole) {
|
||||||
const auto day = mapToSource(index).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date();
|
const auto day = mapToSource(index).data(TimelineMessageModel::DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date();
|
||||||
const auto previousEventDay = mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date();
|
const auto previousEventDay =
|
||||||
|
mapToSource(this->index(index.row() + 1, 0)).data(TimelineMessageModel::DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date();
|
||||||
return day != previousEventDay;
|
return day != previousEventDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "enums/delegatetype.h"
|
#include "enums/delegatetype.h"
|
||||||
#include "messagemodel.h"
|
#include "messagemodel.h"
|
||||||
#include "models/timelinemodel.h"
|
#include "models/timelinemodel.h"
|
||||||
|
#include "neochatdatetime.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
@@ -179,9 +180,13 @@ bool MessageFilterModel::showAuthor(QModelIndex index) const
|
|||||||
if (data(i, TimelineMessageModel::SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) {
|
if (data(i, TimelineMessageModel::SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) {
|
||||||
return data(i, TimelineMessageModel::AuthorRole) != data(index, TimelineMessageModel::AuthorRole)
|
return data(i, TimelineMessageModel::AuthorRole) != data(index, TimelineMessageModel::AuthorRole)
|
||||||
|| data(i, TimelineMessageModel::DelegateTypeRole) == DelegateType::State
|
|| data(i, TimelineMessageModel::DelegateTypeRole) == DelegateType::State
|
||||||
|| data(i, TimelineMessageModel::TimeRole).toDateTime().msecsTo(data(index, TimelineMessageModel::TimeRole).toDateTime()) > 600000
|
|| data(i, TimelineMessageModel::DateTimeRole)
|
||||||
|| data(i, TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date().day()
|
.value<NeoChatDateTime>()
|
||||||
!= data(index, TimelineMessageModel::TimeRole).toDateTime().toLocalTime().date().day();
|
.dateTime()
|
||||||
|
.msecsTo(data(index, TimelineMessageModel::DateTimeRole).value<NeoChatDateTime>().dateTime())
|
||||||
|
> 600000
|
||||||
|
|| data(i, TimelineMessageModel::DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date().day()
|
||||||
|
!= data(index, TimelineMessageModel::DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date().day();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
#include "enums/messagecomponenttype.h"
|
#include "enums/messagecomponenttype.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "events/pollevent.h"
|
#include "events/pollevent.h"
|
||||||
#include "models/reactionmodel.h"
|
|
||||||
#include "models/eventmessagecontentmodel.h"
|
#include "models/eventmessagecontentmodel.h"
|
||||||
|
#include "models/reactionmodel.h"
|
||||||
|
#include "neochatdatetime.h"
|
||||||
#include "neochatroommember.h"
|
#include "neochatroommember.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
@@ -110,11 +111,8 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
|||||||
switch (role) {
|
switch (role) {
|
||||||
case DelegateTypeRole:
|
case DelegateTypeRole:
|
||||||
return DelegateType::ReadMarker;
|
return DelegateType::ReadMarker;
|
||||||
case TimeRole: {
|
case DateTimeRole:
|
||||||
const QDateTime eventDate = data(index(m_lastReadEventIndex.row() + 1, 0), TimeRole).toDateTime().toLocalTime();
|
return data(index(m_lastReadEventIndex.row() + 1, 0), DateTimeRole);
|
||||||
static const KFormat format;
|
|
||||||
return format.formatRelativeDateTime(eventDate, QLocale::ShortFormat);
|
|
||||||
}
|
|
||||||
case SpecialMarksRole:
|
case SpecialMarksRole:
|
||||||
// Check if all the earlier events in the timeline are hidden. If so hide this.
|
// Check if all the earlier events in the timeline are hidden. If so hide this.
|
||||||
for (auto r = row - 1; r >= 0; --r) {
|
for (auto r = row - 1; r >= 0; --r) {
|
||||||
@@ -230,12 +228,8 @@ QVariant MessageModel::data(const QModelIndex &idx, int role) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == TimeRole) {
|
if (role == DateTimeRole) {
|
||||||
return EventHandler::time(eventRoom, &event.value().get(), isPending);
|
return QVariant::fromValue(EventHandler::dateTime(eventRoom, &event.value().get(), isPending));
|
||||||
}
|
|
||||||
|
|
||||||
if (role == SectionRole) {
|
|
||||||
return EventHandler::timeString(eventRoom, &event.value().get(), true, QLocale::ShortFormat, isPending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role == IsThreadedRole) {
|
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.
|
// 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
|
// See - https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows
|
||||||
if (data(i, SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) {
|
if (data(i, SpecialMarksRole) != EventStatus::Hidden && !itemData(i).empty()) {
|
||||||
const auto day = data(idx, TimeRole).toDateTime().toLocalTime().date().dayOfYear();
|
const auto day = data(idx, DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date().dayOfYear();
|
||||||
const auto previousEventDay = data(i, TimeRole).toDateTime().toLocalTime().date().dayOfYear();
|
const auto previousEventDay = data(i, DateTimeRole).value<NeoChatDateTime>().dateTime().toLocalTime().date().dayOfYear();
|
||||||
return day != previousEventDay;
|
return day != previousEventDay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,8 +336,7 @@ QHash<int, QByteArray> MessageModel::roleNames() const
|
|||||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||||
roles[DelegateTypeRole] = "delegateType";
|
roles[DelegateTypeRole] = "delegateType";
|
||||||
roles[EventIdRole] = "eventId";
|
roles[EventIdRole] = "eventId";
|
||||||
roles[TimeRole] = "time";
|
roles[DateTimeRole] = "dateTime";
|
||||||
roles[SectionRole] = "section";
|
|
||||||
roles[AuthorRole] = "author";
|
roles[AuthorRole] = "author";
|
||||||
roles[HighlightRole] = "isHighlighted";
|
roles[HighlightRole] = "isHighlighted";
|
||||||
roles[SpecialMarksRole] = "marks";
|
roles[SpecialMarksRole] = "marks";
|
||||||
|
|||||||
@@ -60,8 +60,7 @@ public:
|
|||||||
enum EventRoles {
|
enum EventRoles {
|
||||||
DelegateTypeRole = Qt::UserRole + 1, /**< The delegate type of the message. */
|
DelegateTypeRole = Qt::UserRole + 1, /**< The delegate type of the message. */
|
||||||
EventIdRole, /**< The matrix event ID of the event. */
|
EventIdRole, /**< The matrix event ID of the event. */
|
||||||
TimeRole, /**< The timestamp for when the event was sent (as a QDateTime). */
|
DateTimeRole, /**< The timestamp for when the event was sent (as a NeoChatDateTime). */
|
||||||
SectionRole, /**< The date of the event as a string. */
|
|
||||||
AuthorRole, /**< The author of the event. */
|
AuthorRole, /**< The author of the event. */
|
||||||
HighlightRole, /**< Whether the event should be highlighted. */
|
HighlightRole, /**< Whether the event should be highlighted. */
|
||||||
SpecialMarksRole, /**< Whether the event is hidden or not. */
|
SpecialMarksRole, /**< Whether the event is hidden or not. */
|
||||||
|
|||||||
Reference in New Issue
Block a user