diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-02-26 09:07:16 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-02-26 09:07:16 +0900 |
commit | 91cc0e8db0006beeb91b9e007cd21343984dfb6a (patch) | |
tree | 7a79286d7c6e5a99644c3f7141e1cdc8e2459416 | |
parent | e77a53946805649be99f8c0f6ee9c00702348132 (diff) | |
parent | ec412621d71b1a7758b15d2b3c5cd5e7b2081ab1 (diff) | |
download | libquotient-91cc0e8db0006beeb91b9e007cd21343984dfb6a.tar.gz libquotient-91cc0e8db0006beeb91b9e007cd21343984dfb6a.zip |
Merge branch 'kitsune-account-data'
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | connection.cpp | 24 | ||||
-rw-r--r-- | connection.h | 15 | ||||
-rw-r--r-- | events/event.cpp | 8 | ||||
-rw-r--r-- | events/event.h | 4 | ||||
-rw-r--r-- | events/tagevent.cpp | 42 | ||||
-rw-r--r-- | events/tagevent.h | 53 | ||||
-rw-r--r-- | jobs/syncjob.cpp | 11 | ||||
-rw-r--r-- | jobs/syncjob.h | 36 | ||||
-rw-r--r-- | libqmatrixclient.pri | 3 | ||||
-rw-r--r-- | room.cpp | 34 | ||||
-rw-r--r-- | room.h | 9 |
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 \ @@ -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 @@ -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, |