18 #include "csapi/message_pagination.h"
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"
29 #include <QtCore/QJsonObject>
30 #include <QtGui/QImage>
39 class RoomMemberEvent;
44 class SetRoomStateWithKeyJob;
54 Q_PROPERTY(
bool isUpload MEMBER isUpload CONSTANT)
55 Q_PROPERTY(
bool active READ active CONSTANT)
56 Q_PROPERTY(
bool started READ started CONSTANT)
57 Q_PROPERTY(
bool completed READ completed CONSTANT)
58 Q_PROPERTY(
bool failed READ failed CONSTANT)
59 Q_PROPERTY(
int progress MEMBER progress CONSTANT)
60 Q_PROPERTY(
int total MEMBER total CONSTANT)
61 Q_PROPERTY(QUrl localDir MEMBER localDir CONSTANT)
62 Q_PROPERTY(QUrl localPath MEMBER localPath CONSTANT)
64 enum Status { None, Started, Completed, Failed, Cancelled };
66 bool isUpload =
false;
72 bool started()
const {
return status == Started; }
73 bool completed()
const {
return status == Completed; }
74 bool active()
const {
return started() || completed(); }
75 bool failed()
const {
return status == Failed; }
82 Q_PROPERTY(QString eventId MEMBER eventId CONSTANT)
83 Q_PROPERTY(QDateTime timestamp MEMBER timestamp CONSTANT)
86 QDateTime timestamp = {};
88 bool operator==(
const ReadReceipt& other)
const
90 return eventId == other.eventId && timestamp == other.timestamp;
92 bool operator!=(
const ReadReceipt& other)
const
94 return !operator==(other);
97 inline void swap(ReadReceipt& lhs, ReadReceipt& rhs)
99 swap(lhs.eventId, rhs.eventId);
100 swap(lhs.timestamp, rhs.timestamp);
107 enum Type { None = 0, Basic, Highlight };
114 Q_PROPERTY(Type type MEMBER type CONSTANT)
119 Q_PROPERTY(Connection* connection READ connection CONSTANT)
120 Q_PROPERTY(RoomMember localMember READ localMember CONSTANT)
121 Q_PROPERTY(QString id READ id CONSTANT)
122 Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded)
123 Q_PROPERTY(
bool isUnstable READ isUnstable NOTIFY stabilityUpdated)
124 Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
125 Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
126 Q_PROPERTY(QString name READ name NOTIFY namesChanged)
127 Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
128 Q_PROPERTY(QStringList altAliases READ altAliases NOTIFY namesChanged)
129 Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
130 Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
131 Q_PROPERTY(QStringList pinnedEventIds READ pinnedEventIds WRITE setPinnedEvents
132 NOTIFY pinnedEventsChanged)
133 Q_PROPERTY(QString displayNameForHtml READ displayNameForHtml NOTIFY displaynameChanged)
134 Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
135 Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
137 Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
138 Q_PROPERTY(
bool usesEncryption READ usesEncryption NOTIFY encryption)
140 Q_PROPERTY(
int timelineSize READ timelineSize NOTIFY addedMessages)
141 Q_PROPERTY(
int joinedCount READ joinedCount NOTIFY memberListChanged)
142 Q_PROPERTY(
int invitedCount READ invitedCount NOTIFY memberListChanged)
143 Q_PROPERTY(
int totalMemberCount READ totalMemberCount NOTIFY memberListChanged)
144 Q_PROPERTY(QList<RoomMember> membersTyping READ membersTyping NOTIFY typingChanged)
145 Q_PROPERTY(QList<RoomMember> otherMembersTyping READ otherMembersTyping NOTIFY typingChanged)
146 Q_PROPERTY(
int localMemberEffectivePowerLevel READ memberEffectivePowerLevel NOTIFY changed)
148 Q_PROPERTY(
bool displayed READ displayed WRITE setDisplayed NOTIFY
150 Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId WRITE
151 setFirstDisplayedEventId NOTIFY firstDisplayedEventChanged)
152 Q_PROPERTY(QString lastDisplayedEventId READ lastDisplayedEventId WRITE
153 setLastDisplayedEventId NOTIFY lastDisplayedEventChanged)
154 Q_PROPERTY(QString lastFullyReadEventId READ lastFullyReadEventId WRITE
155 markMessagesAsRead NOTIFY fullyReadMarkerMoved)
156 Q_PROPERTY(qsizetype highlightCount READ highlightCount
157 NOTIFY highlightCountChanged)
158 Q_PROPERTY(qsizetype notificationCount READ notificationCount
159 NOTIFY notificationCountChanged)
160 Q_PROPERTY(EventStats partiallyReadStats READ partiallyReadStats NOTIFY partiallyReadStatsChanged)
161 Q_PROPERTY(EventStats unreadStats READ unreadStats NOTIFY unreadStatsChanged)
162 Q_PROPERTY(
bool allHistoryLoaded READ allHistoryLoaded NOTIFY allHistoryLoadedChanged
164 Q_PROPERTY(QStringList tagNames READ tagNames NOTIFY tagsChanged)
165 Q_PROPERTY(
bool isFavourite READ isFavourite NOTIFY tagsChanged STORED
false)
166 Q_PROPERTY(
bool isLowPriority READ isLowPriority NOTIFY tagsChanged STORED
false)
168 Q_PROPERTY(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob NOTIFY eventsHistoryJobChanged)
169 Q_PROPERTY(
int requestedHistorySize READ requestedHistorySize NOTIFY eventsHistoryJobChanged)
171 Q_PROPERTY(QStringList accountDataEventTypes READ accountDataEventTypes NOTIFY accountDataChanged)
174 using Timeline = std::deque<TimelineItem>;
175 using PendingEvents = std::vector<PendingEventItem>;
176 using RelatedEvents = QVector<
const RoomEvent*>;
177 using rev_iter_t = Timeline::const_reverse_iterator;
178 using timeline_iter_t = Timeline::const_iterator;
186 enum class Change : quint32 {
191 PartiallyReadStats = 0x8,
218 Room(Connection* connection, QString id, JoinState initialJoinState);
219 Q_DISABLE_COPY_MOVE(Room)
224 Connection* connection()
const;
227 RoomMember localMember()
const;
228 const QString& id()
const;
229 QString version()
const;
230 bool isUnstable()
const;
231 QString predecessorId()
const;
238 Room* predecessor(JoinStates statesFilter = JoinState::Invite
239 | JoinState::Join)
const;
240 QString successorId()
const;
246 Room* successor(JoinStates statesFilter = JoinState::Invite
247 | JoinState::Join)
const;
248 QString name()
const;
249 QString canonicalAlias()
const;
250 QStringList altAliases()
const;
252 QStringList aliases()
const;
253 QString displayName()
const;
254 QStringList pinnedEventIds()
const;
256 QVector<
const RoomEvent*> pinnedEvents()
const;
257 QString displayNameForHtml()
const;
258 QString topic()
const;
259 QString avatarMediaId()
const;
260 QUrl avatarUrl()
const;
261 const Avatar& avatarObject()
const;
262 Q_INVOKABLE JoinState joinState()
const;
264 int timelineSize()
const;
265 bool usesEncryption()
const;
266 RoomEventPtr decryptMessage(
const EncryptedEvent& encryptedEvent);
267 void handleRoomKeyEvent(
const RoomKeyEvent& roomKeyEvent,
268 const QString& senderId,
269 const QByteArray& olmSessionId,
270 const QByteArray& senderKey,
271 const QByteArray& senderEdKey);
272 int joinedCount()
const;
273 int invitedCount()
const;
274 int totalMemberCount()
const;
276 GetRoomEventsJob* eventsHistoryJob()
const;
284 Q_INVOKABLE QImage avatar(
int dimension);
291 Q_INVOKABLE QImage avatar(
int width,
int height);
300 Q_INVOKABLE RoomMember member(
const QString& userId)
const;
303 QList<RoomMember> joinedMembers()
const;
306 QList<RoomMember> members()
const;
309 QList<RoomMember> membersLeft()
const;
312 QList<RoomMember> membersTyping()
const;
317 QList<RoomMember> otherMembersTyping()
const;
320 QStringList joinedMemberIds()
const;
323 QStringList memberIds()
const;
326 bool needsDisambiguation(
const QString& userId)
const;
331 Q_INVOKABLE Quotient::Membership memberState(
const QString& userId)
const;
334 Q_INVOKABLE
bool isMember(
const QString& userId)
const;
336 const Avatar& memberAvatarObject(
const QString& memberId)
const;
343 Q_INVOKABLE QImage memberAvatar(
const QString& memberId,
int width,
int height);
348 Q_INVOKABLE QImage memberAvatar(
const QString& memberId,
int dimension);
350 const Timeline& messageEvents()
const;
351 const PendingEvents& pendingEvents()
const;
355 int requestedHistorySize()
const;
360 bool allHistoryLoaded()
const;
365 rev_iter_t historyEdge()
const;
369 Timeline::const_iterator syncEdge()
const;
370 Q_INVOKABLE Quotient::TimelineItem::index_t minTimelineIndex()
const;
371 Q_INVOKABLE Quotient::TimelineItem::index_t maxTimelineIndex()
const;
372 Q_INVOKABLE
bool isValidIndex(Quotient::TimelineItem::index_t timelineIndex)
const;
374 rev_iter_t findInTimeline(TimelineItem::index_t index)
const;
375 rev_iter_t findInTimeline(
const QString& evtId)
const;
376 PendingEvents::iterator findPendingEvent(
const QString& txnId);
377 PendingEvents::const_iterator findPendingEvent(
const QString& txnId)
const;
379 const RelatedEvents relatedEvents(
const QString& evtId,
380 EventRelation::reltypeid_t relType)
const;
381 const RelatedEvents relatedEvents(
const RoomEvent& evt,
382 EventRelation::reltypeid_t relType)
const;
384 const RoomCreateEvent* creation()
const;
385 const RoomTombstoneEvent* tombstone()
const;
387 bool displayed()
const;
395 void setDisplayed(
bool displayed =
true);
396 QString firstDisplayedEventId()
const;
397 rev_iter_t firstDisplayedMarker()
const;
398 void setFirstDisplayedEventId(
const QString& eventId);
399 void setFirstDisplayedEvent(TimelineItem::index_t index);
400 QString lastDisplayedEventId()
const;
401 rev_iter_t lastDisplayedMarker()
const;
402 void setLastDisplayedEventId(
const QString& eventId);
403 void setLastDisplayedEvent(TimelineItem::index_t index);
411 ReadReceipt lastReadReceipt(
const QString& userId)
const;
417 ReadReceipt lastLocalReadReceipt()
const;
424 rev_iter_t localReadReceiptMarker()
const;
433 QString lastFullyReadEventId()
const;
444 rev_iter_t fullyReadMarker()
const;
458 QSet<QString> userIdsAtEvent(
const QString& eventId)
const;
470 Q_INVOKABLE
void markMessagesAsRead(
const QString& uptoEventId);
488 virtual bool isEventNotable(
const TimelineItem& ti)
const;
494 Notification notificationFor(
const TimelineItem& ti)
const;
517 EventStats partiallyReadStats()
const;
537 EventStats unreadStats()
const;
544 qsizetype notificationCount()
const;
552 qsizetype highlightCount()
const;
557 bool hasAccountData(
const QString& type)
const;
564 const EventPtr& accountData(
const QString& type)
const;
568 QStringList accountDataEventTypes()
const;
570 QStringList tagNames()
const;
571 TagsMap tags()
const;
572 Tag tag(
const QString& name)
const;
580 void addTag(
const QString& name,
const Tag& tagData = {});
581 Q_INVOKABLE
void addTag(
const QString& name,
float order);
584 Q_INVOKABLE
void removeTag(
const QString& name);
610 void setTags(TagsMap newTags, ActionScope applyOn = ThisRoomOnly);
613 bool isFavourite()
const;
615 bool isLowPriority()
const;
617 bool isServerNoticeRoom()
const;
620 Q_INVOKABLE
bool isDirectChat()
const;
623 QList<RoomMember> directChatMembers()
const;
625 Q_INVOKABLE QUrl makeMediaUrl(
const QString& eventId,
626 const QUrl &mxcUrl)
const;
628 Q_INVOKABLE QUrl urlToThumbnail(
const QString& eventId)
const;
629 Q_INVOKABLE QUrl urlToDownload(
const QString& eventId)
const;
636 Q_INVOKABLE QString fileNameToDownload(
const QString& eventId)
const;
645 Q_INVOKABLE Quotient::FileTransferInfo
646 fileTransferInfo(
const QString& id)
const;
653 Q_INVOKABLE QUrl fileSource(
const QString& id)
const;
660 Q_INVOKABLE QString prettyPrint(
const QString& plainText)
const;
662 #if Quotient_VERSION_MAJOR == 0
&& Quotient_VERSION_MINOR < 10
663 [[deprecated(
"Create MemberSorter objects directly instead")]]
664 MemberSorter memberSorter()
const;
667 Q_INVOKABLE
bool supportsCalls()
const;
670 Q_INVOKABLE
bool canSwitchVersions()
const;
673 RoomStateView currentState()
const;
682 Q_INVOKABLE
int memberEffectivePowerLevel(
const QString& memberId = {})
const;
696 Q_INVOKABLE
int powerLevelFor(
const QString& eventTypeId,
bool forceStateEvent =
false)
const;
703 template <EventClass EvT>
704 int powerLevelFor()
const
706 return currentState().get<RoomPowerLevelsEvent>()->powerLevelForEventType<EvT>();
716 const PendingEventItem& post(RoomEventPtr event);
718 template <
typename EvT,
typename... ArgTs>
719 const PendingEventItem& post(ArgTs&&... args)
721 return post(makeEvent<EvT>(std::forward<ArgTs>(args)...));
724 QString postFile(
const QString& plainText,
725 std::unique_ptr<EventContent::FileContentBase> fileContent);
727 PendingEventItem::future_type whenMessageMerged(QString txnId)
const;
730 SetRoomStateWithKeyJob* setState(
const StateEvent& evt);
736 template <
typename EvT,
typename... ArgTs>
737 auto setState(ArgTs&&... args)
739 return setState(EvT(std::forward<ArgTs>(args)...));
742 void addMegolmSessionFromBackup(
const QByteArray &sessionId,
const QByteArray &sessionKey, uint32_t index,
const QByteArray& senderKey,
const QByteArray& senderEdKey);
744 Q_INVOKABLE
void startVerification();
746 QJsonArray exportMegolmSessions();
752 QString postMessage(
const QString& plainText, MessageEventType type);
753 QString postPlainText(
const QString& plainText);
754 QString postHtmlMessage(
const QString& plainText,
const QString& html,
755 MessageEventType type = MessageEventType::Text);
756 QString postHtmlText(
const QString& plainText,
const QString& html);
758 QString postReaction(
const QString& eventId,
const QString& key);
766 [[deprecated(
"Use post() instead")]]
767 QString postEvent(RoomEvent* event);
768 QString postJson(
const QString& matrixType,
const QJsonObject& eventContent);
769 QString retryMessage(
const QString& txnId);
770 void discardMessage(
const QString& txnId);
773 SetRoomStateWithKeyJob* setState(
const QString& evtType,
774 const QString& stateKey,
775 const QJsonObject& contentJson);
776 void setName(
const QString& newName);
777 void setCanonicalAlias(
const QString& newAlias);
778 void setPinnedEvents(
const QStringList& events);
780 void setLocalAliases(
const QStringList& aliases);
781 void setTopic(
const QString& newTopic);
784 void refreshDisplayName();
786 JobHandle<GetRoomEventsJob> getPreviousContent(
int limit = 10,
const QString &filter = {});
788 void inviteToRoom(
const QString& memberId);
789 JobHandle<LeaveRoomJob> leaveRoom();
790 void kickMember(
const QString& memberId,
const QString& reason = {});
791 void ban(
const QString& userId,
const QString& reason = {});
792 void unban(
const QString& userId);
793 void redactEvent(
const QString& eventId,
const QString& reason = {});
795 void uploadFile(
const QString& id,
const QUrl& localFilename,
796 const QString& overrideContentType = {});
798 void downloadFile(
const QString& eventId,
const QUrl& localFilename = {});
799 void cancelFileTransfer(
const QString& id);
805 void setReadReceipt(
const QString& atEventId);
807 void markAllMessagesAsRead();
810 void switchVersion(QString newVersion);
812 void inviteCall(
const QString& callId,
const int lifetime,
814 void sendCallCandidates(
const QString& callId,
const QJsonArray& candidates);
815 void answerCall(
const QString& callId,
const QString& sdp);
816 void hangupCall(
const QString& callId);
822 void activateEncryption();
833 void baseStateLoaded();
834 void eventsHistoryJobChanged();
835 void aboutToAddHistoricalMessages(Quotient::RoomEventsRange events);
836 void aboutToAddNewMessages(Quotient::RoomEventsRange events);
837 void addedMessages(
int fromIndex,
int toIndex);
839 void pendingEventAboutToAdd(Quotient::RoomEvent* event);
841 void pendingEventAdded(
const Quotient::RoomEvent* event);
845 void pendingEventAboutToMerge(Quotient::RoomEvent* serverEvent,
846 int pendingEventIndex);
849 void pendingEventMerged();
851 void pendingEventAboutToDiscard(
int pendingEventIndex);
853 void pendingEventDiscarded();
856 void pendingEventChanged(
int pendingEventIndex);
866 void messageSent(QString txnId, QString eventId);
874 void changed(Quotient::Room::Changes changes);
880 void namesChanged(Quotient::Room* room);
881 void displaynameAboutToChange(Quotient::Room* room);
882 void displaynameChanged(Quotient::Room* room, QString oldName);
883 void pinnedEventsChanged();
885 void avatarChanged();
891 void memberJoined(RoomMember member);
897 void memberLeft(RoomMember member);
900 void memberNameAboutToUpdate(RoomMember member, QString newName);
903 void memberNameUpdated(RoomMember member);
906 void memberAvatarUpdated(RoomMember member);
915 void memberListChanged();
919 void allMembersLoaded();
922 void joinStateChanged(Quotient::JoinState oldState,
923 Quotient::JoinState newState);
926 void typingChanged();
928 void highlightCountChanged();
929 void notificationCountChanged();
931 void displayedChanged(
bool displayed);
932 void firstDisplayedEventChanged();
933 void lastDisplayedEventChanged();
936 void lastReadEventChanged(QVector<QString> userIds);
937 void fullyReadMarkerMoved(QString fromEventId, QString toEventId);
938 void partiallyReadStatsChanged();
939 void unreadStatsChanged();
940 void allHistoryLoadedChanged();
942 void accountDataAboutToChange(QString type);
943 void accountDataChanged(QString type);
944 void tagsAboutToChange();
947 void updatedEvent(QString eventId);
948 void replacedEvent(
const Quotient::RoomEvent* newEvent,
949 const Quotient::RoomEvent* oldEvent);
951 void newFileTransfer(QString id, QUrl localFile);
952 void fileTransferProgress(QString id, qint64 progress, qint64 total);
953 void fileTransferCompleted(QString id, QUrl localFile,
954 FileSourceInfo fileMetadata);
955 void fileTransferFailed(QString id, QString errorMessage = {});
959 void callEvent(Quotient::Room* room,
const Quotient::RoomEvent* event);
962 void stabilityUpdated(QString recommendedDefault,
963 QStringList stableVersions);
965 void upgraded(QString serverMessage, Quotient::Room* successor);
967 void upgradeFailed(QString errorMessage);
970 void beforeDestruction(Quotient::Room*);
973 virtual Changes processStateEvent(
const RoomEvent& e);
974 virtual Changes processEphemeralEvent(EventPtr&& event);
975 virtual Changes processAccountDataEvent(EventPtr&& event);
976 virtual void onAddNewTimelineEvents(timeline_iter_t ) {}
977 virtual void onAddHistoricalTimelineEvents(rev_iter_t ) {}
978 virtual void onRedaction(
const RoomEvent& ,
981 virtual QJsonObject toJson()
const;
982 virtual void updateData(SyncRoomData&& data,
bool fromCache =
false);
983 virtual Notification checkForNotifications(
const TimelineItem& ti);
986 friend class Connection;
994 void setJoinState(JoinState state);
997 template <
template <
class>
class ContT>
998 inline typename ContT<RoomMember>::size_type lowerBoundMemberIndex(
const ContT<RoomMember>& c,
1000 MemberSorter ms = {})
1002 return std::ranges::lower_bound(c, v, ms) - c.begin();
1005 template <
template <
class>
class ContT>
1006 inline typename ContT<QString>::size_type lowerBoundMemberIndex(
const ContT<QString>& c,
1007 const auto& v,
const Room* r,
1008 MemberSorter ms = {})
1010 return std::ranges::lower_bound(c, v, ms, std::bind_front(&Room::member, r)) - c.begin();
1014 Q_DECLARE_METATYPE(Quotient::FileTransferInfo)
1015 Q_DECLARE_METATYPE(Quotient::ReadReceipt)
1016 Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::Room::Changes)