aboutsummaryrefslogtreecommitdiff
path: root/lib/room.h
diff options
context:
space:
mode:
authorHubert Chathi <uhoreg@debian.org>2019-06-25 16:33:24 -0400
committerHubert Chathi <uhoreg@debian.org>2019-06-25 16:33:24 -0400
commit72d5660efd0755bb53a8699cd39865155400d288 (patch)
treeed7e7537e6a3eb7e8b92226c4015f9bfc8e11c5a /lib/room.h
parent52407a933bfe1fcc5f3aa1dccaa0b9a8279aa634 (diff)
parent681203f951d13e9e8eaf772435cac28c6d74cd42 (diff)
downloadlibquotient-72d5660efd0755bb53a8699cd39865155400d288.tar.gz
libquotient-72d5660efd0755bb53a8699cd39865155400d288.zip
Merge branch 'upstream' (v0.5.2)
Diffstat (limited to 'lib/room.h')
-rw-r--r--lib/room.h208
1 files changed, 185 insertions, 23 deletions
diff --git a/lib/room.h b/lib/room.h
index a9ed9647..33d1f4ea 100644
--- a/lib/room.h
+++ b/lib/room.h
@@ -18,7 +18,7 @@
#pragma once
-#include "jobs/syncjob.h"
+#include "csapi/message_pagination.h"
#include "events/roommessageevent.h"
#include "events/accountdataevents.h"
#include "eventitem.h"
@@ -33,6 +33,8 @@
namespace QMatrixClient
{
class Event;
+ class Avatar;
+ class SyncRoomData;
class RoomMemberEvent;
class Connection;
class User;
@@ -41,10 +43,17 @@ namespace QMatrixClient
class SetRoomStateWithKeyJob;
class RedactEventJob;
+ /** The data structure used to expose file transfer information to views
+ *
+ * This is specifically tuned to work with QML exposing all traits as
+ * Q_PROPERTY values.
+ */
class FileTransferInfo
{
Q_GADGET
+ Q_PROPERTY(bool isUpload MEMBER isUpload CONSTANT)
Q_PROPERTY(bool active READ active CONSTANT)
+ Q_PROPERTY(bool started READ started CONSTANT)
Q_PROPERTY(bool completed READ completed CONSTANT)
Q_PROPERTY(bool failed READ failed CONSTANT)
Q_PROPERTY(int progress MEMBER progress CONSTANT)
@@ -52,16 +61,17 @@ namespace QMatrixClient
Q_PROPERTY(QUrl localDir MEMBER localDir CONSTANT)
Q_PROPERTY(QUrl localPath MEMBER localPath CONSTANT)
public:
- enum Status { None, Started, Completed, Failed };
+ enum Status { None, Started, Completed, Failed, Cancelled };
Status status = None;
+ bool isUpload = false;
int progress = 0;
int total = -1;
QUrl localDir { };
QUrl localPath { };
- bool active() const
- { return status == Started || status == Completed; }
+ bool started() const { return status == Started; }
bool completed() const { return status == Completed; }
+ bool active() const { return started() || completed(); }
bool failed() const { return status == Failed; }
};
@@ -71,10 +81,14 @@ namespace QMatrixClient
Q_PROPERTY(Connection* connection READ connection CONSTANT)
Q_PROPERTY(User* localUser READ localUser CONSTANT)
Q_PROPERTY(QString id READ id CONSTANT)
+ Q_PROPERTY(QString version READ version NOTIFY baseStateLoaded)
+ Q_PROPERTY(bool isUnstable READ isUnstable NOTIFY stabilityUpdated)
+ Q_PROPERTY(QString predecessorId READ predecessorId NOTIFY baseStateLoaded)
+ Q_PROPERTY(QString successorId READ successorId NOTIFY upgraded)
Q_PROPERTY(QString name READ name NOTIFY namesChanged)
Q_PROPERTY(QStringList aliases READ aliases NOTIFY namesChanged)
Q_PROPERTY(QString canonicalAlias READ canonicalAlias NOTIFY namesChanged)
- Q_PROPERTY(QString displayName READ displayName NOTIFY namesChanged)
+ Q_PROPERTY(QString displayName READ displayName NOTIFY displaynameChanged)
Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged STORED false)
Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
@@ -83,6 +97,9 @@ namespace QMatrixClient
Q_PROPERTY(int timelineSize READ timelineSize NOTIFY addedMessages)
Q_PROPERTY(QStringList memberNames READ memberNames NOTIFY memberListChanged)
Q_PROPERTY(int memberCount READ memberCount NOTIFY memberListChanged)
+ Q_PROPERTY(int joinedCount READ joinedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int invitedCount READ invitedCount NOTIFY memberListChanged)
+ Q_PROPERTY(int totalMemberCount READ totalMemberCount NOTIFY memberListChanged)
Q_PROPERTY(bool displayed READ displayed WRITE setDisplayed NOTIFY displayedChanged)
Q_PROPERTY(QString firstDisplayedEventId READ firstDisplayedEventId WRITE setFirstDisplayedEventId NOTIFY firstDisplayedEventChanged)
@@ -95,12 +112,34 @@ namespace QMatrixClient
Q_PROPERTY(bool isFavourite READ isFavourite NOTIFY tagsChanged)
Q_PROPERTY(bool isLowPriority READ isLowPriority NOTIFY tagsChanged)
+ Q_PROPERTY(GetRoomEventsJob* eventsHistoryJob READ eventsHistoryJob NOTIFY eventsHistoryJobChanged)
+
public:
using Timeline = std::deque<TimelineItem>;
using PendingEvents = std::vector<PendingEventItem>;
using rev_iter_t = Timeline::const_reverse_iterator;
using timeline_iter_t = Timeline::const_iterator;
+ enum Change : uint {
+ NoChange = 0x0,
+ NameChange = 0x1,
+ CanonicalAliasChange = 0x2,
+ TopicChange = 0x4,
+ UnreadNotifsChange = 0x8,
+ AvatarChange = 0x10,
+ JoinStateChange = 0x20,
+ TagsChange = 0x40,
+ MembersChange = 0x80,
+ /* = 0x100, */
+ AccountDataChange = 0x200,
+ SummaryChange = 0x400,
+ ReadMarkerChange = 0x800,
+ OtherChange = 0x8000,
+ AnyChange = 0xFFFF
+ };
+ Q_DECLARE_FLAGS(Changes, Change)
+ Q_FLAG(Changes)
+
Room(Connection* connection, QString id, JoinState initialJoinState);
~Room() override;
@@ -109,6 +148,10 @@ namespace QMatrixClient
Connection* connection() const;
User* localUser() const;
const QString& id() const;
+ QString version() const;
+ bool isUnstable() const;
+ QString predecessorId() const;
+ QString successorId() const;
QString name() const;
QStringList aliases() const;
QString canonicalAlias() const;
@@ -116,15 +159,22 @@ namespace QMatrixClient
QString topic() const;
QString avatarMediaId() const;
QUrl avatarUrl() const;
+ const Avatar& avatarObject() const;
Q_INVOKABLE JoinState joinState() const;
Q_INVOKABLE QList<User*> usersTyping() const;
QList<User*> membersLeft() const;
Q_INVOKABLE QList<User*> users() const;
QStringList memberNames() const;
+ [[deprecated("Use joinedCount(), invitedCount(), totalMemberCount()")]]
int memberCount() const;
int timelineSize() const;
bool usesEncryption() const;
+ int joinedCount() const;
+ int invitedCount() const;
+ int totalMemberCount() const;
+
+ GetRoomEventsJob* eventsHistoryJob() const;
/**
* Returns a square room avatar with the given size and requests it
@@ -177,9 +227,16 @@ namespace QMatrixClient
const Timeline& messageEvents() const;
const PendingEvents& pendingEvents() const;
/**
- * A convenience method returning the read marker to
- * the before-oldest message
+ * A convenience method returning the read marker to the position
+ * before the "oldest" event; same as messageEvents().crend()
*/
+ rev_iter_t historyEdge() const;
+ /**
+ * A convenience method returning the iterator beyond the latest
+ * arrived event; same as messageEvents().cend()
+ */
+ Timeline::const_iterator syncEdge() const;
+ /// \deprecated Use historyEdge instead
rev_iter_t timelineEdge() const;
Q_INVOKABLE TimelineItem::index_t minTimelineIndex() const;
Q_INVOKABLE TimelineItem::index_t maxTimelineIndex() const;
@@ -187,8 +244,17 @@ namespace QMatrixClient
rev_iter_t findInTimeline(TimelineItem::index_t index) const;
rev_iter_t findInTimeline(const QString& evtId) const;
+ PendingEvents::iterator findPendingEvent(const QString & txnId);
+ PendingEvents::const_iterator findPendingEvent(const QString & txnId) const;
bool displayed() const;
+ /// Mark the room as currently displayed to the user
+ /**
+ * Marking the room displayed causes the room to obtain the full
+ * list of members if it's been lazy-loaded before; in the future
+ * it may do more things bound to "screen time" of the room, e.g.
+ * measure that "screen time".
+ */
void setDisplayed(bool displayed = true);
QString firstDisplayedEventId() const;
rev_iter_t firstDisplayedMarker() const;
@@ -288,11 +354,32 @@ namespace QMatrixClient
/// Get the list of users this room is a direct chat with
QList<User*> directChatUsers() const;
- Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId);
- Q_INVOKABLE QUrl urlToDownload(const QString& eventId);
- Q_INVOKABLE QString fileNameToDownload(const QString& eventId);
+ Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId) const;
+ Q_INVOKABLE QUrl urlToDownload(const QString& eventId) const;
+
+ /// Get a file name for downloading for a given event id
+ /*!
+ * The event MUST be RoomMessageEvent and have content
+ * for downloading. \sa RoomMessageEvent::hasContent
+ */
+ Q_INVOKABLE QString fileNameToDownload(const QString& eventId) const;
+
+ /// Get information on file upload/download
+ /*!
+ * \param id uploads are identified by the corresponding event's
+ * transactionId (because uploads are done before
+ * the event is even sent), while downloads are using
+ * the normal event id for identifier.
+ */
Q_INVOKABLE FileTransferInfo fileTransferInfo(const QString& id) const;
+ /// Get the URL to the actual file source in a unified way
+ /*!
+ * For uploads it will return a URL to a local file; for downloads
+ * the URL will be taken from the corresponding room event.
+ */
+ Q_INVOKABLE QUrl fileSource(const QString& id) const;
+
/** Pretty-prints plain text into HTML
* As of now, it's exactly the same as QMatrixClient::prettyPrint();
* in the future, it will also linkify room aliases, mxids etc.
@@ -314,11 +401,17 @@ namespace QMatrixClient
Q_INVOKABLE bool supportsCalls() const;
public slots:
+ /** Check whether the room should be upgraded */
+ void checkVersion();
+
QString postMessage(const QString& plainText, MessageEventType type);
QString postPlainText(const QString& plainText);
QString postHtmlMessage(const QString& plainText,
- const QString& html, MessageEventType type);
+ const QString& html,
+ MessageEventType type = MessageEventType::Text);
QString postHtmlText(const QString& plainText, const QString& html);
+ QString postFile(const QString& plainText, const QUrl& localPath,
+ bool asGenericFile = false);
/** Post a pre-created room message event
*
* Takes ownership of the event, deleting it once the matching one
@@ -332,8 +425,12 @@ namespace QMatrixClient
void discardMessage(const QString& txnId);
void setName(const QString& newName);
void setCanonicalAlias(const QString& newAlias);
+ void setAliases(const QStringList& aliases);
void setTopic(const QString& newTopic);
+ /// You shouldn't normally call this method; it's here for debugging
+ void refreshDisplayName();
+
void getPreviousContent(int limit = 10);
void inviteToRoom(const QString& memberId);
@@ -356,19 +453,63 @@ namespace QMatrixClient
/// Mark all messages in the room as read
void markAllMessagesAsRead();
+ /// Whether the current user is allowed to upgrade the room
+ bool canSwitchVersions() const;
+
+ /// Switch the room's version (aka upgrade)
+ void switchVersion(QString newVersion);
+
signals:
+ /// Initial set of state events has been loaded
+ /**
+ * The initial set is what comes from the initial sync for the room.
+ * This includes all basic things like RoomCreateEvent,
+ * RoomNameEvent, a (lazy-loaded, not full) set of RoomMemberEvents
+ * etc. This is a per-room reflection of Connection::loadedRoomState
+ * \sa Connection::loadedRoomState
+ */
+ void baseStateLoaded();
+ void eventsHistoryJobChanged();
void aboutToAddHistoricalMessages(RoomEventsRange events);
void aboutToAddNewMessages(RoomEventsRange events);
void addedMessages(int fromIndex, int toIndex);
- void pendingEventAboutToAdd();
+ /// The event is about to be appended to the list of pending events
+ void pendingEventAboutToAdd(RoomEvent* event);
+ /// An event has been appended to the list of pending events
void pendingEventAdded();
+ /// The remote echo has arrived with the sync and will be merged
+ /// with its local counterpart
+ /** NB: Requires a sync loop to be emitted */
void pendingEventAboutToMerge(RoomEvent* serverEvent,
int pendingEventIndex);
+ /// The remote and local copies of the event have been merged
+ /** NB: Requires a sync loop to be emitted */
void pendingEventMerged();
+ /// An event will be removed from the list of pending events
void pendingEventAboutToDiscard(int pendingEventIndex);
+ /// An event has just been removed from the list of pending events
void pendingEventDiscarded();
+ /// The status of a pending event has changed
+ /** \sa PendingEventItem::deliveryStatus */
void pendingEventChanged(int pendingEventIndex);
+ /// The server accepted the message
+ /** This is emitted when an event sending request has successfully
+ * completed. This does not mean that the event is already in the
+ * local timeline, only that the server has accepted it.
+ * \param txnId transaction id assigned by the client during sending
+ * \param eventId event id assigned by the server upon acceptance
+ * \sa postEvent, postPlainText, postMessage, postHtmlMessage
+ * \sa pendingEventMerged, aboutToAddNewMessages
+ */
+ void messageSent(QString txnId, QString eventId);
+ /** A common signal for various kinds of changes in the room
+ * Aside from all changes in the room state
+ * @param changes a set of flags describing what changes occured
+ * upon the last sync
+ * \sa StateChange
+ */
+ void changed(Changes changes);
/**
* \brief The room name, the canonical alias or other aliases changed
*
@@ -383,7 +524,17 @@ namespace QMatrixClient
void userRemoved(User* user);
void memberAboutToRename(User* user, QString newName);
void memberRenamed(User* user);
+ /// The list of members has changed
+ /** Emitted no more than once per sync, this is a good signal to
+ * for cases when some action should be done upon any change in
+ * the member list. If you need per-item granularity you should use
+ * userAdded, userRemoved and memberAboutToRename / memberRenamed
+ * instead.
+ */
void memberListChanged();
+ /// The previously lazy-loaded members list is now loaded entirely
+ /// \sa setDisplayed
+ void allMembersLoaded();
void encryption();
void joinStateChanged(JoinState oldState, JoinState newState);
@@ -415,30 +566,40 @@ namespace QMatrixClient
void fileTransferCancelled(QString id);
void callEvent(Room* room, const RoomEvent* event);
- /// The room is about to be deleted
- void beforeDestruction(Room*);
- public: // Used by Connection - not a part of the client API
- QJsonObject toJson() const;
- void updateData(SyncRoomData&& data );
+ /// The room's version stability may have changed
+ void stabilityUpdated(QString recommendedDefault,
+ QStringList stableVersions);
+ /// This room has been upgraded and won't receive updates anymore
+ void upgraded(QString serverMessage, Room* successor);
+ /// An attempted room upgrade has failed
+ void upgradeFailed(QString errorMessage);
- // Clients should use Connection::joinRoom() and Room::leaveRoom()
- // to change the room state
- void setJoinState( JoinState state );
+ /// The room is about to be deleted
+ void beforeDestruction(Room*);
protected:
/// Returns true if any of room names/aliases has changed
- virtual bool processStateEvent(const RoomEvent& e);
- virtual void processEphemeralEvent(EventPtr&& event);
- virtual void processAccountDataEvent(EventPtr&& event);
+ virtual Changes processStateEvent(const RoomEvent& e);
+ virtual Changes processEphemeralEvent(EventPtr&& event);
+ virtual Changes processAccountDataEvent(EventPtr&& event);
virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) { }
virtual void onAddHistoricalTimelineEvents(rev_iter_t /*from*/) { }
virtual void onRedaction(const RoomEvent& /*prevEvent*/,
const RoomEvent& /*after*/) { }
+ virtual QJsonObject toJson() const;
+ virtual void updateData(SyncRoomData&& data, bool fromCache = false);
private:
+ friend class Connection;
+
class Private;
Private* d;
+
+ // This is called from Connection, reflecting a state change that
+ // arrived from the server. Clients should use
+ // Connection::joinRoom() and Room::leaveRoom() to change the state.
+ void setJoinState(JoinState state);
};
class MemberSorter
@@ -461,3 +622,4 @@ namespace QMatrixClient
};
} // namespace QMatrixClient
Q_DECLARE_METATYPE(QMatrixClient::FileTransferInfo)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMatrixClient::Room::Changes)