aboutsummaryrefslogtreecommitdiff
path: root/lib/eventstats.h
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2021-11-24 19:39:16 +0100
committerGitHub <noreply@github.com>2021-11-24 19:39:16 +0100
commit91c1d93d3389ac924f1013dc7b37dfe70a17e57e (patch)
treea3cbbccf1cb77e0ced68f5dc1175dde0f8999bb6 /lib/eventstats.h
parenta2cc707107464fd98fc8a33afde3ed29f8cd9526 (diff)
parentc57d6de40fb790a4920a9c8ff235511860d68f32 (diff)
downloadlibquotient-91c1d93d3389ac924f1013dc7b37dfe70a17e57e.tar.gz
libquotient-91c1d93d3389ac924f1013dc7b37dfe70a17e57e.zip
Merge pull request #521 from quotient-im/kitsune-unread-statistics
Diffstat (limited to 'lib/eventstats.h')
-rw-r--r--lib/eventstats.h114
1 files changed, 114 insertions, 0 deletions
diff --git a/lib/eventstats.h b/lib/eventstats.h
new file mode 100644
index 00000000..77c661a7
--- /dev/null
+++ b/lib/eventstats.h
@@ -0,0 +1,114 @@
+// SPDX-FileCopyrightText: 2021 Quotient contributors
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include "room.h"
+
+namespace Quotient {
+
+//! \brief Counters of unread events and highlights with a precision flag
+//!
+//! This structure contains a static snapshot with values of unread counters
+//! returned by Room::partiallyReadStats and Room::unreadStats (properties
+//! or methods).
+//!
+//! \note It's just a simple grouping of counters and is not automatically
+//! updated from the room as subsequent syncs arrive.
+//! \sa Room::unreadStats, Room::partiallyReadStats, Room::isEventNotable
+struct EventStats {
+ Q_GADGET
+ Q_PROPERTY(qsizetype notableCount MEMBER notableCount CONSTANT)
+ Q_PROPERTY(qsizetype highlightCount MEMBER highlightCount CONSTANT)
+ Q_PROPERTY(bool isEstimate MEMBER isEstimate CONSTANT)
+public:
+ //! The number of "notable" events in an events range
+ //! \sa Room::isEventNotable
+ qsizetype notableCount = 0;
+ qsizetype highlightCount = 0;
+ //! \brief Whether the counter values above are exact
+ //!
+ //! This is false when the end marker (m.read receipt or m.fully_read) used
+ //! to collect the stats points to an event loaded locally and the counters
+ //! can therefore be calculated exactly using the locally available segment
+ //! of the timeline; true when the marker points to an event outside of
+ //! the local timeline (in which case the estimation is made basing on
+ //! the data supplied by the homeserver as well as counters saved from
+ //! the previous run of the client).
+ bool isEstimate = true;
+
+ // TODO: replace with = default once C++20 becomes a requirement on clients
+ bool operator==(const EventStats& rhs) const
+ {
+ return notableCount == rhs.notableCount
+ && highlightCount == rhs.highlightCount
+ && isEstimate == rhs.isEstimate;
+ }
+ bool operator!=(const EventStats& rhs) const { return !operator==(rhs); }
+
+ //! \brief Check whether the event statistics are empty
+ //!
+ //! Empty statistics have notable and highlight counters of zero and
+ //! isEstimate set to false.
+ Q_INVOKABLE bool empty() const
+ {
+ return notableCount == 0 && !isEstimate && highlightCount == 0;
+ }
+
+ using marker_t = Room::rev_iter_t;
+
+ //! \brief Build event statistics on a range of events
+ //!
+ //! This is a factory that returns an EventStats instance with counts of
+ //! notable and highlighted events between \p from and \p to reverse
+ //! timeline iterators; the \p init parameter allows to override
+ //! the initial statistics object and start from other values.
+ static EventStats fromRange(const Room* room, const marker_t& from,
+ const marker_t& to,
+ const EventStats& init = { 0, 0, false });
+
+ //! \brief Build event statistics on a range from sync edge to marker
+ //!
+ //! This is mainly a shortcut for \code
+ //! <tt>fromRange(room, marker_t(room->syncEdge()), marker)</tt>
+ //! \endcode except that it also sets isEstimate to true if (and only if)
+ //! <tt>to == room->historyEdge()</tt>.
+ static EventStats fromMarker(const Room* room, const marker_t& marker);
+
+ //! \brief Loads a statistics object from the cached counters
+ //!
+ //! Sets isEstimate to `true` unless both notableCount and highlightCount
+ //! are equal to -1.
+ static EventStats fromCachedCounters(Omittable<int> notableCount,
+ Omittable<int> highlightCount = none);
+
+ //! \brief Update statistics when a read marker moves down the timeline
+ //!
+ //! Removes events between oldMarker and newMarker from statistics
+ //! calculation if \p oldMarker points to an existing event in the timeline,
+ //! or recalculates the statistics entirely if \p oldMarker points
+ //! to <tt>room->historyEdge()</tt>. Always results in exact statistics
+ //! (<tt>isEstimate == false</tt>.
+ //! \param oldMarker Must point correspond to the _current_ statistics
+ //! isEstimate state, i.e. it should point to
+ //! <tt>room->historyEdge()</tt> if <tt>isEstimate == true</tt>, or
+ //! to a valid position within the timeline otherwise
+ //! \param newMarker Must point to a valid position in the timeline (not to
+ //! <tt>room->historyEdge()</tt> that is equal to or closer to
+ //! the sync edge than \p oldMarker
+ //! \return true if either notableCount or highlightCount changed, or if
+ //! the statistics was completely recalculated; false otherwise
+ bool updateOnMarkerMove(const Room* room, const marker_t& oldMarker,
+ const marker_t& newMarker);
+
+ //! \brief Validate the statistics object against the given marker
+ //!
+ //! Checks whether the statistics object data are valid for a given marker.
+ //! No stats recalculation takes place, only isEstimate and zero-ness
+ //! of notableCount are checked.
+ bool isValidFor(const Room* room, const marker_t& marker) const;
+};
+
+QDebug operator<<(QDebug dbg, const EventStats& es);
+
+}