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:
James Graham
2026-01-25 13:01:31 +00:00
parent c797ecea3d
commit 92c58b0ea0
17 changed files with 191 additions and 172 deletions

View File

@@ -17,6 +17,7 @@ target_sources(LibNeoChat PRIVATE
filetransferpseudojob.cpp
filetype.cpp
linkpreviewer.cpp
neochatdatetime.cpp
roomlastmessageprovider.cpp
spacehierarchycache.cpp
texthandler.cpp

View File

@@ -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) {

View File

@@ -7,6 +7,8 @@
#include <QString>
#include <Quotient/events/eventcontent.h>
#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.

View 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"

View 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;
};