diff options
author | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2021-11-21 06:55:09 +0100 |
---|---|---|
committer | Alexey Rusakov <Kitsune-Ral@users.sf.net> | 2021-11-21 07:07:00 +0100 |
commit | bf5f209d2d237301c65cc0973f1707b9386f3110 (patch) | |
tree | 17eadba44dd3c8950acb22169b66b3c10286984c /lib | |
parent | 52e640bce5a8931330fa6d653212e524e7baa2eb (diff) | |
download | libquotient-bf5f209d2d237301c65cc0973f1707b9386f3110.tar.gz libquotient-bf5f209d2d237301c65cc0973f1707b9386f3110.zip |
Room: isEventNotable, notificationFor, checkForNotifications
Room::isEventNotable has been moved out from Room::Private and made
compliant with MSC2654.
The concept of Room::checkForNotifications is taken from Quaternion
where a method with the same name has been in QuaternionRoom for a long
time - however, actual body is a stub for now, always returning
{ Notification::None } (Quaternion's implementation is too crude to be
taken to the library). Now we really need a pushrules processor to fill
this method with something reasonably good. Internally the library now
calls checkForNotifications() on every event added to the timeline,
filling up the events-to-notifications map because it is anticipated
that calculation of notifications can be rather resource-intensive and
should only be done once for a given event.
Finally, Room::notificationsFor is an accessor into the mentioned map,
standing next to isEventNotable (but unlike isEventNotable, it's not
virtual; checkForNotifications is).
Diffstat (limited to 'lib')
-rw-r--r-- | lib/room.cpp | 43 | ||||
-rw-r--r-- | lib/room.h | 36 |
2 files changed, 66 insertions, 13 deletions
diff --git a/lib/room.cpp b/lib/room.cpp index a2ec228a..67f65472 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -116,6 +116,7 @@ public: QHash<QPair<QString, QString>, RelatedEvents> relations; QString displayname; Avatar avatar; + QHash<QString, Notification> notifications; int highlightCount = 0; int notificationCount = 0; members_map_t membersMap; @@ -241,13 +242,6 @@ public: // return EventT::content_type() // } - bool isEventNotable(const TimelineItem& ti) const - { - return !ti->isRedacted() && ti->senderId() != connection->userId() - && is<RoomMessageEvent>(*ti) - && ti.viewAs<RoomMessageEvent>()->replacedEvent().isEmpty(); - } - template <typename EventArrayT> Changes updateStateFrom(EventArrayT&& events) { @@ -709,7 +703,7 @@ Room::Changes Room::Private::updateUnreadCount(const rev_iter_t& from, et.start(); const auto newUnreadMessages = count_if(from, to, - std::bind(&Room::Private::isEventNotable, this, _1)); + std::bind(&Room::isEventNotable, q, _1)); if (et.nsecsElapsed() > profilerMinNsecs() / 10) qCDebug(PROFILER) << "Counting gained unread messages in" << q->objectName() << "took" << et; @@ -742,7 +736,7 @@ Room::Changes Room::Private::recalculateUnreadCount(bool force) et.start(); unreadMessages = int(count_if(timeline.crbegin(), q->fullyReadMarker(), - [this](const auto& ti) { return isEventNotable(ti); })); + [this](const auto& ti) { return q->isEventNotable(ti); })); if (et.nsecsElapsed() > profilerMinNsecs() / 10) qCDebug(PROFILER) << "Recounting unread messages in" << q->objectName() << "took" << et; @@ -837,6 +831,28 @@ bool Room::canSwitchVersions() const return true; } +bool Room::isEventNotable(const TimelineItem &ti) const +{ + const auto& evt = *ti; + const auto* rme = ti.viewAs<RoomMessageEvent>(); + return !evt.isRedacted() + && (is<RoomTopicEvent>(evt) || is<RoomNameEvent>(evt) + || is<RoomAvatarEvent>(evt) || is<RoomTombstoneEvent>(evt) + || (rme && rme->msgtype() != MessageEventType::Notice + && rme->replacedEvent().isEmpty())) + && evt.senderId() != localUser()->id(); +} + +Notification Room::notificationFor(const TimelineItem &ti) const +{ + return d->notifications.value(ti->id()); +} + +Notification Room::checkForNotifications(const TimelineItem &ti) +{ + return { Notification::None }; +} + bool Room::hasUnreadMessages() const { return unreadCount() >= 0; } int Room::unreadCount() const { return d->unreadMessages; } @@ -1548,11 +1564,12 @@ Room::Private::moveEventsToTimeline(RoomEventsRange events, !eventsIndex.contains(eId), __FUNCTION__, makeErrorStr(*e, "Event is already in the timeline; " "incoming events were not properly deduplicated")); - if (placement == Older) - timeline.emplace_front(move(e), --index); - else - timeline.emplace_back(move(e), ++index); + const auto& ti = placement == Older + ? timeline.emplace_front(move(e), --index) + : timeline.emplace_back(move(e), ++index); eventsIndex.insert(eId, index); + if (auto n = q->checkForNotifications(ti); n.type != Notification::None) + notifications.insert(e->id(), n); Q_ASSERT(q->findInTimeline(eId)->event()->id() == eId); } const auto insertedSize = (index - baseIndex) * placement; @@ -96,6 +96,18 @@ inline void swap(ReadReceipt& lhs, ReadReceipt& rhs) swap(lhs.timestamp, rhs.timestamp); } +struct Notification +{ + enum Type { None = 0, Basic, Highlight }; + Q_ENUM(Notification) + + Type type = None; + +private: + Q_GADGET + Q_PROPERTY(Type type MEMBER type CONSTANT) +}; + class Room : public QObject { Q_OBJECT Q_PROPERTY(Connection* connection READ connection CONSTANT) @@ -482,6 +494,29 @@ public: //! \sa markAllMessagesAsRead, fullyReadMarker Q_INVOKABLE void markMessagesAsRead(QString uptoEventId); + //! \brief Determine whether an event should be counted as unread + //! + //! The criteria of including an event in unread counters are described in + //! [MSC2654](https://github.com/matrix-org/matrix-doc/pull/2654); according + //! to these, the event should be counted as unread (or, in libQuotient + //! parlance, is "notable") if it is: + //! - either + //! - a message event that is not m.notice, or + //! - a state event with type being one of: + //! `m.room.topic`, `m.room.name`, `m.room.avatar`, `m.room.tombstone`; + //! - neither redacted, nor an edit (redactions cause the redacted event + //! to stop being notable, while edits are not notable themselves while + //! the original event usually is); + //! - from a non-local user (events from other devices of the local + //! user are not notable). + virtual bool isEventNotable(const TimelineItem& ti) const; + + //! \brief Get notification details for an event + //! + //! This allows to get details on the kind of notification that should + //! generated for \p evt. + Notification notificationFor(const TimelineItem& ti) const; + //! Check whether there are unread messages in the room bool hasUnreadMessages() const; @@ -873,6 +908,7 @@ protected: {} virtual QJsonObject toJson() const; virtual void updateData(SyncRoomData&& data, bool fromCache = false); + virtual Notification checkForNotifications(const TimelineItem& ti); private: friend class Connection; |