aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2018-02-26 09:07:16 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2018-02-26 09:07:16 +0900
commit91cc0e8db0006beeb91b9e007cd21343984dfb6a (patch)
tree7a79286d7c6e5a99644c3f7141e1cdc8e2459416
parente77a53946805649be99f8c0f6ee9c00702348132 (diff)
parentec412621d71b1a7758b15d2b3c5cd5e7b2081ab1 (diff)
downloadlibquotient-91cc0e8db0006beeb91b9e007cd21343984dfb6a.tar.gz
libquotient-91cc0e8db0006beeb91b9e007cd21343984dfb6a.zip
Merge branch 'kitsune-account-data'
-rw-r--r--CMakeLists.txt1
-rw-r--r--connection.cpp24
-rw-r--r--connection.h15
-rw-r--r--events/event.cpp8
-rw-r--r--events/event.h4
-rw-r--r--events/tagevent.cpp42
-rw-r--r--events/tagevent.h53
-rw-r--r--jobs/syncjob.cpp11
-rw-r--r--jobs/syncjob.h36
-rw-r--r--libqmatrixclient.pri3
-rw-r--r--room.cpp34
-rw-r--r--room.h9
12 files changed, 216 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index da5bac9b..709860e8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,6 +60,7 @@ set(libqmatrixclient_SRCS
events/roomavatarevent.cpp
events/typingevent.cpp
events/receiptevent.cpp
+ events/tagevent.cpp
jobs/requestdata.cpp
jobs/basejob.cpp
jobs/checkauthmethods.cpp
diff --git a/connection.cpp b/connection.cpp
index 4b7d4abb..52fcc40b 100644
--- a/connection.cpp
+++ b/connection.cpp
@@ -520,6 +520,30 @@ QHash< QPair<QString, bool>, Room* > Connection::roomMap() const
return roomMap;
}
+QHash<QString, QVector<Room*>> Connection::tagsToRooms() const
+{
+ QHash<QString, QVector<Room*>> result;
+ for (auto* r: d->roomMap)
+ {
+ for (const auto& tagName: r->tagNames())
+ result[tagName].push_back(r);
+ }
+ for (auto it = result.begin(); it != result.end(); ++it)
+ std::sort(it->begin(), it->end(),
+ [t=it.key()] (Room* r1, Room* r2) {
+ return r1->tags().value(t).order < r2->tags().value(t).order;
+ });
+ return result;
+}
+
+QVector<Room*> Connection::roomsWithTag(const QString& tagName) const
+{
+ QVector<Room*> rooms;
+ std::copy_if(d->roomMap.begin(), d->roomMap.end(), std::back_inserter(rooms),
+ [&tagName] (Room* r) { return r->tags().contains(tagName); });
+ return rooms;
+}
+
QMap<QString, User*> Connection::users() const
{
return d->userMap;
diff --git a/connection.h b/connection.h
index 3ec4fd9d..b45a171d 100644
--- a/connection.h
+++ b/connection.h
@@ -70,7 +70,22 @@ namespace QMatrixClient
explicit Connection(const QUrl& server, QObject* parent = nullptr);
virtual ~Connection();
+ /** Get all Invited and Joined rooms
+ * \return a hashmap from a composite key - room name and whether
+ * it's an Invite rather than Join - to room pointers
+ */
QHash<QPair<QString, bool>, Room*> roomMap() const;
+
+ /** Get all Invited and Joined rooms grouped by tag
+ * \return a hashmap from tag name to a vector of room pointers,
+ * sorted by their order in the tag - details are at
+ * https://matrix.org/speculator/spec/drafts%2Fe2e/client_server/unstable.html#id95
+ */
+ QHash<QString, QVector<Room*>> tagsToRooms() const;
+
+ /** Get the list of rooms with the specified tag */
+ QVector<Room*> roomsWithTag(const QString& tagName) const;
+
QMap<QString, User*> users() const;
// FIXME: Convert Q_INVOKABLEs to Q_PROPERTIES
diff --git a/events/event.cpp b/events/event.cpp
index 366aa858..b55c44c4 100644
--- a/events/event.cpp
+++ b/events/event.cpp
@@ -24,6 +24,7 @@
#include "roomavatarevent.h"
#include "typingevent.h"
#include "receiptevent.h"
+#include "tagevent.h"
#include "redactionevent.h"
#include "logging.h"
@@ -44,6 +45,11 @@ Event::Event(Type type, const QJsonObject& rep)
Event::~Event() = default;
+QString Event::jsonType() const
+{
+ return originalJsonObject().value("type").toString();
+}
+
QByteArray Event::originalJson() const
{
return QJsonDocument(_originalJson).toJson();
@@ -82,7 +88,7 @@ EventPtr _impl::doMakeEvent<Event>(const QJsonObject& obj)
return EventPtr(move(e));
return EventPtr { makeIfMatches<Event,
- TypingEvent, ReceiptEvent>(obj, obj["type"].toString()) };
+ TypingEvent, ReceiptEvent, TagEvent>(obj, obj["type"].toString()) };
}
RoomEvent::RoomEvent(Event::Type type) : Event(type) { }
diff --git a/events/event.h b/events/event.h
index 1a1b994d..4bd08b55 100644
--- a/events/event.h
+++ b/events/event.h
@@ -45,7 +45,7 @@ namespace QMatrixClient
enum class Type : quint16
{
Unknown = 0,
- Typing, Receipt,
+ Typing, Receipt, Tag, DirectChat,
RoomEventBase = 0x1000,
RoomMessage = RoomEventBase + 1,
RoomEncryptedMessage, Redaction,
@@ -63,6 +63,7 @@ namespace QMatrixClient
virtual ~Event();
Type type() const { return _type; }
+ QString jsonType() const;
bool isStateEvent() const
{
return (quint16(_type) & 0x1800) == 0x1800;
@@ -76,7 +77,6 @@ namespace QMatrixClient
// (and in most cases it will be a combination of other fields
// instead of "content" field).
- protected:
const QJsonObject contentJson() const;
private:
diff --git a/events/tagevent.cpp b/events/tagevent.cpp
new file mode 100644
index 00000000..9f381c76
--- /dev/null
+++ b/events/tagevent.cpp
@@ -0,0 +1,42 @@
+#include "tagevent.h"
+
+using namespace QMatrixClient;
+
+TagRecord::TagRecord(const QJsonObject& json)
+ : order(json.value("order").toString())
+{ }
+
+TagEvent::TagEvent(const QJsonObject& obj)
+ : Event(Type::Tag, obj)
+{
+ Q_ASSERT(obj["type"].toString() == TypeId);
+}
+
+QStringList TagEvent::tagNames() const
+{
+ return tagsObject().keys();
+}
+
+QHash<QString, TagRecord> TagEvent::tags() const
+{
+ QHash<QString, TagRecord> result;
+ auto allTags { tagsObject() };
+ for (auto it = allTags.begin(); it != allTags.end(); ++ it)
+ result.insert(it.key(), TagRecord(it.value().toObject()));
+ return result;
+}
+
+bool TagEvent::isFavourite() const
+{
+ return tagsObject().contains("m.favourite");
+}
+
+bool TagEvent::isLowPriority() const
+{
+ return tagsObject().contains("m.lowpriority");
+}
+
+QJsonObject TagEvent::tagsObject() const
+{
+ return contentJson().value("tags").toObject();
+}
diff --git a/events/tagevent.h b/events/tagevent.h
new file mode 100644
index 00000000..23b0b703
--- /dev/null
+++ b/events/tagevent.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma once
+
+#include "event.h"
+
+namespace QMatrixClient
+{
+ struct TagRecord
+ {
+ explicit TagRecord(const QJsonObject& json = {});
+
+ QString order;
+ };
+
+ class TagEvent : public Event
+ {
+ public:
+ explicit TagEvent(const QJsonObject& obj);
+
+ /** Get the list of tag names */
+ QStringList tagNames() const;
+
+ /** Get the list of tags along with information on each */
+ QHash<QString, TagRecord> tags() const;
+
+ /** Check whether the list of tags has m.favourite */
+ bool isFavourite() const;
+ /** Check whether the list of tags has m.lowpriority */
+ bool isLowPriority() const;
+
+ static constexpr const char * TypeId = "m.tag";
+
+ protected:
+ QJsonObject tagsObject() const;
+ };
+}
diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp
index ce5dd894..7b066f4f 100644
--- a/jobs/syncjob.cpp
+++ b/jobs/syncjob.cpp
@@ -54,6 +54,11 @@ SyncDataList&& SyncData::takeRoomData()
return std::move(roomData);
}
+SyncBatch<Event>&& SyncData::takeAccountData()
+{
+ return std::move(accountData);
+}
+
BaseJob::Status SyncJob::parseJson(const QJsonDocument& data)
{
return d.parseJson(data);
@@ -63,12 +68,12 @@ BaseJob::Status SyncData::parseJson(const QJsonDocument &data)
{
QElapsedTimer et; et.start();
- QJsonObject json = data.object();
+ auto json { data.object() };
nextBatch_ = json.value("next_batch").toString();
// TODO: presence
- // TODO: account_data
- QJsonObject rooms = json.value("rooms").toObject();
+ accountData.fromJson(json);
+ QJsonObject rooms = json.value("rooms").toObject();
for (size_t i = 0; i < JoinStateStrings.size(); ++i)
{
const auto rs = rooms.value(JoinStateStrings[i]).toObject();
diff --git a/jobs/syncjob.h b/jobs/syncjob.h
index aed36e0b..5956e73b 100644
--- a/jobs/syncjob.h
+++ b/jobs/syncjob.h
@@ -26,30 +26,30 @@
namespace QMatrixClient
{
- class SyncRoomData
+ template <typename EventT>
+ class SyncBatch : public EventsBatch<EventT>
{
public:
- template <typename EventT>
- class Batch : public EventsBatch<EventT>
+ explicit SyncBatch(QString k) : jsonKey(std::move(k)) { }
+ void fromJson(const QJsonObject& roomContents)
{
- public:
- explicit Batch(QString k) : jsonKey(std::move(k)) { }
- void fromJson(const QJsonObject& roomContents)
- {
- EventsBatch<EventT>::fromJson(
- roomContents[jsonKey].toObject(), "events");
- }
+ EventsBatch<EventT>::fromJson(
+ roomContents[jsonKey].toObject(), "events");
+ }
- private:
- QString jsonKey;
- };
+ private:
+ QString jsonKey;
+ };
+ class SyncRoomData
+ {
+ public:
QString roomId;
JoinState joinState;
- Batch<RoomEvent> state;
- Batch<RoomEvent> timeline;
- Batch<Event> ephemeral;
- Batch<Event> accountData;
+ SyncBatch<RoomEvent> state;
+ SyncBatch<RoomEvent> timeline;
+ SyncBatch<Event> ephemeral;
+ SyncBatch<Event> accountData;
bool timelineLimited;
QString timelinePrevBatch;
@@ -68,11 +68,13 @@ namespace QMatrixClient
{
public:
BaseJob::Status parseJson(const QJsonDocument &data);
+ SyncBatch<Event>&& takeAccountData();
SyncDataList&& takeRoomData();
QString nextBatch() const;
private:
QString nextBatch_;
+ SyncBatch<Event> accountData { "account_data" };
SyncDataList roomData;
};
diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri
index 72637caf..7cfa94a1 100644
--- a/libqmatrixclient.pri
+++ b/libqmatrixclient.pri
@@ -24,6 +24,7 @@ HEADERS += \
$$PWD/events/roomavatarevent.h \
$$PWD/events/typingevent.h \
$$PWD/events/receiptevent.h \
+ $$PWD/events/tagevent.h \
$$PWD/events/redactionevent.h \
$$PWD/jobs/requestdata.h \
$$PWD/jobs/basejob.h \
@@ -55,7 +56,7 @@ SOURCES += \
$$PWD/events/roommemberevent.cpp \
$$PWD/events/typingevent.cpp \
$$PWD/events/receiptevent.cpp \
- $$PWD/events/redactionevent.cpp \
+ $$PWD/events/tagevent.cpp \
$$PWD/jobs/requestdata.cpp \
$$PWD/jobs/basejob.cpp \
$$PWD/jobs/checkauthmethods.cpp \
diff --git a/room.cpp b/room.cpp
index 762e929c..29244da2 100644
--- a/room.cpp
+++ b/room.cpp
@@ -95,6 +95,8 @@ class Room::Private
QString firstDisplayedEventId;
QString lastDisplayedEventId;
QHash<const User*, QString> lastReadEventIds;
+ QHash<QString, TagRecord> tags;
+ QHash<QString, QJsonObject> accountData;
QString prevBatch;
QPointer<RoomMessagesJob> roomMessagesJob;
@@ -552,6 +554,16 @@ void Room::resetHighlightCount()
emit highlightCountChanged(this);
}
+QStringList Room::tagNames() const
+{
+ return d->tags.keys();
+}
+
+const QHash<QString, TagRecord>& Room::tags() const
+{
+ return d->tags;
+}
+
const RoomMessageEvent*
Room::Private::getEventWithFile(const QString& eventId) const
{
@@ -873,6 +885,15 @@ void Room::updateData(SyncRoomData&& data)
<< et.elapsed() << "ms";
}
+ if (!data.accountData.empty())
+ {
+ et.restart();
+ for (auto&& event: data.accountData)
+ processAccountDataEvent(move(event));
+ qCDebug(PROFILER) << "*** Room::processAccountData():"
+ << et.elapsed() << "ms";
+ }
+
if( data.highlightCount != d->highlightCount )
{
d->highlightCount = data.highlightCount;
@@ -1433,6 +1454,19 @@ void Room::processEphemeralEvent(EventPtr event)
}
}
+void Room::processAccountDataEvent(EventPtr event)
+{
+ switch (event->type())
+ {
+ case EventType::Tag:
+ d->tags = static_cast<TagEvent*>(event.get())->tags();
+ emit tagsChanged();
+ break;
+ default:
+ d->accountData[event->jsonType()] = event->contentJson();
+ }
+}
+
QString Room::Private::roomNameFromMemberNames(const QList<User *> &userlist) const
{
// This is part 3(i,ii,iii) in the room displayname algorithm described
diff --git a/room.h b/room.h
index 5253a7c6..6dba6156 100644
--- a/room.h
+++ b/room.h
@@ -20,6 +20,7 @@
#include "jobs/syncjob.h"
#include "events/roommessageevent.h"
+#include "events/tagevent.h"
#include "joinstate.h"
#include <QtCore/QList>
@@ -116,6 +117,8 @@ namespace QMatrixClient
Q_PROPERTY(QString lastDisplayedEventId READ lastDisplayedEventId WRITE setLastDisplayedEventId NOTIFY lastDisplayedEventChanged)
Q_PROPERTY(QString readMarkerEventId READ readMarkerEventId WRITE markMessagesAsRead NOTIFY readMarkerMoved)
+ Q_PROPERTY(QStringList tagNames READ tagNames NOTIFY tagsChanged)
+
public:
using Timeline = std::deque<TimelineItem>;
using rev_iter_t = Timeline::const_reverse_iterator;
@@ -237,6 +240,9 @@ namespace QMatrixClient
Q_INVOKABLE int highlightCount() const;
Q_INVOKABLE void resetHighlightCount();
+ QStringList tagNames() const;
+ const QHash<QString, TagRecord>& tags() const;
+
Q_INVOKABLE QUrl urlToThumbnail(const QString& eventId);
Q_INVOKABLE QUrl urlToDownload(const QString& eventId);
Q_INVOKABLE QString fileNameToDownload(const QString& eventId);
@@ -318,6 +324,8 @@ namespace QMatrixClient
void readMarkerMoved();
void unreadMessagesChanged(Room* room);
+ void tagsChanged();
+
void replacedEvent(const RoomEvent* newEvent,
const RoomEvent* oldEvent);
@@ -330,6 +338,7 @@ namespace QMatrixClient
protected:
virtual void processStateEvents(const RoomEvents& events);
virtual void processEphemeralEvent(EventPtr event);
+ virtual void processAccountDataEvent(EventPtr event);
virtual void onAddNewTimelineEvents(timeline_iter_t from) { }
virtual void onAddHistoricalTimelineEvents(rev_iter_t from) { }
virtual void onRedaction(const RoomEvent* prevEvent,