libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
room.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2016 Kitsune Ral <Kitsune-Ral@users.sf.net>
2// SPDX-FileCopyrightText: 2017 Roman Plášil <me@rplasil.name>
3// SPDX-FileCopyrightText: 2017 Marius Gripsgard <marius@ubports.com>
4// SPDX-FileCopyrightText: 2018 Josip Delic <delijati@googlemail.com>
5// SPDX-FileCopyrightText: 2018 Black Hat <bhat@encom.eu.org>
6// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru>
7// SPDX-FileCopyrightText: 2020 Ram Nad <ramnad1999@gmail.com>
8// SPDX-License-Identifier: LGPL-2.1-or-later
9
10#pragma once
11
12#include "connection.h"
13#include "roommember.h"
14#include "roomstateview.h"
15#include "eventitem.h"
17
18#include "csapi/message_pagination.h"
19
20#include "events/accountdataevents.h"
21#include "events/encryptedevent.h"
22#include "events/eventrelation.h"
23#include "events/roomcreateevent.h"
24#include "events/roomkeyevent.h"
25#include "events/roommessageevent.h"
26#include "events/roompowerlevelsevent.h"
27#include "events/roomtombstoneevent.h"
28#include "events/roomjoinrulesevent.h"
29
30#include <QtCore/QJsonObject>
31#include <QtGui/QImage>
32#include <QtQmlIntegration/qqmlintegration.h>
33
34#include <deque>
35#include <utility>
36
37namespace Quotient {
38class Event;
39class Avatar;
40class SyncRoomData;
41class RoomMemberEvent;
42class User;
43class RoomMember;
44struct MemberSorter;
45class LeaveRoomJob;
46class SetRoomStateWithKeyJob;
47class RedactEventJob;
48struct ThreadInfo;
49class ThreadInfos;
50
51/** The data structure used to expose file transfer information to views
52 *
53 * This is specifically tuned to work with QML exposing all traits as
54 * Q_PROPERTY values.
55 */
67public:
70 bool isUpload = false;
71 int progress = 0;
72 int total = -1;
73 QUrl localDir {};
74 QUrl localPath {};
75
76 bool started() const { return status == Started; }
77 bool completed() const { return status == Completed; }
78 bool active() const { return started() || completed(); }
79 bool failed() const { return status == Failed; }
80};
81
82//! \brief Data structure for a room member's read receipt
83//! \sa Room::lastReadReceipt
88public:
91
92 bool operator==(const ReadReceipt& other) const
93 {
95 }
96 bool operator!=(const ReadReceipt& other) const
97 {
98 return !operator==(other);
99 }
100};
102{
105}
106
107struct EventStats;
108
110{
111 enum Type { None = 0, Basic, Highlight };
112 Q_ENUM(Type)
113
115
116private:
117 Q_GADGET
118 Q_PROPERTY(Type type MEMBER type CONSTANT)
119};
120
121class QUOTIENT_API Room : public QObject {
125
143 STORED false)
146
154
170 STORED false)
176
179
182
183public:
189
190 //! \brief Room changes that can be tracked using Room::changed() signal
191 //!
192 //! This enumeration lists kinds of changes that can be tracked with
193 //! a "cumulative" changed() signal instead of using individual signals for
194 //! each change. Specific enumerators mention these individual signals.
195 //! \sa changed
196 enum class Change : quint32 { // QFlags can't go more than 32-bit
197 None = 0x0, //!< No changes occurred in the room
198 RoomNames = 0x1, //!< \sa namesChanged, displaynameChanged
199 // NotInUse = 0x2,
200 Topic = 0x4, //!< \sa topicChanged
201 PartiallyReadStats = 0x8, //!< \sa partiallyReadStatsChanged
202 Avatar = 0x10, //!< \sa avatarChanged
203 JoinState = 0x20, //!< \sa joinStateChanged
204 Tags = 0x40, //!< \sa tagsChanged
205 //! \sa userAdded, userRemoved, memberRenamed, memberListChanged,
206 //! displaynameChanged
207 Members = 0x80,
208 UnreadStats = 0x100, //!< \sa unreadStatsChanged
209 // AccountData pre-0.9 = 0x200,
210 Summary = 0x400, //!< \sa summaryChanged, displaynameChanged
211 // ReadMarker pre-0.9 = 0x800,
212 Highlights = 0x1000, //!< \sa highlightCountChanged
213 //! A catch-all value that covers changes not listed above (such as
214 //! encryption turned on or the room having been upgraded), as well as
215 //! changes in the room state that the library is not aware of (e.g.,
216 //! custom state events) and m.read/m.fully_read position changes.
217 //! \sa encryptionChanged, upgraded, accountDataChanged
218 Other = 0x8000,
219 //! This is intended to test a Change/Changes value for non-emptiness;
220 //! adding <tt>& Change::Any</tt> has the same meaning as
221 //! !testFlag(Change::None) or adding <tt>!= Change::None</tt>
222 //! \note testFlag(Change::Any) tests that _all_ bits are on and
223 //! will always return false.
224 Any = 0xFFFF
225 };
227
231
232 // Property accessors
233
235
236 //! Get a RoomMember object for the local user.
238 const QString& id() const;
240 bool isUnstable() const;
242 /// Room predecessor
243 /** This function validates that the predecessor has a tombstone and
244 * the tombstone refers to the current room. If that's not the case,
245 * or if the predecessor is in a join state not matching \p stateFilter,
246 * the function returns nullptr.
247 */
249 | JoinState::Join) const;
251 /// Room successor
252 /** This function validates that the successor room's creation event
253 * refers to the current room. If that's not the case, or if the successor
254 * is in a join state not matching \p stateFilter, it returns nullptr.
255 */
257 | JoinState::Join) const;
258 QString name() const;
261 //! Get a list of both canonical and alternative aliases
265 // Returns events available locally, use pinnedEventIds() for full list
268 QString topic() const;
271 const Avatar& avatarObject() const;
273
274 int timelineSize() const;
275 bool usesEncryption() const;
278 const QString& senderId,
280 const QByteArray& senderKey,
281 const QByteArray& senderEdKey);
282 int joinedCount() const;
283 int invitedCount() const;
284 int totalMemberCount() const;
285
287
288 /**
289 * Returns a square room avatar with the given size and requests it
290 * from the network if needed
291 * \return a pixmap with the avatar or a placeholder if there's none
292 * available yet
293 */
295 /**
296 * Returns a room avatar with the given dimensions and requests it
297 * from the network if needed
298 * \return a pixmap with the avatar or a placeholder if there's none
299 * available yet
300 */
302
303 //! \brief Get a RoomMember object for the given user Matrix ID
304 //!
305 //! Will return a nullptr if there is no m.room.member event for the user in
306 //! the room so needs to be null checked.
307 //!
308 //! \note This can return a member in any state that is known to the room so
309 //! check the state (using RoomMember::membershipState()) before use.
311
312 //! Get a list of room members who have joined the room.
314
315 //! Get a list of all members known to the room.
317
318 //! Get a list of all members known to have left the room.
320
321 //! Get a list of room members who are currently sending a typing indicator.
323
324 //! \brief Get a list of room members who are currently sending a typing indicator.
325 //!
326 //! The local member is excluded from this list.
328
329 //! Get a list of room member Matrix IDs who have joined the room.
331
332 //! Get a list of all member Matrix IDs known to the room.
334
335 //! \brief Get Matrix IDs for room creator(s)
336 //!
337 //! As long as the create event for the room is known, the returned list will start with
338 //! MXID of the room creation event sender. For room versions 12 and newer, the returned list
339 //! will further include additional creators if there are any.
341
342 //! Whether the name for the given member should be disambiguated
344
345 //! \brief Check the join state of a given user in this room
346 //!
347 //! \return the given user's state with respect to the room
349
350 //! Check whether a user with the given id is a member of the room
351 Q_INVOKABLE bool isMember(const QString& userId) const;
352
354
355 //! \brief Get a avatar of the specified dimensions
356 //!
357 //! This always returns immediately; if there's no avatar cached yet, the call triggers
358 //! a network request, that will emit Room::memberAvatarUpdated() once completed.
359 //! \return a pixmap with the avatar or a placeholder if there's none available yet
361
362 //! \brief Get a square avatar of the specified size
363 //!
364 //! This is an overload for the case when the needed width and height are equal.
366
367 const Timeline& messageEvents() const;
369
370 //! \brief Get the number of requested historical events
371 //! \return The number of requested events if there's a pending request; 0 otherwise
373
374 //! Check whether all historical messages are already loaded
375 //! \return true if the "oldest" event in the timeline is a room creation event and there's
376 //! no further history to load; false otherwise
377 bool allHistoryLoaded() const;
378
379 //! \brief Get a reverse iterator at the position before the "oldest" event
380 //!
381 //! Same as messageEvents().crend()
383
384 const ThreadInfos& threads() const;
385
386 //! \brief Get an iterator for the position beyond the latest arrived event
387 //!
388 //! Same as messageEvents().cend()
393
398
403
404 const RoomCreateEvent* creation() const;
406
407 bool displayed() const;
408 /// Mark the room as currently displayed to the user
409 /**
410 * Marking the room displayed causes the room to obtain the full
411 * list of members if it's been lazy-loaded before; in the future
412 * it may do more things bound to "screen time" of the room, e.g.
413 * measure that "screen time".
414 */
415 void setDisplayed(bool displayed = true);
424
425 //! \brief Get the latest read receipt from a user
426 //!
427 //! The user id must be valid. A read receipt with an empty event id
428 //! is returned if the user id is valid but there was no read receipt
429 //! from them.
430 //! \sa usersAtEventId
432
433 //! \brief Get the latest read receipt from the local user
434 //!
435 //! This is a shortcut for <tt>lastReadReceipt(localUserId)</tt>.
436 //! \sa lastReadReceipt
438
439 //! \brief Find the timeline item the local read receipt is at
440 //!
441 //! This is a shortcut for \code
442 //! room->findInTimeline(room->lastLocalReadReceipt().eventId);
443 //! \endcode
445
446 //! \brief Get the latest event id marked as fully read
447 //!
448 //! This can be either the event id pointed to by the actual latest
449 //! m.fully_read event, or the latest event id marked locally as fully read
450 //! if markMessagesAsRead or markAllMessagesAsRead has been called and
451 //! the homeserver didn't return an updated m.fully_read event yet.
452 //! \sa markMessagesAsRead, markAllMessagesAsRead, fullyReadMarker
454
455 //! \brief Get the iterator to the latest timeline item marked as fully read
456 //!
457 //! This method calls findInTimeline on the result of lastFullyReadEventId.
458 //! If the fully read marker turns out to be outside the timeline (because
459 //! the event marked as fully read is too far back in the history) the
460 //! returned value will be equal to historyEdge.
461 //!
462 //! Be sure to read the caveats on iterators returned by findInTimeline.
463 //! \sa lastFullyReadEventId, findInTimeline
465
466 //! \brief Get users whose latest read receipts point to the event
467 //!
468 //! This method is for cases when you need to show users who have read
469 //! an event. Calling it on inexistent or empty event id will return
470 //! an empty set.
471 //! \note The returned list may contain ids resolving to users that are
472 //! not loaded as room members yet (in particular, if members are not
473 //! yet lazy-loaded). For now this merely means that the user's
474 //! room-specific name and avatar will not be there; but generally
475 //! it's recommended to ensure that all room members are loaded
476 //! before operating on the result of this function.
477 //! \sa lastReadReceipt, allMembersLoaded
479
480 //! \brief Mark the event with uptoEventId as fully read
481 //!
482 //! Marks the event with the specified id as fully read locally and also
483 //! sends an update to m.fully_read account data to the server either
484 //! for this message or, if it's from the local user, for
485 //! the nearest non-local message before. uptoEventId must point to a known
486 //! event in the timeline; the method will do nothing if the event is behind
487 //! the current m.fully_read marker or is not loaded, to prevent
488 //! accidentally trying to move the marker back in the timeline.
489 //! \param sendPublicReceipts if true, a public read receipt (m.read) will also be sent to the server.
490 //! \sa markAllMessagesAsRead, fullyReadMarker
492
493 //! \brief Determine whether an event should be counted as unread
494 //!
495 //! The criteria of including an event in unread counters are described in
496 //! [MSC2654](https://github.com/matrix-org/matrix-doc/pull/2654); according
497 //! to these, the event should be counted as unread (or, in libQuotient
498 //! parlance, is "notable") if it is:
499 //! - either
500 //! - a message event that is not m.notice, or
501 //! - a state event with type being one of:
502 //! `m.room.topic`, `m.room.name`, `m.room.avatar`, `m.room.tombstone`;
503 //! - neither redacted, nor an edit (redactions cause the redacted event
504 //! to stop being notable, while edits are not notable themselves while
505 //! the original event usually is);
506 //! - from a non-local user (events from other devices of the local
507 //! user are not notable).
508 //! \sa partiallyReadStats, unreadStats
509 virtual bool isEventNotable(const TimelineItem& ti) const;
510
511 //! \brief Get notification details for an event
512 //!
513 //! This allows to get details on the kind of notification that should
514 //! generated for \p evt.
516
517 //! \brief Get event statistics since the fully read marker
518 //!
519 //! This call returns a structure containing:
520 //! - the number of notable unread events since the fully read marker;
521 //! depending on the fully read marker state with respect to the local
522 //! timeline, this number may be either exact or estimated
523 //! (see EventStats::isEstimate);
524 //! - the number of highlights (TODO).
525 //!
526 //! Note that this is different from the unread count defined by MSC2654
527 //! and from the notification/highlight numbers defined by the spec in that
528 //! it counts events since the fully read marker, not since the last
529 //! read receipt position.
530 //!
531 //! As E2EE is not supported in the library, the returned result will always
532 //! be an estimate (<tt>isEstimate == true</tt>) for encrypted rooms;
533 //! moreover, since the library doesn't know how to tackle push rules yet
534 //! the number of highlights returned here will always be zero (there's no
535 //! good substitute for that now).
536 //!
537 //! \sa isEventNotable, fullyReadMarker, unreadStats, EventStats
539
540 //! \brief Get event statistics since the last read receipt
541 //!
542 //! This call returns a structure that contains the following three numbers,
543 //! all counted on the timeline segment between the event pointed to by
544 //! the m.fully_read marker and the sync edge:
545 //! - the number of unread events - depending on the read receipt state
546 //! with respect to the local timeline, this number may be either precise
547 //! or estimated (see EventStats::isEstimate);
548 //! - the number of highlights (TODO).
549 //!
550 //! As E2EE is not supported in the library, the returned result will always
551 //! be an estimate (<tt>isEstimate == true</tt>) for encrypted rooms;
552 //! moreover, since the library doesn't know how to tackle push rules yet
553 //! the number of highlights returned here will always be zero - use
554 //! highlightCount() for now.
555 //!
556 //! \sa isEventNotable, lastLocalReadReceipt, partiallyReadStats,
557 //! highlightCount
559
560 //! \brief Get the number of notifications since the last read receipt
561 //!
562 //! This is the same as <tt>unreadStats().notableCount</tt>.
563 //!
564 //! \sa unreadStats, lastLocalReadReceipt
566
567 //! \brief Get the number of highlights since the last read receipt
568 //!
569 //! As of 0.7, this is defined by the homeserver as Quotient doesn't process
570 //! push rules.
571 //!
572 //! \sa unreadStats, lastLocalReadReceipt
574
575 /** Check whether the room has account data of the given type
576 * Tags and read markers are not supported by this method _yet_.
577 */
578 bool hasAccountData(const QString& type) const;
579
580 /** Get a generic account data event of the given type
581 * This returns a generic hash map for any room account data event
582 * stored on the server. Tags and read markers cannot be retrieved
583 * using this method _yet_.
584 */
585 const EventPtr& accountData(const QString& type) const;
586
587 //! Get a list of all room account data events
588 //! \return A list of event types that exist in the room
590
592 TagsMap tags() const;
593 Tag tag(const QString& name) const;
594
595 /** Add a new tag to this room
596 * If this room already has this tag, nothing happens. If it's a new
597 * tag for the room, the respective tag record is added to the set
598 * of tags and the new set is sent to the server to update other
599 * clients.
600 */
601 void addTag(const QString& name, const Tag& tagData = {});
602 Q_INVOKABLE void addTag(const QString& name, float order);
603
604 /// Remove a tag from the room
606
607 /// The scope to apply an action on
608 /*! This enumeration is used to pick a strategy to propagate certain
609 * actions on the room to its predecessors and successors.
610 */
612 ThisRoomOnly, ///< Do not apply to predecessors and successors
613 WithinSameState, ///< Apply to predecessors and successors in the same
614 ///< state as the current one
615 OmitLeftState, ///< Apply to all reachable predecessors and successors
616 ///< except those in Leave state
617 WholeSequence ///< Apply to all reachable predecessors and successors
618 };
619
620 /** Overwrite the room's tags
621 * This completely replaces the existing room's tags with a set
622 * of new ones and updates the new set on the server. Unlike
623 * most other methods in Room, this one sends a signal about changes
624 * immediately, not waiting for confirmation from the server
625 * (because tags are saved in account data rather than in shared
626 * room state).
627 * \param applyOn setting this to Room::OnAllConversations will set tags
628 * on this and all _known_ predecessors and successors;
629 * by default only the current room is changed
630 */
632
633 /// Check whether the list of tags has m.favourite
634 bool isFavourite() const;
635 /// Check whether the list of tags has m.lowpriority
636 bool isLowPriority() const;
637 /// Check whether this room is for server notices (MSC1452)
638 bool isServerNoticeRoom() const;
639
640 /// Check whether this room is a direct chat
642
643 /// Get the list of members this room is a direct chat with
645
647 const QUrl &mxcUrl) const;
648
651
652 /// Get a file name for downloading for a given event id
653 /*!
654 * The event MUST be RoomMessageEvent and have content
655 * for downloading. \sa RoomMessageEvent::hasContent
656 */
658
659 /// Get information on file upload/download
660 /*!
661 * \param id uploads are identified by the corresponding event's
662 * transactionId (because uploads are done before
663 * the event is even sent), while downloads are using
664 * the normal event id for identifier.
665 */
668
669 /// Get the URL to the actual file source in a unified way
670 /*!
671 * For uploads it will return a URL to a local file; for downloads
672 * the URL will be taken from the corresponding room event.
673 */
675
676 /** Pretty-prints plain text into HTML
677 * As of now, it's exactly the same as Quotient::prettyPrint();
678 * in the future, it will also linkify room aliases, mxids etc.
679 * using the room context.
680 */
682
684
685 /// Whether the current user is allowed to upgrade the room
687
688 /// \brief Get the current room state
690
691 //! \brief The current Join Rule for the room
692 //!
693 //! \sa https://spec.matrix.org/latest/client-server-api/#mroomjoin_rules
695
696 //! \brief Set the Join Rule for the room
697 //!
698 //! If the local user does not have a high enough power level the request is rejected.
699 //!
700 //! \param newRule the new JoinRule to apply to the room
701 //! \param allowedRooms only required when the join rule is restricted. This is a
702 //! list of room IDs that members of can join without an invite.
703 //! If the rule is restricted and this list is empty it is treated as a join
704 //! rule of invite instead.
705 //!
706 //! \note While any room ID is permitted it is designed to be only spaces that are
707 //! input. I.e. only memebers of space `x` can join this room.
708 //!
709 //! \sa https://spec.matrix.org/latest/client-server-api/#mroomjoin_rules
711
712 //! \brief The list of Room IDs for when the join rule is Restricted
713 //!
714 //! This value will be empty when the Join Rule is not Restricted or
715 //! Knock-Restricted.
716 //!
717 //! \sa https://spec.matrix.org/latest/client-server-api/#mroomjoin_rules
719
720 //! \brief The effective power level of the given member in the room
721 //!
722 //! This is normally the same as calling `RoomPowerLevelEvent::powerLevelForUser(userId)` but
723 //! takes into account the room context and works even if the room state has no power levels
724 //! event. It is THE recommended way to get a room member's power level to display in the UI.
725 //! \param memberId The room member ID to check; if empty, the local user will be checked
726 //! \sa RoomPowerLevelsEvent, https://spec.matrix.org/v1.11/client-server-api/#mroompower_levels
728
729 //! \brief Get the power level required to send events of the given type
730 //!
731 //! \note This is a generic method that only gets the power level to send events with a given
732 //! type. Some operations have additional restrictions or enablers though: e.g.,
733 //! room member changes (kicks, invites) have special power levels; on the other hand,
734 //! redactions of one's own messages are allowed regardless of the power level.
735 //! The library has no method to check effective ability to perform an operation as yet;
736 //! you have to either blindly make a call to the homeserver or implement the logic
737 //! described in the Federation API and respective room versions, in the client code.
738 //! \note Unlike the template version below, this method determines at runtime whether an event
739 //! type is that of a state event, assuming unknown event types to be non-state; pass
740 //! `true` as the second parameter to override that.
741 //! \sa canSwitchVersions
743
744 //! \brief Get the power level required to send events of the given type
745 //!
746 //! This is an optimised version of non-template powerLevelFor() (with the same caveat about
747 //! operations based on some event types) for cases when the event type is known at build time.
748 //! \tparam EvT the event type to get the power level for
749 template <EventClass EvT>
750 int powerLevelFor() const
751 {
753 }
754
755 //! \brief Post a pre-created room message event
756 //!
757 //! Takes ownership of the event, deleting it once the matching one arrives with the sync.
758 //! \note Do not assume that the event is already on the road to the homeserver when this (or
759 //! any other `post*`) method returns; it can be queued internally.
760 //! \sa PendingEventItem::deliveryStatus()
761 //! \return a reference to the pending event item
763
764 template <typename EvT, typename... ArgTs>
766 {
767 return post(makeEvent<EvT>(std::forward<ArgTs>(args)...));
768 }
769
770 //! \brief Send a text type message
771 //!
772 //! This means MessageEventType Text, Emote or Notice.
775 const std::optional<QString>& html = std::nullopt,
777 {
778 static_assert(type == MessageEventType::Text ||
781 "MessageEvent type is not a text message"
782 );
783
785 if (html) {
786 content = std::make_unique<EventContent::TextContent>(*html, u"text/html"_s);
787 }
789 }
790
791 //! Send a file with the given content
795
796 //! Send the given Json as a message
798
799 //! Send a reaction on a given event with a given key
801
803
804 //! Send a request to update the room state with the given event
806
807 //! \brief Set a state event of the given type with the given arguments
808 //!
809 //! This type-safe overload attempts to send a state event of the type \p EvT constructed from
810 //! \p args.
811 template <typename EvT, typename... ArgTs>
812 auto setState(ArgTs&&... args)
813 {
814 return setState(EvT(std::forward<ArgTs>(args)...));
815 }
816
818
820
822
823 //! \brief Upgrade the room to \p newVersion
824 //!
825 //! Triggers an upgrade process that puts the tombstone event on the current room and creates
826 //! a new room of the specified version. It is possible to specify \p additionalCreators for
827 //! room versions that support those (unfortunately it is only possible to find out whether
828 //! a given room version supports additional creators by attempting to upgrade a room).
829 //! \return a future eventually holding a new room once it arrives via sync
832
833public Q_SLOTS:
834 /** Check whether the room should be upgraded */
836
839
840 //! Send a request to update the room state based on freeform inputs
842 const QString& stateKey,
843 const QJsonObject& contentJson);
844 void setName(const QString& newName);
847 /// Set room aliases on the user's current server
850
851 /// You shouldn't normally call this method; it's here for debugging
853
855
858 void kickMember(const QString& memberId, const QString& reason = {});
859 void ban(const QString& userId, const QString& reason = {});
860 void unban(const QString& userId);
861 void redactEvent(const QString& eventId, const QString& reason = {});
862
864 const QString& overrideContentType = {});
865 // If localFilename is empty a temporary file is created
866 void downloadFile(const QString& eventId, const QUrl& localFilename = {});
868
869 //! \brief Set a given event as last read and post a read receipt on it
870 //!
871 //! Does nothing if the event is behind the current read receipt.
872 //! \sa lastReadReceipt, markMessagesAsRead, markAllMessagesAsRead
874 //! Put the fully-read marker at the latest message in the room
875 //! \param sendPublicReceipts if true, a public read receipt (m.read) will also be sent to the server for the latest message.
877
878 //! Switch the room's version (aka upgrade)
879 [[deprecated("Use upgrade() instead")]]
881
882 void inviteCall(const QString& callId, const int lifetime,
883 const QString& sdp);
885 void answerCall(const QString& callId, const QString& sdp);
887
888 /**
889 * Activates encryption for this room.
890 * Warning: Cannot be undone
891 */
893
894 //! \brief Mark this room as a direct chat, guessing which user should be the DM recipient
895 //!
896 //! This function marks this room as a direct chat. There is no option to provide a user id here.
897 //! Emits the signal synchronously, without waiting to complete
898 //! synchronisation with the server.
899 //!
900 //! This function does nothing if you are the sole user, or there are more than two users in the room
901 //!
902 //! \sa directChatsListChanged
904
906 /// Initial set of state events has been loaded
907 /**
908 * The initial set is what comes from the initial sync for the room.
909 * This includes all basic things like RoomCreateEvent,
910 * RoomNameEvent, a (lazy-loaded, not full) set of RoomMemberEvents
911 * etc. This is a per-room reflection of Connection::loadedRoomState
912 * \sa Connection::loadedRoomState
913 */
919 /// The event is about to be appended to the list of pending events
921 /// An event has been appended to the list of pending events
923 /// The remote echo has arrived with the sync and will be merged
924 /// with its local counterpart
925 /** NB: Requires a sync loop to be emitted */
928 /// The remote and local copies of the event have been merged
929 /** NB: Requires a sync loop to be emitted */
931 /// An event will be removed from the list of pending events
933 /// An event has just been removed from the list of pending events
935 /// The status of a pending event has changed
936 /** \sa PendingEventItem::deliveryStatus */
938 /// The server accepted the message
939 /** This is emitted when an event sending request has successfully
940 * completed. This does not mean that the event is already in the
941 * local timeline, only that the server has accepted it.
942 * \param txnId transaction id assigned by the client during sending
943 * \param eventId event id assigned by the server upon acceptance
944 * \sa postEvent, postPlainText, postMessage, postHtmlMessage
945 * \sa pendingEventMerged, aboutToAddNewMessages
946 */
948
949 //! A new thread has been created/added in the room
951
952 /** A common signal for various kinds of changes in the room
953 * Aside from all changes in the room state
954 * @param changes a set of flags describing what changes occurred
955 * upon the last sync
956 * \sa Changes
957 */
959 /**
960 * \brief The room name, the canonical alias or other aliases changed
961 *
962 * Not triggered when display name changes.
963 */
970
971 //! \brief The join rule for the room has changed
973
974 //! \brief A new member has joined the room
975 //!
976 //! This can be from any previous state or a member previously unknown to
977 //! the room.
979
980 //! \brief A member who previously joined has left
981 //!
982 //! The member will still be known to the room their membership state has changed
983 //! from Membership::Join to anything else.
985
986 //! A known joined member is about to update their display name
988
989 //! A known joined member has updated their display name
991
992 //! A known joined member has updated their avatar
994
995 /// The list of members has changed
996 /** Emitted no more than once per sync, this is a good signal to
997 * for cases when some action should be done upon any change in
998 * the member list. If you need per-item granularity you should use
999 * userAdded, userRemoved and memberAboutToRename / memberRenamed
1000 * instead.
1001 */
1003
1004 /// The previously lazy-loaded members list is now loaded entirely
1005 /// \sa setDisplayed
1008
1011
1012 //! The list of members sending typing indicators has changed.
1014
1015 void highlightCountChanged(); ///< \sa highlightCount
1016 void notificationCountChanged(); ///< \sa notificationCount
1017
1021 //! The event the m.read receipt points to has changed for the listed users
1022 //! \sa lastReadReceipt
1028
1033
1036 const Quotient::RoomEvent* oldEvent);
1037
1043 // fileTransferCancelled() is no more here; use fileTransferFailed() and
1044 // check the transfer status instead
1045
1047
1048 /// The room's version stability may have changed
1051 /// This room has been upgraded and won't receive updates any more
1053 /// An attempted room upgrade has failed
1055
1056 /// The room is about to be deleted
1058
1059protected:
1063 virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) {}
1065 virtual void onRedaction(const RoomEvent& /*prevEvent*/,
1066 const RoomEvent& /*after*/)
1067 {}
1068 virtual QJsonObject toJson() const;
1069 virtual void updateData(SyncRoomData&& data, bool fromCache = false);
1071
1072private:
1073 friend class Connection;
1074
1075 class Private;
1076 Private* d;
1077
1078 // This is called from Connection, reflecting a state change that
1079 // arrived from the server. Clients should use
1080 // Connection::joinRoom() and Room::leaveRoom() to change the state.
1082};
1083
1084template <typename RangeT, typename ValT, typename CompT = MemberSorter,
1085 typename ProjT = std::identity>
1088[[deprecated("Use std::ranges::lower_bound(range, ...) - std::ranges::begin(range)")]]
1089inline std::ranges::range_size_t<RangeT> lowerBoundMemberIndex(const RangeT &rng, const ValT &val,
1090 CompT comp = {}, ProjT proj = {})
1091{
1092 return std::ranges::lower_bound(rng, val, std::move(comp), std::move(proj))
1093 - std::ranges::begin(rng);
1094}
1095} // namespace Quotient
1097Q_DECLARE_METATYPE(Quotient::ReadReceipt)
1098Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::Room::Changes)
Data structure for a room member's read receipt.
Definition room.h:84
void swap(ReadReceipt &lhs, ReadReceipt &rhs)
Definition room.h:101
std::ranges::range_size_t< RangeT > lowerBoundMemberIndex(const RangeT &rng, const ValT &val, CompT comp={}, ProjT proj={})
Definition room.h:1089
#define QUO_DECLARE_FLAGS(Flags, Enum)
Quotient replacement for the Q_FLAG/Q_DECLARE_FLAGS combination.
#define QUOTIENT_API