From 340866612b45d6569638320fca5ca16eb499a94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Tinkl?= Date: Tue, 21 Feb 2023 18:15:17 +0100 Subject: [PATCH] feat: relative or absolute timestamping depending on time/date proximity - implement LocaleUtils.formatRelativeTimestamp() that does all the heavy lifting - use it in StatusTimeStampLabel -> propagates to all message timestamps (chat, activity center, settings, etc) Closes #9397 --- .../statusMessage/StatusTimeStampLabel.qml | 2 +- ui/StatusQ/src/StatusQ/Core/LocaleUtils.qml | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/ui/StatusQ/src/StatusQ/Components/private/statusMessage/StatusTimeStampLabel.qml b/ui/StatusQ/src/StatusQ/Components/private/statusMessage/StatusTimeStampLabel.qml index ce2783aff2..9b7ad9cc4b 100644 --- a/ui/StatusQ/src/StatusQ/Components/private/statusMessage/StatusTimeStampLabel.qml +++ b/ui/StatusQ/src/StatusQ/Components/private/statusMessage/StatusTimeStampLabel.qml @@ -12,7 +12,7 @@ StatusBaseText { color: Theme.palette.baseColor1 font.pixelSize: 10 visible: !!text - text: showFullTimestamp ? LocaleUtils.formatDateTime(timestamp) : LocaleUtils.formatTime(timestamp, Locale.ShortFormat) + text: showFullTimestamp ? LocaleUtils.formatDateTime(timestamp) : LocaleUtils.formatRelativeTimestamp(timestamp) StatusToolTip { id: tooltip visible: hhandler.hovered && !!text diff --git a/ui/StatusQ/src/StatusQ/Core/LocaleUtils.qml b/ui/StatusQ/src/StatusQ/Core/LocaleUtils.qml index 48caeca301..aae632fee1 100644 --- a/ui/StatusQ/src/StatusQ/Core/LocaleUtils.qml +++ b/ui/StatusQ/src/StatusQ/Core/LocaleUtils.qml @@ -78,6 +78,8 @@ QtObject { readonly property var amPmFormatChars: ["AP", "A", "ap", "a"] + readonly property int msInADay: 86400000 + // try to parse date from a number or ISO string timestamp function readDate(value) { if (typeof value === "undefined") // default to "now" if omitted @@ -102,6 +104,13 @@ QtObject { return result } } + + // return full days between 2 dates + function daysBetween(firstDate, secondDate) { + firstDate.setHours(0, 0, 0) // discard time + secondDate.setHours(0, 0, 0) + return Math.round(Math.abs((firstDate - secondDate) / d.msInADay)) // Math.round: not all days are 24 hours long! + } } readonly property Settings settings: Settings { @@ -162,6 +171,34 @@ QtObject { return value.toLocaleString(loc, formatString) } + // TODO use JS Intl.RelativeTimeFormat in Qt 6? + function formatRelativeTimestamp(timestamp) { + const now = new Date() + const value = d.readDate(timestamp) + const loc = Qt.locale() + const formatString = d.fixupTimeFormatString(loc.timeFormat(Locale.ShortFormat)) // format string for the time part + const dayDifference = d.daysBetween(d.readDate(timestamp), now) + + // within last day, 2 or 7 days + if (dayDifference < 1) // today -> "Today 14:23" + return qsTr("Today %1").arg(value.toLocaleTimeString(loc, formatString)) + + if (dayDifference < 2) // yesterday -> "Yesterday 14:23" + return qsTr("Yesterday %1").arg(value.toLocaleTimeString(loc, formatString)) + + if (dayDifference < 7) // last 7 days -> "Mon 14:23" + return qsTr("%1 %2").arg(loc.standaloneDayName(value.getDay(), Locale.ShortFormat)).arg(value.toLocaleTimeString(loc, formatString)) + + // otherwise + var fullFormatString = d.fixupTimeFormatString(loc.dateTimeFormat(Locale.ShortFormat)) + if (now.getFullYear() === value.getFullYear()) + fullFormatString = fullFormatString.replace(/y/g, "") // strip year part, if current year -> "31 December 09:41" + else + fullFormatString = fullFormatString.replace("yy", "yyyy") // different year -> "31 December 2022 09:41" + + return value.toLocaleString(loc, fullFormatString) + } + function getTimeDifference(d1, d2) { const day1Year = d1.getFullYear() const day1Month = d1.getMonth()