18 #include "csapi/message_pagination.h"
20 #include "events/accountdataevents.h"
21 #include "events/encryptedevent.h"
22 #include "events/roomkeyevent.h"
23 #include "events/roommessageevent.h"
24 #include "events/roomcreateevent.h"
25 #include "events/roomtombstoneevent.h"
26 #include "events/eventrelation.h"
28 #include <QtCore/QJsonObject>
29 #include <QtGui/QImage>
38 class RoomMemberEvent;
43 class SetRoomStateWithKeyJob;
53 Q_PROPERTY(
bool isUpload MEMBER isUpload CONSTANT)
54 Q_PROPERTY(
bool active READ active CONSTANT)
55 Q_PROPERTY(
bool started READ started CONSTANT)
56 Q_PROPERTY(
bool completed READ completed CONSTANT)
57 Q_PROPERTY(
bool failed READ failed CONSTANT)
58 Q_PROPERTY(
int progress MEMBER progress CONSTANT)
59 Q_PROPERTY(
int total MEMBER total CONSTANT)
60 Q_PROPERTY(QUrl localDir MEMBER localDir CONSTANT)
61 Q_PROPERTY(QUrl localPath MEMBER localPath CONSTANT)
63 enum Status { None, Started, Completed, Failed, Cancelled };
65 bool isUpload =
false;
71 bool started()
const {
return status == Started; }
72 bool completed()
const {
return status == Completed; }
73 bool active()
const {
return started() || completed(); }
74 bool failed()
const {
return status == Failed; }
81 Q_PROPERTY(QString eventId MEMBER eventId CONSTANT)
82 Q_PROPERTY(QDateTime timestamp MEMBER timestamp CONSTANT)
85 QDateTime timestamp = {};
87 bool operator==(
const ReadReceipt& other)
const
89 return eventId == other.eventId && timestamp == other.timestamp;
91 bool operator!=(
const ReadReceipt& other)
const
93 return !operator==(other);
96 inline void swap(ReadReceipt& lhs, ReadReceipt& rhs)
98 swap(lhs.eventId, rhs.eventId);
99 swap(lhs.timestamp, rhs.timestamp);
106 enum Type { None = 0, Basic, Highlight };
113 Q_PROPERTY(Type type MEMBER type CONSTANT)
118 Q_PROPERTY(Connection* connection READ connection CONSTANT)
119 Q_PROPERTY(RoomMember localMember READ localMember CONSTANT)
120 Q_PROPERTY(QString id READ id CONSTANT)
121 Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded)
122 Q_PROPERTY(
bool isUnstable READ isUnstable NOTIFY stabilityUpdated)
123 Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
124 Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
125 Q_PROPERTY(QString name READ name NOTIFY namesChanged)
126 Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
127 Q_PROPERTY(QStringList altAliases READ altAliases NOTIFY namesChanged)
128 Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
129 Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
130 Q_PROPERTY(QStringList pinnedEventIds READ pinnedEventIds WRITE setPinnedEvents
131 NOTIFY pinnedEventsChanged)
132 Q_PROPERTY(QString displayNameForHtml READ displayNameForHtml NOTIFY displaynameChanged)
133 Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
134 Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
136 Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
137 Q_PROPERTY(
bool usesEncryption READ usesEncryption NOTIFY encryption)
139 Q_PROPERTY(
int timelineSize READ timelineSize NOTIFY addedMessages)
140 Q_PROPERTY(
int joinedCount READ joinedCount NOTIFY memberListChanged)
141 Q_PROPERTY(
int invitedCount READ invitedCount NOTIFY memberListChanged)
142 Q_PROPERTY(
int totalMemberCount READ totalMemberCount NOTIFY memberListChanged)
143 Q_PROPERTY(QList<RoomMember> membersTyping READ membersTyping NOTIFY typingChanged)
144 Q_PROPERTY(QList<RoomMember> otherMembersTyping READ otherMembersTyping NOTIFY typingChanged)
146 Q_PROPERTY(
bool displayed READ displayed WRITE setDisplayed NOTIFY
148 Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId WRITE
149 setFirstDisplayedEventId NOTIFY firstDisplayedEventChanged)
150 Q_PROPERTY(QString lastDisplayedEventId READ lastDisplayedEventId WRITE
151 setLastDisplayedEventId NOTIFY lastDisplayedEventChanged)
152 Q_PROPERTY(QString lastFullyReadEventId READ lastFullyReadEventId WRITE
153 markMessagesAsRead NOTIFY fullyReadMarkerMoved)
154 Q_PROPERTY(qsizetype highlightCount READ highlightCount
155 NOTIFY highlightCountChanged)
156 Q_PROPERTY(qsizetype notificationCount READ notificationCount
157 NOTIFY notificationCountChanged)
158 Q_PROPERTY(EventStats partiallyReadStats READ partiallyReadStats NOTIFY partiallyReadStatsChanged)
159 Q_PROPERTY(EventStats unreadStats READ unreadStats NOTIFY unreadStatsChanged)
160 Q_PROPERTY(
bool allHistoryLoaded READ allHistoryLoaded NOTIFY allHistoryLoadedChanged
162 Q_PROPERTY(QStringList tagNames READ tagNames NOTIFY tagsChanged)
163 Q_PROPERTY(
bool isFavourite READ isFavourite NOTIFY tagsChanged STORED
false)
164 Q_PROPERTY(
bool isLowPriority READ isLowPriority NOTIFY tagsChanged STORED
false)
166 Q_PROPERTY(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob NOTIFY eventsHistoryJobChanged)
167 Q_PROPERTY(
int requestedHistorySize READ requestedHistorySize NOTIFY eventsHistoryJobChanged)
169 Q_PROPERTY(QStringList accountDataEventTypes READ accountDataEventTypes NOTIFY accountDataChanged)
172 using Timeline = std::deque<TimelineItem>;
173 using PendingEvents = std::vector<PendingEventItem>;
174 using RelatedEvents = QVector<
const RoomEvent*>;
175 using rev_iter_t = Timeline::const_reverse_iterator;
176 using timeline_iter_t = Timeline::const_iterator;
184 enum class Change : quint32 {
189 PartiallyReadStats = 0x8,
216 Room(Connection* connection, QString id, JoinState initialJoinState);
217 Q_DISABLE_COPY_MOVE(Room)
222 Connection* connection()
const;
225 RoomMember localMember()
const;
226 const QString& id()
const;
227 QString version()
const;
228 bool isUnstable()
const;
229 QString predecessorId()
const;
236 Room* predecessor(JoinStates statesFilter = JoinState::Invite
237 | JoinState::Join)
const;
238 QString successorId()
const;
244 Room* successor(JoinStates statesFilter = JoinState::Invite
245 | JoinState::Join)
const;
246 QString name()
const;
247 QString canonicalAlias()
const;
248 QStringList altAliases()
const;
250 QStringList aliases()
const;
251 QString displayName()
const;
252 QStringList pinnedEventIds()
const;
254 QVector<
const RoomEvent*> pinnedEvents()
const;
255 QString displayNameForHtml()
const;
256 QString topic()
const;
257 QString avatarMediaId()
const;
258 QUrl avatarUrl()
const;
259 const Avatar& avatarObject()
const;
260 Q_INVOKABLE JoinState joinState()
const;
262 int timelineSize()
const;
263 bool usesEncryption()
const;
264 RoomEventPtr decryptMessage(
const EncryptedEvent& encryptedEvent);
265 void handleRoomKeyEvent(
const RoomKeyEvent& roomKeyEvent,
266 const QString& senderId,
267 const QByteArray& olmSessionId,
268 const QByteArray& senderKey);
269 int joinedCount()
const;
270 int invitedCount()
const;
271 int totalMemberCount()
const;
273 GetRoomEventsJob* eventsHistoryJob()
const;
281 Q_INVOKABLE QImage avatar(
int dimension);
288 Q_INVOKABLE QImage avatar(
int width,
int height);
297 Q_INVOKABLE RoomMember member(
const QString& userId)
const;
300 QList<RoomMember> joinedMembers()
const;
303 QList<RoomMember> members()
const;
306 QList<RoomMember> membersLeft()
const;
309 QList<RoomMember> membersTyping()
const;
314 QList<RoomMember> otherMembersTyping()
const;
317 QStringList joinedMemberIds()
const;
320 QStringList memberIds()
const;
323 bool needsDisambiguation(
const QString& userId)
const;
328 Q_INVOKABLE Quotient::Membership memberState(
const QString& userId)
const;
331 Q_INVOKABLE
bool isMember(
const QString& userId)
const;
333 const Avatar& memberAvatar(
const QString& memberId)
const;
335 const Timeline& messageEvents()
const;
336 const PendingEvents& pendingEvents()
const;
340 int requestedHistorySize()
const;
345 bool allHistoryLoaded()
const;
350 rev_iter_t historyEdge()
const;
354 Timeline::const_iterator syncEdge()
const;
355 Q_INVOKABLE Quotient::TimelineItem::index_t minTimelineIndex()
const;
356 Q_INVOKABLE Quotient::TimelineItem::index_t maxTimelineIndex()
const;
357 Q_INVOKABLE
bool isValidIndex(Quotient::TimelineItem::index_t timelineIndex)
const;
359 rev_iter_t findInTimeline(TimelineItem::index_t index)
const;
360 rev_iter_t findInTimeline(
const QString& evtId)
const;
361 PendingEvents::iterator findPendingEvent(
const QString& txnId);
362 PendingEvents::const_iterator findPendingEvent(
const QString& txnId)
const;
364 const RelatedEvents relatedEvents(
const QString& evtId,
365 EventRelation::reltypeid_t relType)
const;
366 const RelatedEvents relatedEvents(
const RoomEvent& evt,
367 EventRelation::reltypeid_t relType)
const;
369 const RoomCreateEvent* creation()
const;
370 const RoomTombstoneEvent* tombstone()
const;
372 bool displayed()
const;
380 void setDisplayed(
bool displayed =
true);
381 QString firstDisplayedEventId()
const;
382 rev_iter_t firstDisplayedMarker()
const;
383 void setFirstDisplayedEventId(
const QString& eventId);
384 void setFirstDisplayedEvent(TimelineItem::index_t index);
385 QString lastDisplayedEventId()
const;
386 rev_iter_t lastDisplayedMarker()
const;
387 void setLastDisplayedEventId(
const QString& eventId);
388 void setLastDisplayedEvent(TimelineItem::index_t index);
396 ReadReceipt lastReadReceipt(
const QString& userId)
const;
402 ReadReceipt lastLocalReadReceipt()
const;
409 rev_iter_t localReadReceiptMarker()
const;
418 QString lastFullyReadEventId()
const;
429 rev_iter_t fullyReadMarker()
const;
443 QSet<QString> userIdsAtEvent(
const QString& eventId)
const;
455 Q_INVOKABLE
void markMessagesAsRead(
const QString& uptoEventId);
473 virtual bool isEventNotable(
const TimelineItem& ti)
const;
479 Notification notificationFor(
const TimelineItem& ti)
const;
502 EventStats partiallyReadStats()
const;
522 EventStats unreadStats()
const;
529 qsizetype notificationCount()
const;
537 qsizetype highlightCount()
const;
542 bool hasAccountData(
const QString& type)
const;
549 const EventPtr& accountData(
const QString& type)
const;
553 QStringList accountDataEventTypes()
const;
555 QStringList tagNames()
const;
556 TagsMap tags()
const;
557 TagRecord tag(
const QString& name)
const;
565 void addTag(
const QString& name,
const TagRecord& record = {});
566 Q_INVOKABLE
void addTag(
const QString& name,
float order);
569 Q_INVOKABLE
void removeTag(
const QString& name);
595 void setTags(TagsMap newTags, ActionScope applyOn = ThisRoomOnly);
598 bool isFavourite()
const;
600 bool isLowPriority()
const;
602 bool isServerNoticeRoom()
const;
605 Q_INVOKABLE
bool isDirectChat()
const;
608 QList<RoomMember> directChatMembers()
const;
610 Q_INVOKABLE QUrl makeMediaUrl(
const QString& eventId,
611 const QUrl &mxcUrl)
const;
613 Q_INVOKABLE QUrl urlToThumbnail(
const QString& eventId)
const;
614 Q_INVOKABLE QUrl urlToDownload(
const QString& eventId)
const;
621 Q_INVOKABLE QString fileNameToDownload(
const QString& eventId)
const;
630 Q_INVOKABLE Quotient::FileTransferInfo
631 fileTransferInfo(
const QString& id)
const;
638 Q_INVOKABLE QUrl fileSource(
const QString& id)
const;
645 Q_INVOKABLE QString prettyPrint(
const QString& plainText)
const;
647 #if Quotient_VERSION_MAJOR == 0
&& Quotient_VERSION_MINOR < 10
648 [[deprecated(
"Create MemberSorter objects directly instead")]]
649 MemberSorter memberSorter()
const;
652 Q_INVOKABLE
bool supportsCalls()
const;
655 Q_INVOKABLE
bool canSwitchVersions()
const;
658 RoomStateView currentState()
const;
661 SetRoomStateWithKeyJob* setState(
const StateEvent& evt);
676 template <
typename EvT,
typename... ArgTs>
677 auto setState(ArgTs&&... args)
679 return setState(EvT(std::forward<ArgTs>(args)...));
682 void addMegolmSessionFromBackup(
const QByteArray &sessionId,
const QByteArray &sessionKey, uint32_t index,
const QByteArray& senderKey);
684 Q_INVOKABLE
void startVerification();
690 QString postMessage(
const QString& plainText, MessageEventType type);
691 QString postPlainText(
const QString& plainText);
692 QString postHtmlMessage(
const QString& plainText,
const QString& html,
693 MessageEventType type = MessageEventType::Text);
694 QString postHtmlText(
const QString& plainText,
const QString& html);
696 QString postReaction(
const QString& eventId,
const QString& key);
698 QString postFile(
const QString& plainText, EventContent::TypedBase* content);
706 QString postEvent(RoomEvent* event);
707 QString postJson(
const QString& matrixType,
const QJsonObject& eventContent);
708 QString retryMessage(
const QString& txnId);
709 void discardMessage(
const QString& txnId);
712 SetRoomStateWithKeyJob* setState(
const QString& evtType,
713 const QString& stateKey,
714 const QJsonObject& contentJson);
715 void setName(
const QString& newName);
716 void setCanonicalAlias(
const QString& newAlias);
717 void setPinnedEvents(
const QStringList& events);
719 void setLocalAliases(
const QStringList& aliases);
720 void setTopic(
const QString& newTopic);
723 void refreshDisplayName();
725 JobHandle<GetRoomEventsJob> getPreviousContent(
int limit = 10,
const QString &filter = {});
727 void inviteToRoom(
const QString& memberId);
728 LeaveRoomJob* leaveRoom();
729 void kickMember(
const QString& memberId,
const QString& reason = {});
730 void ban(
const QString& userId,
const QString& reason = {});
731 void unban(
const QString& userId);
732 void redactEvent(
const QString& eventId,
const QString& reason = {});
734 void uploadFile(
const QString& id,
const QUrl& localFilename,
735 const QString& overrideContentType = {});
737 void downloadFile(
const QString& eventId,
const QUrl& localFilename = {});
738 void cancelFileTransfer(
const QString& id);
744 void setReadReceipt(
const QString& atEventId);
746 void markAllMessagesAsRead();
749 void switchVersion(QString newVersion);
751 void inviteCall(
const QString& callId,
const int lifetime,
753 void sendCallCandidates(
const QString& callId,
const QJsonArray& candidates);
754 void answerCall(
const QString& callId,
const QString& sdp);
755 void hangupCall(
const QString& callId);
761 void activateEncryption();
772 void baseStateLoaded();
773 void eventsHistoryJobChanged();
774 void aboutToAddHistoricalMessages(Quotient::RoomEventsRange events);
775 void aboutToAddNewMessages(Quotient::RoomEventsRange events);
776 void addedMessages(
int fromIndex,
int toIndex);
778 void pendingEventAboutToAdd(Quotient::RoomEvent* event);
780 void pendingEventAdded();
784 void pendingEventAboutToMerge(Quotient::RoomEvent* serverEvent,
785 int pendingEventIndex);
788 void pendingEventMerged();
790 void pendingEventAboutToDiscard(
int pendingEventIndex);
792 void pendingEventDiscarded();
795 void pendingEventChanged(
int pendingEventIndex);
805 void messageSent(QString txnId, QString eventId);
813 void changed(Quotient::Room::Changes changes);
819 void namesChanged(Quotient::Room* room);
820 void displaynameAboutToChange(Quotient::Room* room);
821 void displaynameChanged(Quotient::Room* room, QString oldName);
822 void pinnedEventsChanged();
824 void avatarChanged();
830 void memberJoined(RoomMember member);
836 void memberLeft(RoomMember member);
839 void memberNameAboutToUpdate(RoomMember member, QString newName);
842 void memberNameUpdated(RoomMember member);
845 void memberAvatarUpdated(RoomMember member);
854 void memberListChanged();
858 void allMembersLoaded();
861 void joinStateChanged(Quotient::JoinState oldState,
862 Quotient::JoinState newState);
865 void typingChanged();
867 void highlightCountChanged();
868 void notificationCountChanged();
870 void displayedChanged(
bool displayed);
871 void firstDisplayedEventChanged();
872 void lastDisplayedEventChanged();
875 void lastReadEventChanged(QVector<QString> userIds);
876 void fullyReadMarkerMoved(QString fromEventId, QString toEventId);
877 void partiallyReadStatsChanged();
878 void unreadStatsChanged();
879 void allHistoryLoadedChanged();
881 void accountDataAboutToChange(QString type);
882 void accountDataChanged(QString type);
883 void tagsAboutToChange();
886 void updatedEvent(QString eventId);
887 void replacedEvent(
const Quotient::RoomEvent* newEvent,
888 const Quotient::RoomEvent* oldEvent);
890 void newFileTransfer(QString id, QUrl localFile);
891 void fileTransferProgress(QString id, qint64 progress, qint64 total);
892 void fileTransferCompleted(QString id, QUrl localFile,
893 FileSourceInfo fileMetadata);
894 void fileTransferFailed(QString id, QString errorMessage = {});
898 void callEvent(Quotient::Room* room,
const Quotient::RoomEvent* event);
901 void stabilityUpdated(QString recommendedDefault,
902 QStringList stableVersions);
904 void upgraded(QString serverMessage, Quotient::Room* successor);
906 void upgradeFailed(QString errorMessage);
909 void beforeDestruction(Quotient::Room*);
912 virtual Changes processStateEvent(
const RoomEvent& e);
913 virtual Changes processEphemeralEvent(EventPtr&& event);
914 virtual Changes processAccountDataEvent(EventPtr&& event);
915 virtual void onAddNewTimelineEvents(timeline_iter_t ) {}
916 virtual void onAddHistoricalTimelineEvents(rev_iter_t ) {}
917 virtual void onRedaction(
const RoomEvent& ,
920 virtual QJsonObject toJson()
const;
921 virtual void updateData(SyncRoomData&& data,
bool fromCache =
false);
922 virtual Notification checkForNotifications(
const TimelineItem& ti);
925 friend class Connection;
933 void setJoinState(JoinState state);
936 template <
template <
class>
class ContT>
937 inline typename ContT<RoomMember>::size_type lowerBoundMemberIndex(
const ContT<RoomMember>& c,
939 MemberSorter ms = {})
941 return std::ranges::lower_bound(c, v, ms) - c.begin();
944 template <
template <
class>
class ContT>
945 inline typename ContT<QString>::size_type lowerBoundMemberIndex(
const ContT<QString>& c,
946 const auto& v,
const Room* r,
947 MemberSorter ms = {})
949 return std::ranges::lower_bound(c, v, ms, std::bind_front(&Room::member, r)) - c.begin();
953 Q_DECLARE_METATYPE(Quotient::FileTransferInfo)
954 Q_DECLARE_METATYPE(Quotient::ReadReceipt)
955 Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::Room::Changes)