diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | events/event.cpp | 2 | ||||
-rw-r--r-- | events/event.h | 3 | ||||
-rw-r--r-- | events/roomavatarevent.cpp | 23 | ||||
-rw-r--r-- | events/roomavatarevent.h | 53 | ||||
-rw-r--r-- | libqmatrixclient.pri | 2 | ||||
-rw-r--r-- | room.cpp | 57 | ||||
-rw-r--r-- | room.h | 10 | ||||
-rw-r--r-- | user.cpp | 5 | ||||
-rw-r--r-- | user.h | 2 |
10 files changed, 146 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index fc3276c9..26c7bf46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ set(libqmatrixclient_SRCS events/roomcanonicalaliasevent.cpp events/roommemberevent.cpp events/roomtopicevent.cpp + events/roomavatarevent.cpp events/typingevent.cpp events/receiptevent.cpp events/encryptedevent.cpp diff --git a/events/event.cpp b/events/event.cpp index 304f2af6..9963a0ef 100644 --- a/events/event.cpp +++ b/events/event.cpp @@ -24,6 +24,7 @@ #include "roomcanonicalaliasevent.h" #include "roommemberevent.h" #include "roomtopicevent.h" +#include "roomavatarevent.h" #include "typingevent.h" #include "receiptevent.h" #include "encryptedevent.h" @@ -136,6 +137,7 @@ RoomEvent* RoomEvent::fromJson(const QJsonObject& obj) "m.room.canonical_alias", make<RoomCanonicalAliasEvent>, "m.room.member", make<RoomMemberEvent>, "m.room.topic", make<RoomTopicEvent>, + "m.room.avatar", make<RoomAvatarEvent>, "m.room.encryption", make<EncryptionEvent>, /* Insert new ROOM event types BEFORE this line */ nullptr diff --git a/events/event.h b/events/event.h index ec993522..c151ac0e 100644 --- a/events/event.h +++ b/events/event.h @@ -34,7 +34,8 @@ namespace QMatrixClient enum class Type { RoomMessage, RoomName, RoomAliases, RoomCanonicalAlias, - RoomMember, RoomTopic, RoomEncryption, RoomEncryptedMessage, + RoomMember, RoomTopic, RoomAvatar, + RoomEncryption, RoomEncryptedMessage, Typing, Receipt, Unknown }; diff --git a/events/roomavatarevent.cpp b/events/roomavatarevent.cpp new file mode 100644 index 00000000..7a5f82a1 --- /dev/null +++ b/events/roomavatarevent.cpp @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (C) 2017 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 + */ + +#include "roomavatarevent.h" + +using namespace QMatrixClient; + + diff --git a/events/roomavatarevent.h b/events/roomavatarevent.h new file mode 100644 index 00000000..411de4e8 --- /dev/null +++ b/events/roomavatarevent.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (C) 2017 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" + +#include <utility> + +#include "eventcontent.h" + +namespace QMatrixClient +{ + class RoomAvatarEvent: public RoomEvent + { + public: + explicit RoomAvatarEvent(EventContent::ImageContent avatar) + : RoomEvent(Type::RoomAvatar), _avatar(std::move(avatar)) + { } + explicit RoomAvatarEvent(const QJsonObject& obj) + : RoomEvent(Type::RoomAvatar, obj), _avatar(contentJson()) + { } + + const EventContent::ImageContent& content() const { return _avatar; } + + QJsonObject toJson() const { return _avatar.toJson(); } + + static constexpr const char* TypeId = "m.room.avatar"; + + private: + // It's a bit of an overkill to use a full-fledged ImageContent + // because in reality m.room.avatar usually only has a single URL, + // without a thumbnail. But The Spec says there be thumbnails, and + // we follow The Spec. + EventContent::ImageContent _avatar; + }; + +} // namespace QMatrixClient diff --git a/libqmatrixclient.pri b/libqmatrixclient.pri index 9bcb911f..9eb6bd16 100644 --- a/libqmatrixclient.pri +++ b/libqmatrixclient.pri @@ -18,6 +18,7 @@ HEADERS += \ $$PWD/events/roomcanonicalaliasevent.h \ $$PWD/events/roommemberevent.h \ $$PWD/events/roomtopicevent.h \ + $$PWD/events/roomavatarevent.h \ $$PWD/events/typingevent.h \ $$PWD/events/receiptevent.h \ $$PWD/jobs/basejob.h \ @@ -48,6 +49,7 @@ SOURCES += \ $$PWD/events/roomcanonicalaliasevent.cpp \ $$PWD/events/roommemberevent.cpp \ $$PWD/events/roomtopicevent.cpp \ + $$PWD/events/roomavatarevent.cpp \ $$PWD/events/typingevent.cpp \ $$PWD/events/receiptevent.cpp \ $$PWD/jobs/basejob.cpp \ @@ -27,12 +27,14 @@ #include "events/roomaliasesevent.h" #include "events/roomcanonicalaliasevent.h" #include "events/roomtopicevent.h" +#include "events/roomavatarevent.h" #include "events/roommemberevent.h" #include "events/typingevent.h" #include "events/receiptevent.h" #include "jobs/sendeventjob.h" #include "jobs/roommessagesjob.h" #include "jobs/postreceiptjob.h" +#include "avatar.h" #include "connection.h" #include "user.h" @@ -53,7 +55,7 @@ class Room::Private Private(Connection* c, QString id_, JoinState initialJoinState) : q(nullptr), connection(c), id(std::move(id_)) - , joinState(initialJoinState), unreadMessages(false) + , avatar(c), joinState(initialJoinState), unreadMessages(false) , highlightCount(0), notificationCount(0), roomMessagesJob(nullptr) { } @@ -73,6 +75,7 @@ class Room::Private QString name; QString displayname; QString topic; + Avatar avatar; JoinState joinState; bool unreadMessages; int highlightCount; @@ -189,6 +192,23 @@ QString Room::topic() const return d->topic; } +QPixmap Room::avatar(int width, int height) +{ + if (!d->avatar.url().isEmpty()) + return d->avatar.get(width, height, [=] { emit avatarChanged(); }); + + // Use the other side's avatar for 1:1's + if (d->membersMap.size() == 2) + { + auto theOtherOneIt = d->membersMap.begin(); + if (theOtherOneIt.value() == localUser()) + ++theOtherOneIt; + return theOtherOneIt.value()->avatarObject() + .get(width, height, [=] { emit avatarChanged(); }); + } + return {}; +} + JoinState Room::joinState() const { return d->joinState; @@ -778,6 +798,17 @@ void Room::processStateEvents(const RoomEvents& events) emit topicChanged(); break; } + case EventType::RoomAvatar: { + const auto& avatarEventContent = + static_cast<RoomAvatarEvent*>(event)->content(); + if (d->avatar.updateUrl(avatarEventContent.url)) + { + qCDebug(MAIN) << "Room avatar URL updated:" + << avatarEventContent.url.toString(); + emit avatarChanged(); + } + break; + } case EventType::RoomMember: { auto memberEvent = static_cast<RoomMemberEvent*>(event); // Can't use d->member() below because the user may be not a member (yet) @@ -939,9 +970,13 @@ void Room::Private::updateDisplayname() emit q->displaynameChanged(q); } -QJsonObject stateEventToJson(const QString& type, const QString& name, - const QJsonValue& content) +template <typename T> +void appendEventJson(QJsonArray& events, const QString& type, + const QString& name, const T& content) { + if (content.isEmpty()) + return; + QJsonObject contentObj; contentObj.insert(name, content); @@ -949,7 +984,7 @@ QJsonObject stateEventToJson(const QString& type, const QString& name, eventObj.insert("type", type); eventObj.insert("content", contentObj); - return eventObj; + events.append(eventObj); } QJsonObject Room::Private::toJson() const @@ -958,12 +993,14 @@ QJsonObject Room::Private::toJson() const { QJsonArray stateEvents; - stateEvents.append(stateEventToJson("m.room.name", "name", name)); - stateEvents.append(stateEventToJson("m.room.topic", "topic", topic)); - stateEvents.append(stateEventToJson("m.room.aliases", "aliases", - QJsonArray::fromStringList(aliases))); - stateEvents.append(stateEventToJson("m.room.canonical_alias", "alias", - canonicalAlias)); + appendEventJson(stateEvents, "m.room.name", "name", name); + appendEventJson(stateEvents, "m.room.topic", "topic", topic); + appendEventJson(stateEvents, "m.room.avatar", "avatar_url", + avatar.url().toString()); + appendEventJson(stateEvents, "m.room.aliases", "aliases", + QJsonArray::fromStringList(aliases)); + appendEventJson(stateEvents, "m.room.canonical_alias", "alias", + canonicalAlias); for (const auto &i : membersMap) { @@ -25,6 +25,7 @@ #include <QtCore/QStringList> #include <QtCore/QObject> #include <QtCore/QJsonObject> +#include <QtGui/QPixmap> #include "jobs/syncjob.h" #include "events/roommessageevent.h" @@ -79,7 +80,7 @@ namespace QMatrixClient using rev_iter_t = Timeline::const_reverse_iterator; Room(Connection* connection, QString id, JoinState initialJoinState); - virtual ~Room(); + ~Room() override; Connection* connection() const; User* localUser() const; @@ -98,6 +99,12 @@ namespace QMatrixClient Q_INVOKABLE int memberCount() const; /** + * Returns a room avatar and requests it from the network if needed + * @return a pixmap with the avatar or a placeholder if there's none + * available yet + */ + Q_INVOKABLE QPixmap avatar(int width, int height); + /** * @brief Produces a disambiguated name for a given user in * the context of the room */ @@ -181,6 +188,7 @@ namespace QMatrixClient /** @brief The room displayname changed */ void displaynameChanged(Room* room); void topicChanged(); + void avatarChanged(); void userAdded(User* user); void userRemoved(User* user); void memberRenamed(User* user); @@ -90,6 +90,11 @@ QString User::bridged() const { return d->bridged; } +Avatar& User::avatarObject() +{ + return d->avatar; +} + QPixmap User::avatar(int width, int height) { return d->avatar.get(width, height, [=] { emit avatarChanged(this); }); @@ -20,6 +20,7 @@ #include <QtCore/QString> #include <QtCore/QObject> +#include "avatar.h" namespace QMatrixClient { @@ -52,6 +53,7 @@ namespace QMatrixClient */ Q_INVOKABLE QString bridged() const; + Avatar& avatarObject(); QPixmap avatar(int requestedWidth, int requestedHeight); QUrl avatarUrl() const; |