diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index 0ddf0f8b..fbaf9ddd 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -25,6 +25,20 @@
#include "Sync.h"
#include "UserInfoWidget.h"
+#include "AliasesEventContent.h"
+#include "AvatarEventContent.h"
+#include "CanonicalAliasEventContent.h"
+#include "CreateEventContent.h"
+#include "HistoryVisibilityEventContent.h"
+#include "JoinRulesEventContent.h"
+#include "NameEventContent.h"
+#include "PowerLevelsEventContent.h"
+#include "TopicEventContent.h"
+
+#include "StateEvent.h"
+
+namespace events = matrix::events;
+
ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent)
, ui(new Ui::ChatPage)
@@ -55,16 +69,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout()));
connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
- connect(room_list_,
- SIGNAL(roomChanged(const RoomInfo &)),
- this,
- SLOT(changeTopRoomInfo(const RoomInfo &)));
- connect(room_list_,
- SIGNAL(roomChanged(const RoomInfo &)),
- view_manager_,
- SLOT(setHistoryView(const RoomInfo &)));
+ connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
+ connect(room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
- // TODO: Better pass the whole RoomInfo struct instead of the roomid.
connect(view_manager_,
SIGNAL(unreadMessages(const QString &, int)),
room_list_,
@@ -161,7 +168,24 @@ void ChatPage::syncCompleted(const SyncResponse &response)
{
client_->setNextBatchToken(response.nextBatch());
- /* room_list_->sync(response.rooms()); */
+ auto joined = response.rooms().join();
+
+ for (auto it = joined.constBegin(); it != joined.constEnd(); it++) {
+ RoomState room_state;
+
+ if (state_manager_.contains(it.key()))
+ room_state = state_manager_[it.key()];
+
+ updateRoomState(room_state, it.value().state().events());
+ updateRoomState(room_state, it.value().timeline().events());
+
+ state_manager_.insert(it.key(), room_state);
+
+ if (it.key() == current_room_)
+ changeTopRoomInfo(it.key());
+ }
+
+ room_list_->sync(state_manager_);
view_manager_->sync(response.rooms());
sync_timer_->start(sync_interval_);
@@ -172,8 +196,19 @@ void ChatPage::initialSyncCompleted(const SyncResponse &response)
if (!response.nextBatch().isEmpty())
client_->setNextBatchToken(response.nextBatch());
+ auto joined = response.rooms().join();
+
+ for (auto it = joined.constBegin(); it != joined.constEnd(); it++) {
+ RoomState room_state;
+
+ updateRoomState(room_state, it.value().state().events());
+ updateRoomState(room_state, it.value().timeline().events());
+
+ state_manager_.insert(it.key(), room_state);
+ }
+
view_manager_->initialize(response.rooms());
- room_list_->setInitialRooms(response.rooms());
+ room_list_->setInitialRooms(state_manager_);
sync_timer_->start(sync_interval_);
}
@@ -182,7 +217,7 @@ void ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img)
{
room_avatars_.insert(roomid, img);
- if (current_room_.id() != roomid)
+ if (current_room_ != roomid)
return;
top_bar_->updateRoomAvatar(img.toImage());
@@ -199,17 +234,22 @@ void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &displ
client_->fetchOwnAvatar(avatar_url);
}
-void ChatPage::changeTopRoomInfo(const RoomInfo &info)
+void ChatPage::changeTopRoomInfo(const QString &room_id)
{
- top_bar_->updateRoomName(info.name());
- top_bar_->updateRoomTopic(info.topic());
+ if (!state_manager_.contains(room_id))
+ return;
+
+ auto state = state_manager_[room_id];
+
+ top_bar_->updateRoomName(state.resolveName());
+ top_bar_->updateRoomTopic(state.resolveTopic());
- if (room_avatars_.contains(info.id()))
- top_bar_->updateRoomAvatar(room_avatars_.value(info.id()).toImage());
+ if (room_avatars_.contains(room_id))
+ top_bar_->updateRoomAvatar(room_avatars_.value(room_id).toImage());
else
- top_bar_->updateRoomAvatarFromName(info.name());
+ top_bar_->updateRoomAvatarFromName(state.resolveName());
- current_room_ = info;
+ current_room_ = room_id;
}
void ChatPage::showUnreadMessageNotification(int count)
@@ -221,6 +261,88 @@ void ChatPage::showUnreadMessageNotification(int count)
emit changeWindowTitle(QString("nheko (%1)").arg(count));
}
+void ChatPage::updateRoomState(RoomState &room_state, const QJsonArray &events)
+{
+ events::EventType ty;
+
+ for (const auto &event : events) {
+ try {
+ ty = events::extractEventType(event.toObject());
+ } catch (const DeserializationException &e) {
+ qWarning() << e.what() << event;
+ continue;
+ }
+
+ if (!events::isStateEvent(ty))
+ continue;
+
+ try {
+ switch (ty) {
+ case events::EventType::RoomAliases: {
+ events::StateEvent<events::AliasesEventContent> aliases;
+ aliases.deserialize(event);
+ room_state.aliases = aliases;
+ break;
+ }
+ case events::EventType::RoomAvatar: {
+ events::StateEvent<events::AvatarEventContent> avatar;
+ avatar.deserialize(event);
+ room_state.avatar = avatar;
+ break;
+ }
+ case events::EventType::RoomCanonicalAlias: {
+ events::StateEvent<events::CanonicalAliasEventContent> canonical_alias;
+ canonical_alias.deserialize(event);
+ room_state.canonical_alias = canonical_alias;
+ break;
+ }
+ case events::EventType::RoomCreate: {
+ events::StateEvent<events::CreateEventContent> create;
+ create.deserialize(event);
+ room_state.create = create;
+ break;
+ }
+ case events::EventType::RoomHistoryVisibility: {
+ events::StateEvent<events::HistoryVisibilityEventContent> history_visibility;
+ history_visibility.deserialize(event);
+ room_state.history_visibility = history_visibility;
+ break;
+ }
+ case events::EventType::RoomJoinRules: {
+ events::StateEvent<events::JoinRulesEventContent> join_rules;
+ join_rules.deserialize(event);
+ room_state.join_rules = join_rules;
+ break;
+ }
+ case events::EventType::RoomName: {
+ events::StateEvent<events::NameEventContent> name;
+ name.deserialize(event);
+ room_state.name = name;
+ break;
+ }
+ case events::EventType::RoomPowerLevels: {
+ events::StateEvent<events::PowerLevelsEventContent> power_levels;
+ power_levels.deserialize(event);
+ room_state.power_levels = power_levels;
+ break;
+ }
+ case events::EventType::RoomTopic: {
+ events::StateEvent<events::TopicEventContent> topic;
+ topic.deserialize(event);
+ room_state.topic = topic;
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ } catch (const DeserializationException &e) {
+ qWarning() << e.what() << event;
+ continue;
+ }
+ }
+}
+
ChatPage::~ChatPage()
{
sync_timer_->stop();
diff --git a/src/ImageItem.cc b/src/ImageItem.cc
index d03e41b5..e0e2f977 100644
--- a/src/ImageItem.cc
+++ b/src/ImageItem.cc
@@ -25,10 +25,11 @@
#include "ImageItem.h"
#include "ImageOverlayDialog.h"
-ImageItem::ImageItem(QSharedPointer<MatrixClient> client, const Event &event, const QString &body, const QUrl &url, QWidget *parent)
+namespace events = matrix::events;
+namespace msgs = matrix::events::messages;
+
+ImageItem::ImageItem(QSharedPointer<MatrixClient> client, const events::MessageEvent<msgs::Image> &event, QWidget *parent)
: QWidget(parent)
- , url_{url}
- , text_{body}
, event_{event}
, client_{client}
{
@@ -37,6 +38,9 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client, const Event &event, co
setCursor(Qt::PointingHandCursor);
setAttribute(Qt::WA_Hover, true);
+ url_ = event.msgContent().url();
+ text_ = event.content().body();
+
QList<QString> url_parts = url_.toString().split("mxc://");
if (url_parts.size() != 2) {
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 6b4a81bb..f9d81f27 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -194,10 +194,12 @@ void MatrixClient::onInitialSyncResponse(QNetworkReply *reply)
try {
response.deserialize(json);
- emit initialSyncCompleted(response);
} catch (DeserializationException &e) {
qWarning() << "Sync malformed response" << e.what();
+ return;
}
+
+ emit initialSyncCompleted(response);
}
void MatrixClient::onSyncResponse(QNetworkReply *reply)
diff --git a/src/RoomInfoListItem.cc b/src/RoomInfoListItem.cc
index 954025c6..6e632a6a 100644
--- a/src/RoomInfoListItem.cc
+++ b/src/RoomInfoListItem.cc
@@ -19,12 +19,13 @@
#include <QMouseEvent>
#include "Ripple.h"
-#include "RoomInfo.h"
#include "RoomInfoListItem.h"
+#include "RoomState.h"
-RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
+RoomInfoListItem::RoomInfoListItem(RoomState state, QString room_id, QWidget *parent)
: QWidget(parent)
- , info_(info)
+ , state_(state)
+ , room_id_(room_id)
, is_pressed_(false)
, max_height_(60)
, unread_msg_count_(0)
@@ -43,6 +44,9 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
setMaximumSize(parent->width(), max_height_);
+ QString room_name = state_.resolveName();
+ QString room_topic = state_.topic.content().topic().simplified();
+
topLayout_ = new QHBoxLayout(this);
topLayout_->setSpacing(0);
topLayout_->setMargin(0);
@@ -60,7 +64,7 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
textLayout_->setContentsMargins(0, 5, 0, 5);
roomAvatar_ = new Avatar(avatarWidget_);
- roomAvatar_->setLetter(QChar(info_.name()[0]));
+ roomAvatar_->setLetter(QChar(room_name[0]));
roomAvatar_->setSize(max_height_ - 20);
roomAvatar_->setTextColor("#555459");
roomAvatar_->setBackgroundColor("#d6dde3");
@@ -76,12 +80,12 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
avatarLayout_->addWidget(roomAvatar_);
- roomName_ = new QLabel(info_.name(), textWidget_);
+ roomName_ = new QLabel(room_name, textWidget_);
roomName_->setMaximumSize(parent->width() - max_height_, 20);
roomName_->setFont(QFont("Open Sans", 11));
roomName_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
- roomTopic_ = new QLabel(info_.topic(), textWidget_);
+ roomTopic_ = new QLabel(room_topic, textWidget_);
roomTopic_->setMaximumSize(parent->width() - max_height_, 20);
roomTopic_->setFont(QFont("Open Sans", 10));
roomTopic_->setStyleSheet("color: #171919");
@@ -93,8 +97,8 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
topLayout_->addWidget(avatarWidget_);
topLayout_->addWidget(textWidget_);
- setElidedText(roomName_, info_.name(), parent->width() - max_height_);
- setElidedText(roomTopic_, info_.topic(), parent->width() - max_height_);
+ setElidedText(roomName_, room_name, parent->width() - max_height_);
+ setElidedText(roomTopic_, room_topic, parent->width() - max_height_);
QPainterPath path;
path.addRoundedRect(rect(), 0, 0);
@@ -131,9 +135,23 @@ void RoomInfoListItem::setPressedState(bool state)
}
}
+void RoomInfoListItem::setState(const RoomState &new_state)
+{
+ if (state_.resolveName() != new_state.resolveName())
+ setElidedText(roomName_, new_state.resolveName(), parentWidget()->width() - max_height_);
+
+ if (state_.resolveTopic() != new_state.resolveTopic())
+ setElidedText(roomTopic_, new_state.resolveTopic(), parentWidget()->width() - max_height_);
+
+ if (new_state.avatar.content().url().toString().isEmpty())
+ roomAvatar_->setLetter(QChar(new_state.resolveName()[0]));
+
+ state_ = new_state;
+}
+
void RoomInfoListItem::mousePressEvent(QMouseEvent *event)
{
- emit clicked(info_);
+ emit clicked(room_id_);
setPressedState(true);
diff --git a/src/RoomList.cc b/src/RoomList.cc
index 4fbccee0..a0312113 100644
--- a/src/RoomList.cc
+++ b/src/RoomList.cc
@@ -57,32 +57,6 @@ void RoomList::clear()
rooms_.clear();
}
-RoomInfo RoomList::extractRoomInfo(const State &room_state)
-{
- RoomInfo info;
-
- auto events = room_state.events();
-
- for (const auto &event : events) {
- if (event.type() == "m.room.name") {
- info.setName(event.content().value("name").toString());
- } else if (event.type() == "m.room.topic") {
- info.setTopic(event.content().value("topic").toString());
- } else if (event.type() == "m.room.avatar") {
- info.setAvatarUrl(QUrl(event.content().value("url").toString()));
- } else if (event.type() == "m.room.canonical_alias") {
- if (info.name().isEmpty())
- info.setName(event.content().value("alias").toString());
- }
- }
-
- // Sanitize info for print.
- info.setTopic(info.topic().simplified());
- info.setName(info.name().simplified());
-
- return info;
-}
-
void RoomList::updateUnreadMessageCount(const QString &roomid, int count)
{
if (!rooms_.contains(roomid)) {
@@ -105,27 +79,21 @@ void RoomList::calculateUnreadMessageCount()
emit totalUnreadMessageCountUpdated(total_unread_msgs);
}
-void RoomList::setInitialRooms(const Rooms &rooms)
+void RoomList::setInitialRooms(const QMap<QString, RoomState> &states)
{
rooms_.clear();
- for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) {
- RoomInfo info = RoomList::extractRoomInfo(it.value().state());
- info.setId(it.key());
+ for (auto it = states.constBegin(); it != states.constEnd(); it++) {
+ auto room_id = it.key();
+ auto state = it.value();
- if (info.name().isEmpty())
- continue;
+ if (!state.avatar.content().url().toString().isEmpty())
+ client_->fetchRoomAvatar(room_id, state.avatar.content().url());
- if (!info.avatarUrl().isEmpty())
- client_->fetchRoomAvatar(info.id(), info.avatarUrl());
+ RoomInfoListItem *room_item = new RoomInfoListItem(state, room_id, ui->scrollArea);
+ connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom);
- RoomInfoListItem *room_item = new RoomInfoListItem(info, ui->scrollArea);
- connect(room_item,
- SIGNAL(clicked(const RoomInfo &)),
- this,
- SLOT(highlightSelectedRoom(const RoomInfo &)));
-
- rooms_.insert(it.key(), room_item);
+ rooms_.insert(room_id, room_item);
int pos = ui->scrollVerticalLayout->count() - 1;
ui->scrollVerticalLayout->insertWidget(pos, room_item);
@@ -134,29 +102,51 @@ void RoomList::setInitialRooms(const Rooms &rooms)
if (rooms_.isEmpty())
return;
- // TODO: Move this into its own function.
auto first_room = rooms_.first();
first_room->setPressedState(true);
- emit roomChanged(first_room->info());
+
+ emit roomChanged(rooms_.firstKey());
+}
+
+void RoomList::sync(const QMap<QString, RoomState> &states)
+{
+ for (auto it = states.constBegin(); it != states.constEnd(); it++) {
+ auto room_id = it.key();
+ auto state = it.value();
+
+ // TODO: Add the new room to the list.
+ if (!rooms_.contains(room_id))
+ continue;
+
+ auto room = rooms_[room_id];
+
+ auto current_avatar = room->state().avatar.content().url();
+ auto new_avatar = state.avatar.content().url();
+
+ if (current_avatar != new_avatar && !new_avatar.toString().isEmpty())
+ client_->fetchRoomAvatar(room_id, new_avatar);
+
+ room->setState(state);
+ }
}
-void RoomList::highlightSelectedRoom(const RoomInfo &info)
+void RoomList::highlightSelectedRoom(const QString &room_id)
{
- emit roomChanged(info);
+ emit roomChanged(room_id);
- if (!rooms_.contains(info.id())) {
+ if (!rooms_.contains(room_id)) {
qDebug() << "RoomList: clicked unknown roomid";
return;
}
// TODO: Send a read receipt for the last event.
- auto room = rooms_[info.id()];
+ auto room = rooms_[room_id];
room->clearUnreadMessageCount();
calculateUnreadMessageCount();
for (auto it = rooms_.constBegin(); it != rooms_.constEnd(); it++) {
- if (it.key() != info.id())
+ if (it.key() != room_id)
it.value()->setPressedState(false);
}
}
diff --git a/src/RoomState.cc b/src/RoomState.cc
new file mode 100644
index 00000000..98f418e3
--- /dev/null
+++ b/src/RoomState.cc
@@ -0,0 +1,32 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "RoomState.h"
+
+QString RoomState::resolveName() const
+{
+ if (!name.content().name().isEmpty())
+ return name.content().name().simplified();
+
+ if (!canonical_alias.content().alias().isEmpty())
+ return canonical_alias.content().alias().simplified();
+
+ if (aliases.content().aliases().size() != 0)
+ return aliases.content().aliases()[0].simplified();
+
+ return "Unknown Room Name";
+}
diff --git a/src/Sync.cc b/src/Sync.cc
index 50b49fc6..0d04e878 100644
--- a/src/Sync.cc
+++ b/src/Sync.cc
@@ -157,19 +157,7 @@ void State::deserialize(const QJsonValue &data)
if (!data.isArray())
throw DeserializationException("State is not a JSON array");
- QJsonArray event_array = data.toArray();
-
- for (int i = 0; i < event_array.count(); i++) {
- Event event;
-
- try {
- event.deserialize(event_array.at(i));
- events_.push_back(event);
- } catch (DeserializationException &e) {
- qWarning() << e.what();
- qWarning() << "Skipping malformed state event";
- }
- }
+ events_ = data.toArray();
}
void Timeline::deserialize(const QJsonValue &data)
@@ -194,17 +182,5 @@ void Timeline::deserialize(const QJsonValue &data)
if (!object.value("events").isArray())
throw DeserializationException("timeline/events is not a JSON array");
- auto timeline_events = object.value("events").toArray();
-
- for (int i = 0; i < timeline_events.count(); i++) {
- Event event;
-
- try {
- event.deserialize(timeline_events.at(i));
- events_.push_back(event);
- } catch (DeserializationException &e) {
- qWarning() << e.what();
- qWarning() << "Skipping malformed timeline event";
- }
- }
+ events_ = object.value("events").toArray();
}
diff --git a/src/TimelineItem.cc b/src/TimelineItem.cc
index 4d33db70..8d5e503a 100644
--- a/src/TimelineItem.cc
+++ b/src/TimelineItem.cc
@@ -21,6 +21,9 @@
#include "ImageItem.h"
#include "TimelineItem.h"
+namespace events = matrix::events;
+namespace msgs = matrix::events::messages;
+
TimelineItem::TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent)
: QWidget(parent)
{
@@ -37,7 +40,7 @@ TimelineItem::TimelineItem(const QString &body, QWidget *parent)
setupLayout();
}
-TimelineItem::TimelineItem(ImageItem *image, const Event &event, const QString &color, QWidget *parent)
+TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, const QString &color, QWidget *parent)
: QWidget(parent)
{
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
@@ -58,7 +61,7 @@ TimelineItem::TimelineItem(ImageItem *image, const Event &event, const QString &
setLayout(top_layout_);
}
-TimelineItem::TimelineItem(ImageItem *image, const Event &event, QWidget *parent)
+TimelineItem::TimelineItem(ImageItem *image, const events::MessageEvent<msgs::Image> &event, QWidget *parent)
: QWidget(parent)
{
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
@@ -73,16 +76,31 @@ TimelineItem::TimelineItem(ImageItem *image, const Event &event, QWidget *parent
setLayout(top_layout_);
}
-TimelineItem::TimelineItem(const Event &event, bool with_sender, const QString &color, QWidget *parent)
+TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event, bool with_sender, const QString &color, QWidget *parent)
: QWidget(parent)
{
- auto body = event.content().value("body").toString().trimmed().toHtmlEscaped();
+ auto body = event.content().body().trimmed().toHtmlEscaped();
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
generateTimestamp(timestamp);
- if (event.content().value("msgtype").toString() == "m.notice")
- body = "<i style=\"color: #565E5E\">" + body + "</i>";
+ body = "<i style=\"color: #565E5E\">" + body + "</i>";
+
+ if (with_sender)
+ generateBody(event.sender(), color, body);
+ else
+ generateBody(body);
+
+ setupLayout();
+}
+
+TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event, bool with_sender, const QString &color, QWidget *parent)
+ : QWidget(parent)
+{
+ auto body = event.content().body().trimmed().toHtmlEscaped();
+ auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
+
+ generateTimestamp(timestamp);
if (with_sender)
generateBody(event.sender(), color, body);
diff --git a/src/TimelineView.cc b/src/TimelineView.cc
index 95c7a351..686fd602 100644
--- a/src/TimelineView.cc
+++ b/src/TimelineView.cc
@@ -16,17 +16,25 @@
*/
#include <QDebug>
+#include <QJsonArray>
#include <QScrollBar>
#include <QSettings>
#include <QtWidgets/QLabel>
#include <QtWidgets/QSpacerItem>
+#include "Event.h"
+#include "MessageEvent.h"
+#include "MessageEventContent.h"
+
#include "ImageItem.h"
#include "TimelineItem.h"
#include "TimelineView.h"
#include "TimelineViewManager.h"
-TimelineView::TimelineView(const QList<Event> &events, QSharedPointer<MatrixClient> client, QWidget *parent)
+namespace events = matrix::events;
+namespace msgs = matrix::events::messages;
+
+TimelineView::TimelineView(const QJsonArray &events, QSharedPointer<MatrixClient> client, QWidget *parent)
: QWidget(parent)
, client_{client}
{
@@ -53,52 +61,79 @@ void TimelineView::sliderRangeChanged(int min, int max)
scroll_area_->verticalScrollBar()->setValue(max);
}
-int TimelineView::addEvents(const QList<Event> &events)
+int TimelineView::addEvents(const QJsonArray &events)
{
QSettings settings;
auto local_user = settings.value("auth/user_id").toString();
int message_count = 0;
+ events::EventType ty;
for (const auto &event : events) {
- if (event.type() == "m.room.message") {
- auto msg_type = event.content().value("msgtype").toString();
+ ty = events::extractEventType(event.toObject());
- if (isPendingMessage(event, local_user)) {
- removePendingMessage(event);
- continue;
- }
+ if (ty == events::RoomMessage) {
+ events::MessageEventType msg_type = events::extractMessageEventType(event.toObject());
- if (msg_type == "m.text" || msg_type == "m.notice") {
- auto with_sender = last_sender_ != event.sender();
- auto color = TimelineViewManager::getUserColor(event.sender());
+ if (msg_type == events::MessageEventType::Text) {
+ events::MessageEvent<msgs::Text> text;
- addHistoryItem(event, color, with_sender);
- last_sender_ = event.sender();
+ try {
+ text.deserialize(event.toObject());
+ } catch (const DeserializationException &e) {
+ qWarning() << e.what() << event;
+ continue;
+ }
- message_count += 1;
- } else if (msg_type == "m.image") {
- // TODO: Move this into serialization.
- if (!event.content().contains("url")) {
- qWarning() << "Missing url from m.image event" << event.content();
+ if (isPendingMessage(text, local_user)) {
+ removePendingMessage(text);
continue;
}
- if (!event.content().contains("body")) {
- qWarning() << "Missing body from m.image event" << event.content();
+ auto with_sender = last_sender_ != text.sender();
+ auto color = TimelineViewManager::getUserColor(text.sender());
+
+ addHistoryItem(text, color, with_sender);
+ last_sender_ = text.sender();
+
+ message_count += 1;
+ } else if (msg_type == events::MessageEventType::Notice) {
+ events::MessageEvent<msgs::Notice> notice;
+
+ try {
+ notice.deserialize(event.toObject());
+ } catch (const DeserializationException &e) {
+ qWarning() << e.what() << event;
continue;
}
- QUrl url(event.content().value("url").toString());
- QString body(event.content().value("body").toString());
+ auto with_sender = last_sender_ != notice.sender();
+ auto color = TimelineViewManager::getUserColor(notice.sender());
- auto with_sender = last_sender_ != event.sender();
- auto color = TimelineViewManager::getUserColor(event.sender());
+ addHistoryItem(notice, color, with_sender);
+ last_sender_ = notice.sender();
- addImageItem(body, url, event, color, with_sender);
+ message_count += 1;
+ } else if (msg_type == events::MessageEventType::Image) {
+ events::MessageEvent<msgs::Image> img;
- last_sender_ = event.sender();
+ try {
+ img.deserialize(event.toObject());
+ } catch (const DeserializationException &e) {
+ qWarning() << e.what() << event;
+ continue;
+ }
+
+ auto with_sender = last_sender_ != img.sender();
+ auto color = TimelineViewManager::getUserColor(img.sender());
+
+ addHistoryItem(img, color, with_sender);
+
+ last_sender_ = img.sender();
message_count += 1;
+ } else if (msg_type == events::MessageEventType::Unknown) {
+ qWarning() << "Unknown message type" << event.toObject();
+ continue;
}
}
}
@@ -136,13 +171,9 @@ void TimelineView::init()
SLOT(sliderRangeChanged(int, int)));
}
-void TimelineView::addImageItem(const QString &body,
- const QUrl &url,
- const Event &event,
- const QString &color,
- bool with_sender)
+void TimelineView::addHistoryItem(const events::MessageEvent<msgs::Image> &event, const QString &color, bool with_sender)
{
- auto image = new ImageItem(client_, event, body, url);
+ auto image = new ImageItem(client_, event);
if (with_sender) {
auto item = new TimelineItem(image, event, color, scroll_widget_);
@@ -153,7 +184,13 @@ void TimelineView::addImageItem(const QString &body,
}
}
-void TimelineView::addHistoryItem(const Event &event, const QString &color, bool with_sender)
+void TimelineView::addHistoryItem(const events::MessageEvent<msgs::Notice> &event, const QString &color, bool with_sender)
+{
+ TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_);
+ scroll_layout_->addWidget(item);
+}
+
+void TimelineView::addHistoryItem(const events::MessageEvent<msgs::Text> &event, const QString &color, bool with_sender)
{
TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_);
scroll_layout_->addWidget(item);
@@ -169,34 +206,25 @@ void TimelineView::updatePendingMessage(int txn_id, QString event_id)
}
}
-bool TimelineView::isPendingMessage(const Event &event, const QString &userid)
+bool TimelineView::isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &local_userid)
{
- if (event.sender() != userid || event.type() != "m.room.message")
- return false;
-
- auto msgtype = event.content().value("msgtype").toString();
- auto body = event.content().value("body").toString();
-
- // FIXME: should contain more checks later on for other types of messages.
- if (msgtype != "m.text")
+ if (e.sender() != local_userid)
return false;
for (const auto &msg : pending_msgs_) {
- if (msg.event_id == event.eventId() || msg.body == body)
+ if (msg.event_id == e.eventId() || msg.body == e.content().body())
return true;
}
return false;
}
-void TimelineView::removePendingMessage(const Event &event)
+void TimelineView::removePendingMessage(const events::MessageEvent<msgs::Text> &e)
{
- auto body = event.content().value("body").toString();
-
for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) {
int index = std::distance(pending_msgs_.begin(), it);
- if (it->event_id == event.eventId() || it->body == body) {
+ if (it->event_id == e.eventId() || it->body == e.content().body()) {
pending_msgs_.removeAt(index);
break;
}
diff --git a/src/TimelineViewManager.cc b/src/TimelineViewManager.cc
index ddb142d3..bf3dd997 100644
--- a/src/TimelineViewManager.cc
+++ b/src/TimelineViewManager.cc
@@ -54,11 +54,11 @@ void TimelineViewManager::messageSent(const QString &event_id, const QString &ro
void TimelineViewManager::sendTextMessage(const QString &msg)
{
- auto room = active_room_;
- auto view = views_[room.id()];
+ auto room_id = active_room_;
+ auto view = views_[room_id];
view->addUserTextMessage(msg, client_->transactionId());
- client_->sendTextMessage(room.id(), msg);
+ client_->sendTextMessage(room_id, msg);
}
void TimelineViewManager::clearAll()
@@ -95,7 +95,7 @@ void TimelineViewManager::sync(const Rooms &rooms)
auto roomid = it.key();
if (!views_.contains(roomid)) {
- qDebug() << "Ignoring event from unknown room";
+ qDebug() << "Ignoring event from unknown room" << roomid;
continue;
}
@@ -105,26 +105,25 @@ void TimelineViewManager::sync(const Rooms &rooms)
int msgs_added = view->addEvents(events);
if (msgs_added > 0) {
- // TODO: When window gets active the current
+ // TODO: When the app window gets active the current
// unread count (if any) should be cleared.
auto isAppActive = QApplication::activeWindow() != nullptr;
- if (roomid != active_room_.id() || !isAppActive)
+ if (roomid != active_room_ || !isAppActive)
emit unreadMessages(roomid, msgs_added);
}
}
}
-void TimelineViewManager::setHistoryView(const RoomInfo &info)
+void TimelineViewManager::setHistoryView(const QString &room_id)
{
- if (!views_.contains(info.id())) {
- qDebug() << "Room List id is not present in view manager";
- qDebug() << info.name();
+ if (!views_.contains(room_id)) {
+ qDebug() << "Room ID from RoomList is not present in ViewManager" << room_id;
return;
}
- active_room_ = info;
- auto widget = views_.value(info.id());
+ active_room_ = room_id;
+ auto widget = views_.value(room_id);
setCurrentWidget(widget);
}
diff --git a/src/events/Event.cc b/src/events/Event.cc
index 9a8590e0..da4f3e99 100644
--- a/src/events/Event.cc
+++ b/src/events/Event.cc
@@ -50,6 +50,8 @@ matrix::events::EventType matrix::events::extractEventType(const QJsonObject &ob
return EventType::RoomJoinRules;
else if (type == "m.room.member")
return EventType::RoomMember;
+ else if (type == "m.room.message")
+ return EventType::RoomMessage;
else if (type == "m.room.name")
return EventType::RoomName;
else if (type == "m.room.power_levels")
@@ -59,3 +61,22 @@ matrix::events::EventType matrix::events::extractEventType(const QJsonObject &ob
else
return EventType::Unsupported;
}
+
+bool matrix::events::isStateEvent(EventType type)
+{
+ return type == EventType::RoomAliases ||
+ type == EventType::RoomAvatar ||
+ type == EventType::RoomCanonicalAlias ||
+ type == EventType::RoomCreate ||
+ type == EventType::RoomHistoryVisibility ||
+ type == EventType::RoomJoinRules ||
+ type == EventType::RoomMember ||
+ type == EventType::RoomName ||
+ type == EventType::RoomPowerLevels ||
+ type == EventType::RoomTopic;
+}
+
+bool matrix::events::isMessageEvent(EventType type)
+{
+ return type == EventType::RoomMessage;
+}
diff --git a/src/events/MessageEventContent.cc b/src/events/MessageEventContent.cc
new file mode 100644
index 00000000..df2c39e8
--- /dev/null
+++ b/src/events/MessageEventContent.cc
@@ -0,0 +1,63 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QDebug>
+
+#include "MessageEventContent.h"
+
+using namespace matrix::events;
+
+MessageEventType matrix::events::extractMessageEventType(const QJsonObject &data)
+{
+ if (!data.contains("content"))
+ return MessageEventType::Unknown;
+
+ auto content = data.value("content").toObject();
+ auto msgtype = content.value("msgtype").toString();
+
+ if (msgtype == "m.audio")
+ return MessageEventType::Audio;
+ else if (msgtype == "m.emote")
+ return MessageEventType::Emote;
+ else if (msgtype == "m.file")
+ return MessageEventType::File;
+ else if (msgtype == "m.image")
+ return MessageEventType::Image;
+ else if (msgtype == "m.location")
+ return MessageEventType::Location;
+ else if (msgtype == "m.notice")
+ return MessageEventType::Notice;
+ else if (msgtype == "m.text")
+ return MessageEventType::Text;
+ else if (msgtype == "m.video")
+ return MessageEventType::Video;
+ else
+ return MessageEventType::Unknown;
+}
+
+void MessageEventContent::deserialize(const QJsonValue &data)
+{
+ if (!data.isObject())
+ throw DeserializationException("MessageEventContent is not a JSON object");
+
+ auto object = data.toObject();
+
+ if (!object.contains("body"))
+ throw DeserializationException("body key is missing");
+
+ body_ = object.value("body").toString();
+}
diff --git a/src/RoomInfo.cc b/src/events/messages/Audio.cc
index f8a7c56a..f0fb443b 100644
--- a/src/RoomInfo.cc
+++ b/src/events/messages/Audio.cc
@@ -15,57 +15,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "RoomInfo.h"
+#include "Audio.h"
-RoomInfo::RoomInfo()
- : name_("")
- , topic_("")
-{
-}
-
-RoomInfo::RoomInfo(QString name, QString topic, QUrl avatar_url)
- : name_(name)
- , topic_(topic)
- , avatar_url_(avatar_url)
-{
-}
-
-QString RoomInfo::id() const
-{
- return id_;
-}
-
-QString RoomInfo::name() const
-{
- return name_;
-}
+using namespace matrix::events::messages;
-QString RoomInfo::topic() const
+void Audio::deserialize(const QJsonObject &object)
{
- return topic_;
-}
+ if (!object.contains("url"))
+ throw DeserializationException("url key is missing");
-QUrl RoomInfo::avatarUrl() const
-{
- return avatar_url_;
-}
+ url_ = object.value("url").toString();
-void RoomInfo::setAvatarUrl(const QUrl &url)
-{
- avatar_url_ = url;
-}
+ if (object.value("msgtype") != "m.audio")
+ throw DeserializationException("invalid msgtype for audio");
-void RoomInfo::setId(const QString &id)
-{
- id_ = id;
-}
+ if (object.contains("info")) {
+ auto info = object.value("info").toObject();
-void RoomInfo::setName(const QString &name)
-{
- name_ = name;
-}
-
-void RoomInfo::setTopic(const QString &topic)
-{
- topic_ = topic;
+ info_.duration = info.value("duration").toInt();
+ info_.mimetype = info.value("mimetype").toString();
+ info_.size = info.value("size").toInt();
+ }
}
diff --git a/src/events/messages/Emote.cc b/src/events/messages/Emote.cc
new file mode 100644
index 00000000..1d6a4753
--- /dev/null
+++ b/src/events/messages/Emote.cc
@@ -0,0 +1,26 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Emote.h"
+
+using namespace matrix::events::messages;
+
+void Emote::deserialize(const QJsonObject &object)
+{
+ if (object.value("msgtype") != "m.emote")
+ throw DeserializationException("invalid msgtype for emote");
+}
diff --git a/src/events/messages/File.cc b/src/events/messages/File.cc
new file mode 100644
index 00000000..a6b5b6c2
--- /dev/null
+++ b/src/events/messages/File.cc
@@ -0,0 +1,51 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "File.h"
+
+using namespace matrix::events::messages;
+
+void File::deserialize(const QJsonObject &object)
+{
+ if (!object.contains("url"))
+ throw DeserializationException("messages::File url key is missing");
+
+ if (!object.contains("filename"))
+ throw DeserializationException("messages::File filename key is missing");
+
+ if (object.value("msgtype") != "m.file")
+ throw DeserializationException("invalid msgtype for file");
+
+ url_ = object.value("url").toString();
+
+ if (object.contains("info")) {
+ auto file_info = object.value("info").toObject();
+
+ info_.size = file_info.value("size").toInt();
+ info_.mimetype = file_info.value("mimetype").toString();
+ info_.thumbnail_url = file_info.value("thumbnail_url").toString();
+
+ if (file_info.contains("thumbnail_info")) {
+ auto thumbinfo = file_info.value("thumbnail_info").toObject();
+
+ info_.thumbnail_info.h = thumbinfo.value("h").toInt();
+ info_.thumbnail_info.w = thumbinfo.value("w").toInt();
+ info_.thumbnail_info.size = thumbinfo.value("size").toInt();
+ info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString();
+ }
+ }
+}
diff --git a/src/events/messages/Image.cc b/src/events/messages/Image.cc
new file mode 100644
index 00000000..d528e174
--- /dev/null
+++ b/src/events/messages/Image.cc
@@ -0,0 +1,51 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Image.h"
+
+using namespace matrix::events::messages;
+
+void Image::deserialize(const QJsonObject &object)
+{
+ if (!object.contains("url"))
+ throw DeserializationException("messages::Image url key is missing");
+
+ url_ = object.value("url").toString();
+
+ if (object.value("msgtype") != "m.image")
+ throw DeserializationException("invalid msgtype for image");
+
+ if (object.contains("info")) {
+ auto imginfo = object.value("info").toObject();
+
+ info_.w = imginfo.value("w").toInt();
+ info_.h = imginfo.value("h").toInt();
+ info_.size = imginfo.value("size").toInt();
+
+ info_.mimetype = imginfo.value("mimetype").toString();
+ info_.thumbnail_url = imginfo.value("thumbnail_url").toString();
+
+ if (imginfo.contains("thumbnail_info")) {
+ auto thumbinfo = imginfo.value("thumbnail_info").toObject();
+
+ info_.thumbnail_info.h = thumbinfo.value("h").toInt();
+ info_.thumbnail_info.w = thumbinfo.value("w").toInt();
+ info_.thumbnail_info.size = thumbinfo.value("size").toInt();
+ info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString();
+ }
+ }
+}
diff --git a/src/events/messages/Location.cc b/src/events/messages/Location.cc
new file mode 100644
index 00000000..68a9a9c1
--- /dev/null
+++ b/src/events/messages/Location.cc
@@ -0,0 +1,46 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Location.h"
+
+using namespace matrix::events::messages;
+
+void Location::deserialize(const QJsonObject &object)
+{
+ if (!object.contains("geo_uri"))
+ throw DeserializationException("messages::Location geo_uri key is missing");
+
+ if (object.value("msgtype") != "m.location")
+ throw DeserializationException("invalid msgtype for location");
+
+ geo_uri_ = object.value("geo_uri").toString();
+
+ if (object.contains("info")) {
+ auto location_info = object.value("info").toObject();
+
+ info_.thumbnail_url = location_info.value("thumbnail_url").toString();
+
+ if (location_info.contains("thumbnail_info")) {
+ auto thumbinfo = location_info.value("thumbnail_info").toObject();
+
+ info_.thumbnail_info.h = thumbinfo.value("h").toInt();
+ info_.thumbnail_info.w = thumbinfo.value("w").toInt();
+ info_.thumbnail_info.size = thumbinfo.value("size").toInt();
+ info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString();
+ }
+ }
+}
diff --git a/src/events/messages/Notice.cc b/src/events/messages/Notice.cc
new file mode 100644
index 00000000..1dd4cc28
--- /dev/null
+++ b/src/events/messages/Notice.cc
@@ -0,0 +1,26 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Notice.h"
+
+using namespace matrix::events::messages;
+
+void Notice::deserialize(const QJsonObject &object)
+{
+ if (object.value("msgtype") != "m.notice")
+ throw DeserializationException("invalid msgtype for notice");
+}
diff --git a/src/events/messages/Text.cc b/src/events/messages/Text.cc
new file mode 100644
index 00000000..5446d7f4
--- /dev/null
+++ b/src/events/messages/Text.cc
@@ -0,0 +1,26 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Text.h"
+
+using namespace matrix::events::messages;
+
+void Text::deserialize(const QJsonObject &object)
+{
+ if (object.value("msgtype") != "m.text")
+ throw DeserializationException("invalid msgtype for text");
+}
diff --git a/src/events/messages/Video.cc b/src/events/messages/Video.cc
new file mode 100644
index 00000000..a7ddba96
--- /dev/null
+++ b/src/events/messages/Video.cc
@@ -0,0 +1,52 @@
+/*
+ * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Video.h"
+
+using namespace matrix::events::messages;
+
+void Video::deserialize(const QJsonObject &object)
+{
+ if (!object.contains("url"))
+ throw DeserializationException("messages::Video url key is missing");
+
+ url_ = object.value("url").toString();
+
+ if (object.value("msgtype") != "m.video")
+ throw DeserializationException("invalid msgtype for video");
+
+ if (object.contains("info")) {
+ auto video_info = object.value("info").toObject();
+
+ info_.w = video_info.value("w").toInt();
+ info_.h = video_info.value("h").toInt();
+ info_.size = video_info.value("size").toInt();
+ info_.duration = video_info.value("duration").toInt();
+
+ info_.mimetype = video_info.value("mimetype").toString();
+ info_.thumbnail_url = video_info.value("thumbnail_url").toString();
+
+ if (video_info.contains("thumbnail_info")) {
+ auto thumbinfo = video_info.value("thumbnail_info").toObject();
+
+ info_.thumbnail_info.h = thumbinfo.value("h").toInt();
+ info_.thumbnail_info.w = thumbinfo.value("w").toInt();
+ info_.thumbnail_info.size = thumbinfo.value("size").toInt();
+ info_.thumbnail_info.mimetype = thumbinfo.value("mimetype").toString();
+ }
+ }
+}
|