mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-10-30 09:30:47 +03:00
Use timeline to retrieve state events
- Rooms without any history will be shown. - Room's state will be kept in sync and any updates will be visible.
This commit is contained in:
parent
8825e072f2
commit
1f90c58076
45 changed files with 1922 additions and 303 deletions
|
@ -89,9 +89,9 @@ set(SRC_FILES
|
|||
src/MainWindow.cc
|
||||
src/MatrixClient.cc
|
||||
src/Profile.cc
|
||||
src/RoomInfo.cc
|
||||
src/RoomInfoListItem.cc
|
||||
src/RoomList.cc
|
||||
src/RoomState.cc
|
||||
src/Register.cc
|
||||
src/RegisterPage.cc
|
||||
src/SlidingStackWidget.cc
|
||||
|
@ -126,14 +126,25 @@ set(MATRIX_EVENTS
|
|||
src/events/HistoryVisibilityEventContent.cc
|
||||
src/events/JoinRulesEventContent.cc
|
||||
src/events/MemberEventContent.cc
|
||||
src/events/MessageEventContent.cc
|
||||
src/events/NameEventContent.cc
|
||||
src/events/PowerLevelsEventContent.cc
|
||||
src/events/TopicEventContent.cc
|
||||
|
||||
src/events/messages/Audio.cc
|
||||
src/events/messages/Emote.cc
|
||||
src/events/messages/File.cc
|
||||
src/events/messages/Image.cc
|
||||
src/events/messages/Location.cc
|
||||
src/events/messages/Notice.cc
|
||||
src/events/messages/Text.cc
|
||||
src/events/messages/Video.cc
|
||||
)
|
||||
|
||||
include_directories(include)
|
||||
include_directories(include/ui)
|
||||
include_directories(include/events)
|
||||
include_directories(include/events/messages)
|
||||
|
||||
qt5_wrap_ui (UI_HEADERS
|
||||
forms/ChatPage.ui
|
||||
|
@ -191,7 +202,15 @@ if (BUILD_TESTS)
|
|||
add_executable(events_test tests/events.cc)
|
||||
target_link_libraries(events_test matrix_events ${GTEST_BOTH_LIBRARIES})
|
||||
|
||||
add_executable(event_collection_test tests/event_collection.cc)
|
||||
target_link_libraries(event_collection_test matrix_events ${GTEST_BOTH_LIBRARIES})
|
||||
|
||||
add_executable(message_events tests/message_events.cc)
|
||||
target_link_libraries(message_events matrix_events ${GTEST_BOTH_LIBRARIES})
|
||||
|
||||
add_test(MatrixEvents events_test)
|
||||
add_test(MatrixEventCollection event_collection_test)
|
||||
add_test(MatrixMessageEvents message_events)
|
||||
else()
|
||||
add_executable (nheko ${OS_BUNDLE} ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC})
|
||||
target_link_libraries (nheko matrix_events Qt5::Widgets Qt5::Network)
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "MatrixClient.h"
|
||||
#include "RoomInfo.h"
|
||||
#include "RoomList.h"
|
||||
#include "RoomState.h"
|
||||
#include "TextInputWidget.h"
|
||||
#include "TimelineViewManager.h"
|
||||
#include "TopRoomBar.h"
|
||||
|
@ -58,11 +58,13 @@ private slots:
|
|||
void initialSyncCompleted(const SyncResponse &response);
|
||||
void syncCompleted(const SyncResponse &response);
|
||||
void syncFailed(const QString &msg);
|
||||
void changeTopRoomInfo(const RoomInfo &info);
|
||||
void changeTopRoomInfo(const QString &room_id);
|
||||
void startSync();
|
||||
void logout();
|
||||
|
||||
private:
|
||||
void updateRoomState(RoomState &room_state, const QJsonArray &events);
|
||||
|
||||
Ui::ChatPage *ui;
|
||||
|
||||
RoomList *room_list_;
|
||||
|
@ -74,11 +76,13 @@ private:
|
|||
QTimer *sync_timer_;
|
||||
int sync_interval_;
|
||||
|
||||
RoomInfo current_room_;
|
||||
QString current_room_;
|
||||
QMap<QString, QPixmap> room_avatars_;
|
||||
|
||||
UserInfoWidget *user_info_widget_;
|
||||
|
||||
QMap<QString, RoomState> state_manager_;
|
||||
|
||||
// Matrix Client API provider.
|
||||
QSharedPointer<MatrixClient> client_;
|
||||
};
|
||||
|
|
|
@ -23,16 +23,18 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Image.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
namespace events = matrix::events;
|
||||
namespace msgs = matrix::events::messages;
|
||||
|
||||
class ImageItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImageItem(QSharedPointer<MatrixClient> client,
|
||||
const Event &event,
|
||||
const QString &body,
|
||||
const QUrl &url,
|
||||
const events::MessageEvent<msgs::Image> &event,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
void setImage(const QPixmap &image);
|
||||
|
@ -65,7 +67,7 @@ private:
|
|||
|
||||
int bottom_height_ = 30;
|
||||
|
||||
Event event_;
|
||||
events::MessageEvent<msgs::Image> event_;
|
||||
|
||||
QSharedPointer<MatrixClient> client_;
|
||||
};
|
||||
|
|
|
@ -26,26 +26,27 @@
|
|||
#include "Avatar.h"
|
||||
#include "Badge.h"
|
||||
#include "RippleOverlay.h"
|
||||
#include "RoomInfo.h"
|
||||
#include "RoomState.h"
|
||||
|
||||
class RoomInfoListItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RoomInfoListItem(RoomInfo info, QWidget *parent = 0);
|
||||
RoomInfoListItem(RoomState state, QString room_id, QWidget *parent = 0);
|
||||
~RoomInfoListItem();
|
||||
|
||||
void updateUnreadMessageCount(int count);
|
||||
void clearUnreadMessageCount();
|
||||
void setState(const RoomState &state);
|
||||
|
||||
inline bool isPressed();
|
||||
inline RoomInfo info();
|
||||
inline bool isPressed() const;
|
||||
inline RoomState state() const;
|
||||
inline void setAvatar(const QImage &avatar_image);
|
||||
inline int unreadMessageCount();
|
||||
inline int unreadMessageCount() const;
|
||||
|
||||
signals:
|
||||
void clicked(const RoomInfo &info_);
|
||||
void clicked(const QString &room_id);
|
||||
|
||||
public slots:
|
||||
void setPressedState(bool state);
|
||||
|
@ -58,7 +59,8 @@ private:
|
|||
|
||||
RippleOverlay *ripple_overlay_;
|
||||
|
||||
RoomInfo info_;
|
||||
RoomState state_;
|
||||
QString room_id_;
|
||||
|
||||
QHBoxLayout *topLayout_;
|
||||
|
||||
|
@ -83,19 +85,19 @@ private:
|
|||
int unread_msg_count_;
|
||||
};
|
||||
|
||||
inline int RoomInfoListItem::unreadMessageCount()
|
||||
inline int RoomInfoListItem::unreadMessageCount() const
|
||||
{
|
||||
return unread_msg_count_;
|
||||
}
|
||||
|
||||
inline bool RoomInfoListItem::isPressed()
|
||||
inline bool RoomInfoListItem::isPressed() const
|
||||
{
|
||||
return is_pressed_;
|
||||
}
|
||||
|
||||
inline RoomInfo RoomInfoListItem::info()
|
||||
inline RoomState RoomInfoListItem::state() const
|
||||
{
|
||||
return info_;
|
||||
return state_;
|
||||
}
|
||||
|
||||
inline void RoomInfoListItem::setAvatar(const QImage &avatar_image)
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "MatrixClient.h"
|
||||
#include "RoomInfo.h"
|
||||
#include "RoomInfoListItem.h"
|
||||
#include "RoomState.h"
|
||||
#include "Sync.h"
|
||||
|
||||
namespace Ui
|
||||
|
@ -41,18 +41,18 @@ public:
|
|||
RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
||||
~RoomList();
|
||||
|
||||
void setInitialRooms(const Rooms &rooms);
|
||||
void setInitialRooms(const QMap<QString, RoomState> &states);
|
||||
void sync(const QMap<QString, RoomState> &states);
|
||||
|
||||
void clear();
|
||||
|
||||
RoomInfo extractRoomInfo(const State &room_state);
|
||||
|
||||
signals:
|
||||
void roomChanged(const RoomInfo &info);
|
||||
void roomChanged(const QString &room_id);
|
||||
void totalUnreadMessageCountUpdated(int count);
|
||||
|
||||
public slots:
|
||||
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
|
||||
void highlightSelectedRoom(const RoomInfo &info);
|
||||
void highlightSelectedRoom(const QString &room_id);
|
||||
void updateUnreadMessageCount(const QString &roomid, int count);
|
||||
|
||||
private:
|
||||
|
|
63
include/RoomState.h
Normal file
63
include/RoomState.h
Normal file
|
@ -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/>.
|
||||
*/
|
||||
|
||||
#ifndef ROOM_STATE_H
|
||||
#define ROOM_STATE_H
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
#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 "Event.h"
|
||||
#include "RoomEvent.h"
|
||||
#include "StateEvent.h"
|
||||
|
||||
namespace events = matrix::events;
|
||||
|
||||
class RoomState
|
||||
{
|
||||
public:
|
||||
QString resolveName() const;
|
||||
inline QString resolveTopic() const;
|
||||
|
||||
QPixmap avatar_img_;
|
||||
|
||||
events::StateEvent<events::AliasesEventContent> aliases;
|
||||
events::StateEvent<events::AvatarEventContent> avatar;
|
||||
events::StateEvent<events::CanonicalAliasEventContent> canonical_alias;
|
||||
events::StateEvent<events::CreateEventContent> create;
|
||||
events::StateEvent<events::HistoryVisibilityEventContent> history_visibility;
|
||||
events::StateEvent<events::JoinRulesEventContent> join_rules;
|
||||
events::StateEvent<events::NameEventContent> name;
|
||||
events::StateEvent<events::PowerLevelsEventContent> power_levels;
|
||||
events::StateEvent<events::TopicEventContent> topic;
|
||||
};
|
||||
|
||||
inline QString RoomState::resolveTopic() const
|
||||
{
|
||||
return topic.content().topic().simplified();
|
||||
}
|
||||
|
||||
#endif // ROOM_STATE_H
|
|
@ -18,6 +18,7 @@
|
|||
#ifndef SYNC_H
|
||||
#define SYNC_H
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
@ -90,13 +91,13 @@ class State : public Deserializable
|
|||
{
|
||||
public:
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
inline QList<Event> events() const;
|
||||
inline QJsonArray events() const;
|
||||
|
||||
private:
|
||||
QList<Event> events_;
|
||||
QJsonArray events_;
|
||||
};
|
||||
|
||||
inline QList<Event> State::events() const
|
||||
inline QJsonArray State::events() const
|
||||
{
|
||||
return events_;
|
||||
}
|
||||
|
@ -104,19 +105,19 @@ inline QList<Event> State::events() const
|
|||
class Timeline : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QList<Event> events() const;
|
||||
inline QJsonArray events() const;
|
||||
inline QString previousBatch() const;
|
||||
inline bool limited() const;
|
||||
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
|
||||
private:
|
||||
QList<Event> events_;
|
||||
QJsonArray events_;
|
||||
QString prev_batch_;
|
||||
bool limited_;
|
||||
};
|
||||
|
||||
inline QList<Event> Timeline::events() const
|
||||
inline QJsonArray Timeline::events() const
|
||||
{
|
||||
return events_;
|
||||
}
|
||||
|
|
|
@ -25,20 +25,27 @@
|
|||
#include "ImageItem.h"
|
||||
#include "Sync.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "MessageEvent.h"
|
||||
#include "Notice.h"
|
||||
#include "Text.h"
|
||||
|
||||
namespace events = matrix::events;
|
||||
namespace msgs = matrix::events::messages;
|
||||
|
||||
class TimelineItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// For remote messages.
|
||||
TimelineItem(const Event &event, bool with_sender, const QString &color, QWidget *parent = 0);
|
||||
TimelineItem(const events::MessageEvent<msgs::Notice> &e, bool with_sender, const QString &color, QWidget *parent = 0);
|
||||
TimelineItem(const events::MessageEvent<msgs::Text> &e, bool with_sender, const QString &color, QWidget *parent = 0);
|
||||
|
||||
// For local messages.
|
||||
TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent = 0);
|
||||
TimelineItem(const QString &body, QWidget *parent = 0);
|
||||
|
||||
// For inline images.
|
||||
TimelineItem(ImageItem *image, const Event &event, const QString &color, QWidget *parent);
|
||||
TimelineItem(ImageItem *image, const Event &event, QWidget *parent);
|
||||
TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, const QString &color, QWidget *parent);
|
||||
TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, QWidget *parent);
|
||||
|
||||
~TimelineItem();
|
||||
|
||||
|
|
|
@ -27,6 +27,13 @@
|
|||
#include "Sync.h"
|
||||
#include "TimelineItem.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "Notice.h"
|
||||
#include "Text.h"
|
||||
|
||||
namespace msgs = matrix::events::messages;
|
||||
namespace events = matrix::events;
|
||||
|
||||
// Contains info about a message shown in the history view
|
||||
// but not yet confirmed by the homeserver through sync.
|
||||
struct PendingMessage {
|
||||
|
@ -50,13 +57,14 @@ class TimelineView : public QWidget
|
|||
|
||||
public:
|
||||
TimelineView(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
||||
TimelineView(const QList<Event> &events, QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
||||
TimelineView(const QJsonArray &events, QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
||||
~TimelineView();
|
||||
|
||||
// FIXME: Reduce the parameters
|
||||
void addHistoryItem(const Event &event, const QString &color, bool with_sender);
|
||||
void addImageItem(const QString &body, const QUrl &url, const Event &event, const QString &color, bool with_sender);
|
||||
int addEvents(const QList<Event> &events);
|
||||
void addHistoryItem(const events::MessageEvent<msgs::Image> &e, const QString &color, bool with_sender);
|
||||
void addHistoryItem(const events::MessageEvent<msgs::Notice> &e, const QString &color, bool with_sender);
|
||||
void addHistoryItem(const events::MessageEvent<msgs::Text> &e, const QString &color, bool with_sender);
|
||||
|
||||
int addEvents(const QJsonArray &events);
|
||||
void addUserTextMessage(const QString &msg, int txn_id);
|
||||
void updatePendingMessage(int txn_id, QString event_id);
|
||||
void clear();
|
||||
|
@ -66,8 +74,8 @@ public slots:
|
|||
|
||||
private:
|
||||
void init();
|
||||
void removePendingMessage(const Event &event);
|
||||
bool isPendingMessage(const Event &event, const QString &userid);
|
||||
void removePendingMessage(const events::MessageEvent<msgs::Text> &e);
|
||||
bool isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &userid);
|
||||
|
||||
QVBoxLayout *top_layout_;
|
||||
QVBoxLayout *scroll_layout_;
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include "MatrixClient.h"
|
||||
#include "RoomInfo.h"
|
||||
#include "Sync.h"
|
||||
#include "TimelineView.h"
|
||||
|
||||
|
@ -48,14 +47,14 @@ signals:
|
|||
void unreadMessages(QString roomid, int count);
|
||||
|
||||
public slots:
|
||||
void setHistoryView(const RoomInfo &info);
|
||||
void setHistoryView(const QString &room_id);
|
||||
void sendTextMessage(const QString &msg);
|
||||
|
||||
private slots:
|
||||
void messageSent(const QString &eventid, const QString &roomid, int txnid);
|
||||
|
||||
private:
|
||||
RoomInfo active_room_;
|
||||
QString active_room_;
|
||||
QMap<QString, TimelineView *> views_;
|
||||
QSharedPointer<MatrixClient> client_;
|
||||
};
|
||||
|
|
|
@ -41,6 +41,8 @@ enum EventType {
|
|||
RoomJoinRules,
|
||||
/// m.room.member
|
||||
RoomMember,
|
||||
/// m.room.message
|
||||
RoomMessage,
|
||||
/// m.room.name
|
||||
RoomName,
|
||||
/// m.room.power_levels
|
||||
|
@ -53,6 +55,9 @@ enum EventType {
|
|||
|
||||
EventType extractEventType(const QJsonObject &data);
|
||||
|
||||
bool isMessageEvent(EventType type);
|
||||
bool isStateEvent(EventType type);
|
||||
|
||||
template <class Content>
|
||||
class Event : public Deserializable
|
||||
{
|
||||
|
|
67
include/events/MessageEvent.h
Normal file
67
include/events/MessageEvent.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MATRIX_MESSAGE_EVENT_H
|
||||
#define MATRIX_MESSAGE_EVENT_H
|
||||
|
||||
#include "MessageEventContent.h"
|
||||
#include "RoomEvent.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
template <class MsgContent>
|
||||
class MessageEvent : public RoomEvent<MessageEventContent>
|
||||
{
|
||||
public:
|
||||
inline MsgContent msgContent() const;
|
||||
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
|
||||
private:
|
||||
MsgContent msg_content_;
|
||||
};
|
||||
|
||||
template <class MsgContent>
|
||||
inline MsgContent MessageEvent<MsgContent>::msgContent() const
|
||||
{
|
||||
return msg_content_;
|
||||
}
|
||||
|
||||
template <class MsgContent>
|
||||
void MessageEvent<MsgContent>::deserialize(const QJsonValue &data)
|
||||
{
|
||||
RoomEvent<MessageEventContent>::deserialize(data);
|
||||
|
||||
msg_content_.deserialize(data.toObject().value("content").toObject());
|
||||
}
|
||||
|
||||
namespace messages
|
||||
{
|
||||
struct ThumbnailInfo {
|
||||
int h;
|
||||
int w;
|
||||
int size;
|
||||
|
||||
QString mimetype;
|
||||
};
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MATRIX_MESSAGE_EVENT_H
|
78
include/events/MessageEventContent.h
Normal file
78
include/events/MessageEventContent.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_CONTENT_H
|
||||
#define MESSAGE_EVENT_CONTENT_H
|
||||
|
||||
#include <QJsonValue>
|
||||
|
||||
#include "Deserializable.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
enum MessageEventType {
|
||||
// m.audio
|
||||
Audio,
|
||||
|
||||
// m.emote
|
||||
Emote,
|
||||
|
||||
// m.file
|
||||
File,
|
||||
|
||||
// m.image
|
||||
Image,
|
||||
|
||||
// m.location
|
||||
Location,
|
||||
|
||||
// m.notice
|
||||
Notice,
|
||||
|
||||
// m.text
|
||||
Text,
|
||||
|
||||
// m.video
|
||||
Video,
|
||||
|
||||
// Unrecognized message type
|
||||
Unknown,
|
||||
};
|
||||
|
||||
MessageEventType extractMessageEventType(const QJsonObject &data);
|
||||
|
||||
class MessageEventContent : public Deserializable
|
||||
{
|
||||
public:
|
||||
void deserialize(const QJsonValue &data) override;
|
||||
|
||||
inline QString body() const;
|
||||
|
||||
private:
|
||||
QString body_;
|
||||
};
|
||||
|
||||
inline QString MessageEventContent::body() const
|
||||
{
|
||||
return body_;
|
||||
}
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_CONTENT_H
|
|
@ -83,8 +83,9 @@ void RoomEvent<Content>::deserialize(const QJsonValue &data)
|
|||
if (!object.contains("origin_server_ts"))
|
||||
throw DeserializationException("origin_server_ts key is missing");
|
||||
|
||||
if (!object.contains("room_id"))
|
||||
throw DeserializationException("room_id key is missing");
|
||||
// FIXME: Synapse doesn't include room id?!
|
||||
/* if (!object.contains("room_id")) */
|
||||
/* throw DeserializationException("room_id key is missing"); */
|
||||
|
||||
if (!object.contains("sender"))
|
||||
throw DeserializationException("sender key is missing");
|
||||
|
|
|
@ -15,57 +15,51 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "RoomInfo.h"
|
||||
#ifndef MESSAGE_EVENT_AUDIO_H
|
||||
#define MESSAGE_EVENT_AUDIO_H
|
||||
|
||||
RoomInfo::RoomInfo()
|
||||
: name_("")
|
||||
, topic_("")
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
struct AudioInfo {
|
||||
uint64_t duration;
|
||||
int size;
|
||||
|
||||
QString mimetype;
|
||||
};
|
||||
|
||||
class Audio : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QString url() const;
|
||||
inline AudioInfo info() const;
|
||||
|
||||
void deserialize(const QJsonObject &object) override;
|
||||
|
||||
private:
|
||||
QString url_;
|
||||
AudioInfo info_;
|
||||
};
|
||||
|
||||
inline QString Audio::url() const
|
||||
{
|
||||
return url_;
|
||||
}
|
||||
|
||||
RoomInfo::RoomInfo(QString name, QString topic, QUrl avatar_url)
|
||||
: name_(name)
|
||||
, topic_(topic)
|
||||
, avatar_url_(avatar_url)
|
||||
inline AudioInfo Audio::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
QString RoomInfo::id() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
QString RoomInfo::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
QString RoomInfo::topic() const
|
||||
{
|
||||
return topic_;
|
||||
}
|
||||
|
||||
QUrl RoomInfo::avatarUrl() const
|
||||
{
|
||||
return avatar_url_;
|
||||
}
|
||||
|
||||
void RoomInfo::setAvatarUrl(const QUrl &url)
|
||||
{
|
||||
avatar_url_ = url;
|
||||
}
|
||||
|
||||
void RoomInfo::setId(const QString &id)
|
||||
{
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
void RoomInfo::setName(const QString &name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
void RoomInfo::setTopic(const QString &topic)
|
||||
{
|
||||
topic_ = topic;
|
||||
}
|
||||
#endif // MESSAGE_EVENT_AUDIO_H
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
||||
*
|
||||
|
@ -15,35 +16,26 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ROOM_INFO_H
|
||||
#define ROOM_INFO_H
|
||||
#ifndef MESSAGE_EVENT_EMOTE_H
|
||||
#define MESSAGE_EVENT_EMOTE_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QJsonObject>
|
||||
|
||||
class RoomInfo
|
||||
#include "Deserializable.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
class Emote : public Deserializable
|
||||
{
|
||||
public:
|
||||
RoomInfo();
|
||||
RoomInfo(QString name, QString topic = "", QUrl avatar_url = QUrl(""));
|
||||
|
||||
QString id() const;
|
||||
QString name() const;
|
||||
QString topic() const;
|
||||
QUrl avatarUrl() const;
|
||||
|
||||
void setAvatarUrl(const QUrl &url);
|
||||
void setId(const QString &id);
|
||||
void setName(const QString &name);
|
||||
void setTopic(const QString &name);
|
||||
|
||||
private:
|
||||
QString id_;
|
||||
QString name_;
|
||||
QString topic_;
|
||||
QUrl avatar_url_;
|
||||
QList<QString> aliases_;
|
||||
void deserialize(const QJsonObject &obj) override;
|
||||
};
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // ROOM_INFO_H
|
||||
#endif // MESSAGE_EVENT_EMOTE_H
|
76
include/events/messages/File.h
Normal file
76
include/events/messages/File.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_FILE_H
|
||||
#define MESSAGE_EVENT_FILE_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
#include "MessageEvent.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
struct FileInfo {
|
||||
int size;
|
||||
|
||||
QString mimetype;
|
||||
QString thumbnail_url;
|
||||
ThumbnailInfo thumbnail_info;
|
||||
};
|
||||
|
||||
class File : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QString url() const;
|
||||
inline QString filename() const;
|
||||
|
||||
inline FileInfo info() const;
|
||||
|
||||
void deserialize(const QJsonObject &object) override;
|
||||
|
||||
private:
|
||||
QString url_;
|
||||
QString filename_;
|
||||
|
||||
FileInfo info_;
|
||||
};
|
||||
|
||||
inline QString File::filename() const
|
||||
{
|
||||
return filename_;
|
||||
}
|
||||
|
||||
inline QString File::url() const
|
||||
{
|
||||
return url_;
|
||||
}
|
||||
|
||||
inline FileInfo File::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_FILE_H
|
69
include/events/messages/Image.h
Normal file
69
include/events/messages/Image.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_IMAGE_H
|
||||
#define MESSAGE_EVENT_IMAGE_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
#include "MessageEvent.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
struct ImageInfo {
|
||||
int h;
|
||||
int w;
|
||||
int size;
|
||||
|
||||
QString mimetype;
|
||||
QString thumbnail_url;
|
||||
ThumbnailInfo thumbnail_info;
|
||||
};
|
||||
|
||||
class Image : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QString url() const;
|
||||
inline ImageInfo info() const;
|
||||
|
||||
void deserialize(const QJsonObject &object) override;
|
||||
|
||||
private:
|
||||
QString url_;
|
||||
ImageInfo info_;
|
||||
};
|
||||
|
||||
inline QString Image::url() const
|
||||
{
|
||||
return url_;
|
||||
}
|
||||
|
||||
inline ImageInfo Image::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_IMAGE_H
|
65
include/events/messages/Location.h
Normal file
65
include/events/messages/Location.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_LOCATION_H
|
||||
#define MESSAGE_EVENT_LOCATION_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
#include "MessageEvent.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
struct LocationInfo {
|
||||
QString thumbnail_url;
|
||||
ThumbnailInfo thumbnail_info;
|
||||
};
|
||||
|
||||
class Location : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QString geoUri() const;
|
||||
inline LocationInfo info() const;
|
||||
|
||||
void deserialize(const QJsonObject &object) override;
|
||||
|
||||
private:
|
||||
QString geo_uri_;
|
||||
|
||||
LocationInfo info_;
|
||||
};
|
||||
|
||||
inline QString Location::geoUri() const
|
||||
{
|
||||
return geo_uri_;
|
||||
}
|
||||
|
||||
inline LocationInfo Location::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_LOCATION_H
|
40
include/events/messages/Notice.h
Normal file
40
include/events/messages/Notice.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_NOTICE_H
|
||||
#define MESSAGE_EVENT_NOTICE_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
class Notice : public Deserializable
|
||||
{
|
||||
public:
|
||||
void deserialize(const QJsonObject &obj) override;
|
||||
};
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_NOTICE_H
|
40
include/events/messages/Text.h
Normal file
40
include/events/messages/Text.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_TEXT_H
|
||||
#define MESSAGE_EVENT_TEXT_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
class Text : public Deserializable
|
||||
{
|
||||
public:
|
||||
void deserialize(const QJsonObject &obj) override;
|
||||
};
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_TEXT_H
|
70
include/events/messages/Video.h
Normal file
70
include/events/messages/Video.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MESSAGE_EVENT_VIDEO_H
|
||||
#define MESSAGE_EVENT_VIDEO_H
|
||||
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Deserializable.h"
|
||||
#include "MessageEvent.h"
|
||||
|
||||
namespace matrix
|
||||
{
|
||||
namespace events
|
||||
{
|
||||
namespace messages
|
||||
{
|
||||
struct VideoInfo {
|
||||
int h;
|
||||
int w;
|
||||
int size;
|
||||
int duration;
|
||||
|
||||
QString mimetype;
|
||||
QString thumbnail_url;
|
||||
ThumbnailInfo thumbnail_info;
|
||||
};
|
||||
|
||||
class Video : public Deserializable
|
||||
{
|
||||
public:
|
||||
inline QString url() const;
|
||||
inline VideoInfo info() const;
|
||||
|
||||
void deserialize(const QJsonObject &object) override;
|
||||
|
||||
private:
|
||||
QString url_;
|
||||
VideoInfo info_;
|
||||
};
|
||||
|
||||
inline QString Video::url() const
|
||||
{
|
||||
return url_;
|
||||
}
|
||||
|
||||
inline VideoInfo Video::info() const
|
||||
{
|
||||
return info_;
|
||||
}
|
||||
|
||||
} // namespace messages
|
||||
} // namespace events
|
||||
} // namespace matrix
|
||||
|
||||
#endif // MESSAGE_EVENT_VIDEO_H
|
160
src/ChatPage.cc
160
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;
|
||||
|
||||
if (room_avatars_.contains(info.id()))
|
||||
top_bar_->updateRoomAvatar(room_avatars_.value(info.id()).toImage());
|
||||
auto state = state_manager_[room_id];
|
||||
|
||||
top_bar_->updateRoomName(state.resolveName());
|
||||
top_bar_->updateRoomTopic(state.resolveTopic());
|
||||
|
||||
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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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::highlightSelectedRoom(const RoomInfo &info)
|
||||
void RoomList::sync(const QMap<QString, RoomState> &states)
|
||||
{
|
||||
emit roomChanged(info);
|
||||
for (auto it = states.constBegin(); it != states.constEnd(); it++) {
|
||||
auto room_id = it.key();
|
||||
auto state = it.value();
|
||||
|
||||
if (!rooms_.contains(info.id())) {
|
||||
// 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 QString &room_id)
|
||||
{
|
||||
emit roomChanged(room_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);
|
||||
}
|
||||
}
|
||||
|
|
32
src/RoomState.cc
Normal file
32
src/RoomState.cc
Normal file
|
@ -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";
|
||||
}
|
28
src/Sync.cc
28
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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,53 +61,80 @@ 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);
|
||||
if (ty == events::RoomMessage) {
|
||||
events::MessageEventType msg_type = events::extractMessageEventType(event.toObject());
|
||||
|
||||
if (msg_type == events::MessageEventType::Text) {
|
||||
events::MessageEvent<msgs::Text> text;
|
||||
|
||||
try {
|
||||
text.deserialize(event.toObject());
|
||||
} catch (const DeserializationException &e) {
|
||||
qWarning() << e.what() << event;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isPendingMessage(text, local_user)) {
|
||||
removePendingMessage(text);
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
auto with_sender = last_sender_ != notice.sender();
|
||||
auto color = TimelineViewManager::getUserColor(notice.sender());
|
||||
|
||||
addHistoryItem(notice, color, with_sender);
|
||||
last_sender_ = notice.sender();
|
||||
|
||||
message_count += 1;
|
||||
} else if (msg_type == events::MessageEventType::Image) {
|
||||
events::MessageEvent<msgs::Image> img;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (msg_type == "m.text" || msg_type == "m.notice") {
|
||||
auto with_sender = last_sender_ != event.sender();
|
||||
auto color = TimelineViewManager::getUserColor(event.sender());
|
||||
|
||||
addHistoryItem(event, color, with_sender);
|
||||
last_sender_ = event.sender();
|
||||
|
||||
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();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!event.content().contains("body")) {
|
||||
qWarning() << "Missing body from m.image event" << event.content();
|
||||
continue;
|
||||
}
|
||||
|
||||
QUrl url(event.content().value("url").toString());
|
||||
QString body(event.content().value("body").toString());
|
||||
|
||||
auto with_sender = last_sender_ != event.sender();
|
||||
auto color = TimelineViewManager::getUserColor(event.sender());
|
||||
|
||||
addImageItem(body, url, event, color, with_sender);
|
||||
|
||||
last_sender_ = event.sender();
|
||||
message_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
63
src/events/MessageEventContent.cc
Normal file
63
src/events/MessageEventContent.cc
Normal file
|
@ -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();
|
||||
}
|
39
src/events/messages/Audio.cc
Normal file
39
src/events/messages/Audio.cc
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 "Audio.h"
|
||||
|
||||
using namespace matrix::events::messages;
|
||||
|
||||
void Audio::deserialize(const QJsonObject &object)
|
||||
{
|
||||
if (!object.contains("url"))
|
||||
throw DeserializationException("url key is missing");
|
||||
|
||||
url_ = object.value("url").toString();
|
||||
|
||||
if (object.value("msgtype") != "m.audio")
|
||||
throw DeserializationException("invalid msgtype for audio");
|
||||
|
||||
if (object.contains("info")) {
|
||||
auto info = object.value("info").toObject();
|
||||
|
||||
info_.duration = info.value("duration").toInt();
|
||||
info_.mimetype = info.value("mimetype").toString();
|
||||
info_.size = info.value("size").toInt();
|
||||
}
|
||||
}
|
26
src/events/messages/Emote.cc
Normal file
26
src/events/messages/Emote.cc
Normal file
|
@ -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");
|
||||
}
|
51
src/events/messages/File.cc
Normal file
51
src/events/messages/File.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
51
src/events/messages/Image.cc
Normal file
51
src/events/messages/Image.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
46
src/events/messages/Location.cc
Normal file
46
src/events/messages/Location.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
26
src/events/messages/Notice.cc
Normal file
26
src/events/messages/Notice.cc
Normal file
|
@ -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");
|
||||
}
|
26
src/events/messages/Text.cc
Normal file
26
src/events/messages/Text.cc
Normal file
|
@ -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");
|
||||
}
|
52
src/events/messages/Video.cc
Normal file
52
src/events/messages/Video.cc
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
115
tests/event_collection.cc
Normal file
115
tests/event_collection.cc
Normal file
|
@ -0,0 +1,115 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "Event.h"
|
||||
#include "RoomEvent.h"
|
||||
#include "StateEvent.h"
|
||||
|
||||
#include "AliasesEventContent.h"
|
||||
#include "AvatarEventContent.h"
|
||||
#include "CanonicalAliasEventContent.h"
|
||||
#include "CreateEventContent.h"
|
||||
#include "HistoryVisibilityEventContent.h"
|
||||
#include "JoinRulesEventContent.h"
|
||||
#include "MemberEventContent.h"
|
||||
#include "NameEventContent.h"
|
||||
#include "PowerLevelsEventContent.h"
|
||||
#include "TopicEventContent.h"
|
||||
|
||||
using namespace matrix::events;
|
||||
|
||||
TEST(EventCollection, Deserialize)
|
||||
{
|
||||
auto events = QJsonArray{
|
||||
QJsonObject{
|
||||
{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"prev_content", QJsonObject{{"name", "Previous Name"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"state_key", ""},
|
||||
{"type", "m.room.name"}},
|
||||
QJsonObject{
|
||||
{"content", QJsonObject{{"topic", "Topic"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"prev_content", QJsonObject{{"topic", "Previous Topic"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"state_key", ""},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.topic"}},
|
||||
};
|
||||
|
||||
for (const auto &event : events) {
|
||||
EventType ty = extractEventType(event.toObject());
|
||||
|
||||
if (ty == EventType::RoomName) {
|
||||
StateEvent<NameEventContent> name_event;
|
||||
name_event.deserialize(event);
|
||||
|
||||
EXPECT_EQ(name_event.content().name(), "Name");
|
||||
EXPECT_EQ(name_event.previousContent().name(), "Previous Name");
|
||||
} else if (ty == EventType::RoomTopic) {
|
||||
StateEvent<TopicEventContent> topic_event;
|
||||
topic_event.deserialize(event);
|
||||
|
||||
EXPECT_EQ(topic_event.content().topic(), "Topic");
|
||||
EXPECT_EQ(topic_event.previousContent().topic(), "Previous Topic");
|
||||
} else {
|
||||
ASSERT_EQ(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EventCollection, DeserializationException)
|
||||
{
|
||||
// Using wrong event types.
|
||||
auto events = QJsonArray{
|
||||
QJsonObject{
|
||||
{"content", QJsonObject{{"name", "Name"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"prev_content", QJsonObject{{"name", "Previous Name"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"state_key", ""},
|
||||
{"type", "m.room.topic"}},
|
||||
QJsonObject{
|
||||
{"content", QJsonObject{{"topic", "Topic"}}},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"prev_content", QJsonObject{{"topic", "Previous Topic"}}},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"state_key", ""},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.name"}},
|
||||
};
|
||||
|
||||
for (const auto &event : events) {
|
||||
EventType ty = extractEventType(event.toObject());
|
||||
|
||||
if (ty == EventType::RoomName) {
|
||||
StateEvent<NameEventContent> name_event;
|
||||
|
||||
try {
|
||||
name_event.deserialize(event);
|
||||
} catch (const DeserializationException &e) {
|
||||
ASSERT_STREQ("name key is missing", e.what());
|
||||
}
|
||||
|
||||
} else if (ty == EventType::RoomTopic) {
|
||||
StateEvent<TopicEventContent> topic_event;
|
||||
|
||||
try {
|
||||
topic_event.deserialize(event);
|
||||
} catch (const DeserializationException &e) {
|
||||
ASSERT_STREQ("topic key is missing", e.what());
|
||||
}
|
||||
} else {
|
||||
ASSERT_EQ(false, true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -183,6 +183,7 @@ TEST(EventType, Mapping)
|
|||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.history_visibility"}}), EventType::RoomHistoryVisibility);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.join_rules"}}), EventType::RoomJoinRules);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.member"}}), EventType::RoomMember);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.message"}}), EventType::RoomMessage);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.name"}}), EventType::RoomName);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}), EventType::RoomPowerLevels);
|
||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.topic"}}), EventType::RoomTopic);
|
||||
|
|
311
tests/message_events.cc
Normal file
311
tests/message_events.cc
Normal file
|
@ -0,0 +1,311 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "MessageEvent.h"
|
||||
#include "MessageEventContent.h"
|
||||
|
||||
#include "Audio.h"
|
||||
#include "Emote.h"
|
||||
#include "File.h"
|
||||
#include "Image.h"
|
||||
#include "Location.h"
|
||||
#include "Notice.h"
|
||||
#include "Text.h"
|
||||
#include "Video.h"
|
||||
|
||||
using namespace matrix::events;
|
||||
|
||||
TEST(MessageEvent, Audio)
|
||||
{
|
||||
auto info = QJsonObject{
|
||||
{"duration", 2140786},
|
||||
{"mimetype", "audio/mpeg"},
|
||||
{"size", 1563688}};
|
||||
|
||||
auto content = QJsonObject{
|
||||
{"body", "Bee Gees - Stayin' Alive"},
|
||||
{"msgtype", "m.audio"},
|
||||
{"url", "mxc://localhost/2sdfj23f33r3faad"},
|
||||
{"info", info}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Audio> audio;
|
||||
audio.deserialize(event);
|
||||
|
||||
EXPECT_EQ(audio.msgContent().info().duration, 2140786);
|
||||
EXPECT_EQ(audio.msgContent().info().size, 1563688);
|
||||
EXPECT_EQ(audio.msgContent().info().mimetype, "audio/mpeg");
|
||||
EXPECT_EQ(audio.content().body(), "Bee Gees - Stayin' Alive");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Emote)
|
||||
{
|
||||
auto content = QJsonObject{
|
||||
{"body", "emote message"},
|
||||
{"msgtype", "m.emote"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Emote> emote;
|
||||
emote.deserialize(event);
|
||||
|
||||
EXPECT_EQ(emote.content().body(), "emote message");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, File)
|
||||
{
|
||||
auto thumbnail_info = QJsonObject{
|
||||
{"h", 300},
|
||||
{"w", 400},
|
||||
{"size", 3432434},
|
||||
{"mimetype", "image/jpeg"}};
|
||||
|
||||
auto file_info = QJsonObject{
|
||||
{"size", 24242424},
|
||||
{"mimetype", "application/msword"},
|
||||
{"thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3"},
|
||||
{"thumbnail_info", thumbnail_info}};
|
||||
|
||||
auto content = QJsonObject{
|
||||
{"body", "something-important.doc"},
|
||||
{"filename", "something-important.doc"},
|
||||
{"url", "mxc://localhost/23d233d32r3r2r"},
|
||||
{"info", file_info},
|
||||
{"msgtype", "m.file"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::File> file;
|
||||
file.deserialize(event);
|
||||
|
||||
EXPECT_EQ(file.content().body(), "something-important.doc");
|
||||
EXPECT_EQ(file.msgContent().info().thumbnail_info.h, 300);
|
||||
EXPECT_EQ(file.msgContent().info().thumbnail_info.w, 400);
|
||||
EXPECT_EQ(file.msgContent().info().thumbnail_info.mimetype, "image/jpeg");
|
||||
EXPECT_EQ(file.msgContent().info().mimetype, "application/msword");
|
||||
EXPECT_EQ(file.msgContent().info().size, 24242424);
|
||||
EXPECT_EQ(file.content().body(), "something-important.doc");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Image)
|
||||
{
|
||||
auto thumbinfo = QJsonObject{
|
||||
{"h", 11},
|
||||
{"w", 22},
|
||||
{"size", 212},
|
||||
{"mimetype", "img/jpeg"},
|
||||
};
|
||||
|
||||
auto imginfo = QJsonObject{
|
||||
{"h", 110},
|
||||
{"w", 220},
|
||||
{"size", 2120},
|
||||
{"mimetype", "img/jpeg"},
|
||||
{"thumbnail_url", "https://images.com/image-thumb.jpg"},
|
||||
{"thumbnail_info", thumbinfo},
|
||||
};
|
||||
|
||||
auto content = QJsonObject{
|
||||
{"body", "Image title"},
|
||||
{"msgtype", "m.image"},
|
||||
{"url", "https://images.com/image.jpg"},
|
||||
{"info", imginfo}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Image> img;
|
||||
img.deserialize(event);
|
||||
|
||||
EXPECT_EQ(img.content().body(), "Image title");
|
||||
EXPECT_EQ(img.msgContent().info().h, 110);
|
||||
EXPECT_EQ(img.msgContent().info().w, 220);
|
||||
EXPECT_EQ(img.msgContent().info().thumbnail_info.w, 22);
|
||||
EXPECT_EQ(img.msgContent().info().mimetype, "img/jpeg");
|
||||
EXPECT_EQ(img.msgContent().info().thumbnail_url, "https://images.com/image-thumb.jpg");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Location)
|
||||
{
|
||||
auto thumbnail_info = QJsonObject{
|
||||
{"h", 300},
|
||||
{"w", 400},
|
||||
{"size", 3432434},
|
||||
{"mimetype", "image/jpeg"}};
|
||||
|
||||
auto info = QJsonObject{
|
||||
{"thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3"},
|
||||
{"thumbnail_info", thumbnail_info}};
|
||||
|
||||
auto content = QJsonObject{
|
||||
{"body", "Big Ben, London, UK"},
|
||||
{"geo_uri", "geo:51.5008,0.1247"},
|
||||
{"info", info},
|
||||
{"msgtype", "m.location"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Location> location;
|
||||
location.deserialize(event);
|
||||
|
||||
EXPECT_EQ(location.msgContent().info().thumbnail_info.h, 300);
|
||||
EXPECT_EQ(location.msgContent().info().thumbnail_info.w, 400);
|
||||
EXPECT_EQ(location.msgContent().info().thumbnail_info.mimetype, "image/jpeg");
|
||||
EXPECT_EQ(location.msgContent().info().thumbnail_url, "mxc://localhost/adfaefaFAFSDFF3");
|
||||
EXPECT_EQ(location.content().body(), "Big Ben, London, UK");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Notice)
|
||||
{
|
||||
auto content = QJsonObject{
|
||||
{"body", "notice message"},
|
||||
{"msgtype", "m.notice"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Notice> notice;
|
||||
notice.deserialize(event);
|
||||
|
||||
EXPECT_EQ(notice.content().body(), "notice message");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Text)
|
||||
{
|
||||
auto content = QJsonObject{
|
||||
{"body", "text message"},
|
||||
{"msgtype", "m.text"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Text> text;
|
||||
text.deserialize(event);
|
||||
|
||||
EXPECT_EQ(text.content().body(), "text message");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Video)
|
||||
{
|
||||
auto thumbnail_info = QJsonObject{
|
||||
{"h", 300},
|
||||
{"w", 400},
|
||||
{"size", 3432434},
|
||||
{"mimetype", "image/jpeg"}};
|
||||
|
||||
auto video_info = QJsonObject{
|
||||
{"h", 222},
|
||||
{"w", 333},
|
||||
{"duration", 232323},
|
||||
{"size", 24242424},
|
||||
{"mimetype", "video/mp4"},
|
||||
{"thumbnail_url", "mxc://localhost/adfaefaFAFSDFF3"},
|
||||
{"thumbnail_info", thumbnail_info}};
|
||||
|
||||
auto content = QJsonObject{
|
||||
{"body", "Gangnam Style"},
|
||||
{"url", "mxc://localhost/23d233d32r3r2r"},
|
||||
{"info", video_info},
|
||||
{"msgtype", "m.video"}};
|
||||
|
||||
auto event = QJsonObject{
|
||||
{"content", content},
|
||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
||||
{"sender", "@alice:matrix.org"},
|
||||
{"origin_server_ts", 1323238293289323LL},
|
||||
{"type", "m.room.message"}};
|
||||
|
||||
MessageEvent<messages::Video> video;
|
||||
video.deserialize(event);
|
||||
|
||||
EXPECT_EQ(video.msgContent().info().thumbnail_info.h, 300);
|
||||
EXPECT_EQ(video.msgContent().info().thumbnail_info.w, 400);
|
||||
EXPECT_EQ(video.msgContent().info().thumbnail_info.mimetype, "image/jpeg");
|
||||
EXPECT_EQ(video.msgContent().info().duration, 232323);
|
||||
EXPECT_EQ(video.msgContent().info().size, 24242424);
|
||||
EXPECT_EQ(video.msgContent().info().mimetype, "video/mp4");
|
||||
EXPECT_EQ(video.content().body(), "Gangnam Style");
|
||||
}
|
||||
|
||||
TEST(MessageEvent, Types)
|
||||
{
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.audio"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Audio);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.emote"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Emote);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.file"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::File);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.image"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Image);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.location"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Location);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.notice"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Notice);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.text"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Text);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.video"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Video);
|
||||
EXPECT_EQ(extractMessageEventType(QJsonObject{
|
||||
{"content", QJsonObject{{"msgtype", "m.random"}}}, {"type", "m.room.message"},
|
||||
}),
|
||||
MessageEventType::Unknown);
|
||||
}
|
Loading…
Reference in a new issue