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/MainWindow.cc
|
||||||
src/MatrixClient.cc
|
src/MatrixClient.cc
|
||||||
src/Profile.cc
|
src/Profile.cc
|
||||||
src/RoomInfo.cc
|
|
||||||
src/RoomInfoListItem.cc
|
src/RoomInfoListItem.cc
|
||||||
src/RoomList.cc
|
src/RoomList.cc
|
||||||
|
src/RoomState.cc
|
||||||
src/Register.cc
|
src/Register.cc
|
||||||
src/RegisterPage.cc
|
src/RegisterPage.cc
|
||||||
src/SlidingStackWidget.cc
|
src/SlidingStackWidget.cc
|
||||||
|
@ -126,14 +126,25 @@ set(MATRIX_EVENTS
|
||||||
src/events/HistoryVisibilityEventContent.cc
|
src/events/HistoryVisibilityEventContent.cc
|
||||||
src/events/JoinRulesEventContent.cc
|
src/events/JoinRulesEventContent.cc
|
||||||
src/events/MemberEventContent.cc
|
src/events/MemberEventContent.cc
|
||||||
|
src/events/MessageEventContent.cc
|
||||||
src/events/NameEventContent.cc
|
src/events/NameEventContent.cc
|
||||||
src/events/PowerLevelsEventContent.cc
|
src/events/PowerLevelsEventContent.cc
|
||||||
src/events/TopicEventContent.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)
|
||||||
include_directories(include/ui)
|
include_directories(include/ui)
|
||||||
include_directories(include/events)
|
include_directories(include/events)
|
||||||
|
include_directories(include/events/messages)
|
||||||
|
|
||||||
qt5_wrap_ui (UI_HEADERS
|
qt5_wrap_ui (UI_HEADERS
|
||||||
forms/ChatPage.ui
|
forms/ChatPage.ui
|
||||||
|
@ -191,7 +202,15 @@ if (BUILD_TESTS)
|
||||||
add_executable(events_test tests/events.cc)
|
add_executable(events_test tests/events.cc)
|
||||||
target_link_libraries(events_test matrix_events ${GTEST_BOTH_LIBRARIES})
|
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(MatrixEvents events_test)
|
||||||
|
add_test(MatrixEventCollection event_collection_test)
|
||||||
|
add_test(MatrixMessageEvents message_events)
|
||||||
else()
|
else()
|
||||||
add_executable (nheko ${OS_BUNDLE} ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC})
|
add_executable (nheko ${OS_BUNDLE} ${SRC_FILES} ${UI_HEADERS} ${MOC_HEADERS} ${QRC})
|
||||||
target_link_libraries (nheko matrix_events Qt5::Widgets Qt5::Network)
|
target_link_libraries (nheko matrix_events Qt5::Widgets Qt5::Network)
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "RoomInfo.h"
|
|
||||||
#include "RoomList.h"
|
#include "RoomList.h"
|
||||||
|
#include "RoomState.h"
|
||||||
#include "TextInputWidget.h"
|
#include "TextInputWidget.h"
|
||||||
#include "TimelineViewManager.h"
|
#include "TimelineViewManager.h"
|
||||||
#include "TopRoomBar.h"
|
#include "TopRoomBar.h"
|
||||||
|
@ -58,11 +58,13 @@ private slots:
|
||||||
void initialSyncCompleted(const SyncResponse &response);
|
void initialSyncCompleted(const SyncResponse &response);
|
||||||
void syncCompleted(const SyncResponse &response);
|
void syncCompleted(const SyncResponse &response);
|
||||||
void syncFailed(const QString &msg);
|
void syncFailed(const QString &msg);
|
||||||
void changeTopRoomInfo(const RoomInfo &info);
|
void changeTopRoomInfo(const QString &room_id);
|
||||||
void startSync();
|
void startSync();
|
||||||
void logout();
|
void logout();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateRoomState(RoomState &room_state, const QJsonArray &events);
|
||||||
|
|
||||||
Ui::ChatPage *ui;
|
Ui::ChatPage *ui;
|
||||||
|
|
||||||
RoomList *room_list_;
|
RoomList *room_list_;
|
||||||
|
@ -74,11 +76,13 @@ private:
|
||||||
QTimer *sync_timer_;
|
QTimer *sync_timer_;
|
||||||
int sync_interval_;
|
int sync_interval_;
|
||||||
|
|
||||||
RoomInfo current_room_;
|
QString current_room_;
|
||||||
QMap<QString, QPixmap> room_avatars_;
|
QMap<QString, QPixmap> room_avatars_;
|
||||||
|
|
||||||
UserInfoWidget *user_info_widget_;
|
UserInfoWidget *user_info_widget_;
|
||||||
|
|
||||||
|
QMap<QString, RoomState> state_manager_;
|
||||||
|
|
||||||
// Matrix Client API provider.
|
// Matrix Client API provider.
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,16 +23,18 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "Image.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
|
||||||
|
namespace events = matrix::events;
|
||||||
|
namespace msgs = matrix::events::messages;
|
||||||
|
|
||||||
class ImageItem : public QWidget
|
class ImageItem : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ImageItem(QSharedPointer<MatrixClient> client,
|
ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
const Event &event,
|
const events::MessageEvent<msgs::Image> &event,
|
||||||
const QString &body,
|
|
||||||
const QUrl &url,
|
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setImage(const QPixmap &image);
|
void setImage(const QPixmap &image);
|
||||||
|
@ -65,7 +67,7 @@ private:
|
||||||
|
|
||||||
int bottom_height_ = 30;
|
int bottom_height_ = 30;
|
||||||
|
|
||||||
Event event_;
|
events::MessageEvent<msgs::Image> event_;
|
||||||
|
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,26 +26,27 @@
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "Badge.h"
|
#include "Badge.h"
|
||||||
#include "RippleOverlay.h"
|
#include "RippleOverlay.h"
|
||||||
#include "RoomInfo.h"
|
#include "RoomState.h"
|
||||||
|
|
||||||
class RoomInfoListItem : public QWidget
|
class RoomInfoListItem : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RoomInfoListItem(RoomInfo info, QWidget *parent = 0);
|
RoomInfoListItem(RoomState state, QString room_id, QWidget *parent = 0);
|
||||||
~RoomInfoListItem();
|
~RoomInfoListItem();
|
||||||
|
|
||||||
void updateUnreadMessageCount(int count);
|
void updateUnreadMessageCount(int count);
|
||||||
void clearUnreadMessageCount();
|
void clearUnreadMessageCount();
|
||||||
|
void setState(const RoomState &state);
|
||||||
|
|
||||||
inline bool isPressed();
|
inline bool isPressed() const;
|
||||||
inline RoomInfo info();
|
inline RoomState state() const;
|
||||||
inline void setAvatar(const QImage &avatar_image);
|
inline void setAvatar(const QImage &avatar_image);
|
||||||
inline int unreadMessageCount();
|
inline int unreadMessageCount() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void clicked(const RoomInfo &info_);
|
void clicked(const QString &room_id);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setPressedState(bool state);
|
void setPressedState(bool state);
|
||||||
|
@ -58,7 +59,8 @@ private:
|
||||||
|
|
||||||
RippleOverlay *ripple_overlay_;
|
RippleOverlay *ripple_overlay_;
|
||||||
|
|
||||||
RoomInfo info_;
|
RoomState state_;
|
||||||
|
QString room_id_;
|
||||||
|
|
||||||
QHBoxLayout *topLayout_;
|
QHBoxLayout *topLayout_;
|
||||||
|
|
||||||
|
@ -83,19 +85,19 @@ private:
|
||||||
int unread_msg_count_;
|
int unread_msg_count_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int RoomInfoListItem::unreadMessageCount()
|
inline int RoomInfoListItem::unreadMessageCount() const
|
||||||
{
|
{
|
||||||
return unread_msg_count_;
|
return unread_msg_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool RoomInfoListItem::isPressed()
|
inline bool RoomInfoListItem::isPressed() const
|
||||||
{
|
{
|
||||||
return is_pressed_;
|
return is_pressed_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RoomInfo RoomInfoListItem::info()
|
inline RoomState RoomInfoListItem::state() const
|
||||||
{
|
{
|
||||||
return info_;
|
return state_;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void RoomInfoListItem::setAvatar(const QImage &avatar_image)
|
inline void RoomInfoListItem::setAvatar(const QImage &avatar_image)
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "RoomInfo.h"
|
|
||||||
#include "RoomInfoListItem.h"
|
#include "RoomInfoListItem.h"
|
||||||
|
#include "RoomState.h"
|
||||||
#include "Sync.h"
|
#include "Sync.h"
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
|
@ -41,18 +41,18 @@ public:
|
||||||
RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
RoomList(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
||||||
~RoomList();
|
~RoomList();
|
||||||
|
|
||||||
void setInitialRooms(const Rooms &rooms);
|
void setInitialRooms(const QMap<QString, RoomState> &states);
|
||||||
|
void sync(const QMap<QString, RoomState> &states);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
RoomInfo extractRoomInfo(const State &room_state);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void roomChanged(const RoomInfo &info);
|
void roomChanged(const QString &room_id);
|
||||||
void totalUnreadMessageCountUpdated(int count);
|
void totalUnreadMessageCountUpdated(int count);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateRoomAvatar(const QString &roomid, const QPixmap &img);
|
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);
|
void updateUnreadMessageCount(const QString &roomid, int count);
|
||||||
|
|
||||||
private:
|
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
|
#ifndef SYNC_H
|
||||||
#define SYNC_H
|
#define SYNC_H
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
@ -90,13 +91,13 @@ class State : public Deserializable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void deserialize(const QJsonValue &data) override;
|
void deserialize(const QJsonValue &data) override;
|
||||||
inline QList<Event> events() const;
|
inline QJsonArray events() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Event> events_;
|
QJsonArray events_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QList<Event> State::events() const
|
inline QJsonArray State::events() const
|
||||||
{
|
{
|
||||||
return events_;
|
return events_;
|
||||||
}
|
}
|
||||||
|
@ -104,19 +105,19 @@ inline QList<Event> State::events() const
|
||||||
class Timeline : public Deserializable
|
class Timeline : public Deserializable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline QList<Event> events() const;
|
inline QJsonArray events() const;
|
||||||
inline QString previousBatch() const;
|
inline QString previousBatch() const;
|
||||||
inline bool limited() const;
|
inline bool limited() const;
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
void deserialize(const QJsonValue &data) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Event> events_;
|
QJsonArray events_;
|
||||||
QString prev_batch_;
|
QString prev_batch_;
|
||||||
bool limited_;
|
bool limited_;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline QList<Event> Timeline::events() const
|
inline QJsonArray Timeline::events() const
|
||||||
{
|
{
|
||||||
return events_;
|
return events_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,20 +25,27 @@
|
||||||
#include "ImageItem.h"
|
#include "ImageItem.h"
|
||||||
#include "Sync.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
|
class TimelineItem : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
// For remote messages.
|
TimelineItem(const events::MessageEvent<msgs::Notice> &e, bool with_sender, const QString &color, QWidget *parent = 0);
|
||||||
TimelineItem(const Event &event, 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.
|
// For local messages.
|
||||||
TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent = 0);
|
TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent = 0);
|
||||||
TimelineItem(const QString &body, QWidget *parent = 0);
|
TimelineItem(const QString &body, QWidget *parent = 0);
|
||||||
|
|
||||||
// For inline images.
|
TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, const QString &color, QWidget *parent);
|
||||||
TimelineItem(ImageItem *image, const Event &event, const QString &color, QWidget *parent);
|
TimelineItem(ImageItem *img, const events::MessageEvent<msgs::Image> &e, QWidget *parent);
|
||||||
TimelineItem(ImageItem *image, const Event &event, QWidget *parent);
|
|
||||||
|
|
||||||
~TimelineItem();
|
~TimelineItem();
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,13 @@
|
||||||
#include "Sync.h"
|
#include "Sync.h"
|
||||||
#include "TimelineItem.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
|
// Contains info about a message shown in the history view
|
||||||
// but not yet confirmed by the homeserver through sync.
|
// but not yet confirmed by the homeserver through sync.
|
||||||
struct PendingMessage {
|
struct PendingMessage {
|
||||||
|
@ -50,13 +57,14 @@ class TimelineView : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TimelineView(QSharedPointer<MatrixClient> client, QWidget *parent = 0);
|
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();
|
~TimelineView();
|
||||||
|
|
||||||
// FIXME: Reduce the parameters
|
void addHistoryItem(const events::MessageEvent<msgs::Image> &e, const QString &color, bool with_sender);
|
||||||
void addHistoryItem(const Event &event, const QString &color, bool with_sender);
|
void addHistoryItem(const events::MessageEvent<msgs::Notice> &e, const QString &color, bool with_sender);
|
||||||
void addImageItem(const QString &body, const QUrl &url, const Event &event, const QString &color, bool with_sender);
|
void addHistoryItem(const events::MessageEvent<msgs::Text> &e, const QString &color, bool with_sender);
|
||||||
int addEvents(const QList<Event> &events);
|
|
||||||
|
int addEvents(const QJsonArray &events);
|
||||||
void addUserTextMessage(const QString &msg, int txn_id);
|
void addUserTextMessage(const QString &msg, int txn_id);
|
||||||
void updatePendingMessage(int txn_id, QString event_id);
|
void updatePendingMessage(int txn_id, QString event_id);
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -66,8 +74,8 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void removePendingMessage(const Event &event);
|
void removePendingMessage(const events::MessageEvent<msgs::Text> &e);
|
||||||
bool isPendingMessage(const Event &event, const QString &userid);
|
bool isPendingMessage(const events::MessageEvent<msgs::Text> &e, const QString &userid);
|
||||||
|
|
||||||
QVBoxLayout *top_layout_;
|
QVBoxLayout *top_layout_;
|
||||||
QVBoxLayout *scroll_layout_;
|
QVBoxLayout *scroll_layout_;
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "RoomInfo.h"
|
|
||||||
#include "Sync.h"
|
#include "Sync.h"
|
||||||
#include "TimelineView.h"
|
#include "TimelineView.h"
|
||||||
|
|
||||||
|
@ -48,14 +47,14 @@ signals:
|
||||||
void unreadMessages(QString roomid, int count);
|
void unreadMessages(QString roomid, int count);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setHistoryView(const RoomInfo &info);
|
void setHistoryView(const QString &room_id);
|
||||||
void sendTextMessage(const QString &msg);
|
void sendTextMessage(const QString &msg);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void messageSent(const QString &eventid, const QString &roomid, int txnid);
|
void messageSent(const QString &eventid, const QString &roomid, int txnid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RoomInfo active_room_;
|
QString active_room_;
|
||||||
QMap<QString, TimelineView *> views_;
|
QMap<QString, TimelineView *> views_;
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,8 @@ enum EventType {
|
||||||
RoomJoinRules,
|
RoomJoinRules,
|
||||||
/// m.room.member
|
/// m.room.member
|
||||||
RoomMember,
|
RoomMember,
|
||||||
|
/// m.room.message
|
||||||
|
RoomMessage,
|
||||||
/// m.room.name
|
/// m.room.name
|
||||||
RoomName,
|
RoomName,
|
||||||
/// m.room.power_levels
|
/// m.room.power_levels
|
||||||
|
@ -53,6 +55,9 @@ enum EventType {
|
||||||
|
|
||||||
EventType extractEventType(const QJsonObject &data);
|
EventType extractEventType(const QJsonObject &data);
|
||||||
|
|
||||||
|
bool isMessageEvent(EventType type);
|
||||||
|
bool isStateEvent(EventType type);
|
||||||
|
|
||||||
template <class Content>
|
template <class Content>
|
||||||
class Event : public Deserializable
|
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"))
|
if (!object.contains("origin_server_ts"))
|
||||||
throw DeserializationException("origin_server_ts key is missing");
|
throw DeserializationException("origin_server_ts key is missing");
|
||||||
|
|
||||||
if (!object.contains("room_id"))
|
// FIXME: Synapse doesn't include room id?!
|
||||||
throw DeserializationException("room_id key is missing");
|
/* if (!object.contains("room_id")) */
|
||||||
|
/* throw DeserializationException("room_id key is missing"); */
|
||||||
|
|
||||||
if (!object.contains("sender"))
|
if (!object.contains("sender"))
|
||||||
throw DeserializationException("sender key is missing");
|
throw DeserializationException("sender key is missing");
|
||||||
|
|
|
@ -15,57 +15,51 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* 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()
|
#include <QJsonObject>
|
||||||
: name_("")
|
|
||||||
, topic_("")
|
#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)
|
inline AudioInfo Audio::info() const
|
||||||
: name_(name)
|
|
||||||
, topic_(topic)
|
|
||||||
, avatar_url_(avatar_url)
|
|
||||||
{
|
{
|
||||||
|
return info_;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RoomInfo::id() const
|
} // namespace messages
|
||||||
{
|
} // namespace events
|
||||||
return id_;
|
} // namespace matrix
|
||||||
}
|
|
||||||
|
|
||||||
QString RoomInfo::name() const
|
#endif // MESSAGE_EVENT_AUDIO_H
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr>
|
* 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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ROOM_INFO_H
|
#ifndef MESSAGE_EVENT_EMOTE_H
|
||||||
#define ROOM_INFO_H
|
#define MESSAGE_EVENT_EMOTE_H
|
||||||
|
|
||||||
#include <QList>
|
#include <QJsonObject>
|
||||||
#include <QString>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
class RoomInfo
|
#include "Deserializable.h"
|
||||||
|
|
||||||
|
namespace matrix
|
||||||
|
{
|
||||||
|
namespace events
|
||||||
|
{
|
||||||
|
namespace messages
|
||||||
|
{
|
||||||
|
class Emote : public Deserializable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RoomInfo();
|
void deserialize(const QJsonObject &obj) override;
|
||||||
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_;
|
|
||||||
};
|
};
|
||||||
|
} // 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 "Sync.h"
|
||||||
#include "UserInfoWidget.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)
|
ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, ui(new Ui::ChatPage)
|
, 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(user_info_widget_, SIGNAL(logout()), client_.data(), SLOT(logout()));
|
||||||
connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
|
connect(client_.data(), SIGNAL(loggedOut()), this, SLOT(logout()));
|
||||||
|
|
||||||
connect(room_list_,
|
connect(room_list_, &RoomList::roomChanged, this, &ChatPage::changeTopRoomInfo);
|
||||||
SIGNAL(roomChanged(const RoomInfo &)),
|
connect(room_list_, &RoomList::roomChanged, view_manager_, &TimelineViewManager::setHistoryView);
|
||||||
this,
|
|
||||||
SLOT(changeTopRoomInfo(const RoomInfo &)));
|
|
||||||
connect(room_list_,
|
|
||||||
SIGNAL(roomChanged(const RoomInfo &)),
|
|
||||||
view_manager_,
|
|
||||||
SLOT(setHistoryView(const RoomInfo &)));
|
|
||||||
|
|
||||||
// TODO: Better pass the whole RoomInfo struct instead of the roomid.
|
|
||||||
connect(view_manager_,
|
connect(view_manager_,
|
||||||
SIGNAL(unreadMessages(const QString &, int)),
|
SIGNAL(unreadMessages(const QString &, int)),
|
||||||
room_list_,
|
room_list_,
|
||||||
|
@ -161,7 +168,24 @@ void ChatPage::syncCompleted(const SyncResponse &response)
|
||||||
{
|
{
|
||||||
client_->setNextBatchToken(response.nextBatch());
|
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());
|
view_manager_->sync(response.rooms());
|
||||||
|
|
||||||
sync_timer_->start(sync_interval_);
|
sync_timer_->start(sync_interval_);
|
||||||
|
@ -172,8 +196,19 @@ void ChatPage::initialSyncCompleted(const SyncResponse &response)
|
||||||
if (!response.nextBatch().isEmpty())
|
if (!response.nextBatch().isEmpty())
|
||||||
client_->setNextBatchToken(response.nextBatch());
|
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());
|
view_manager_->initialize(response.rooms());
|
||||||
room_list_->setInitialRooms(response.rooms());
|
room_list_->setInitialRooms(state_manager_);
|
||||||
|
|
||||||
sync_timer_->start(sync_interval_);
|
sync_timer_->start(sync_interval_);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +217,7 @@ void ChatPage::updateTopBarAvatar(const QString &roomid, const QPixmap &img)
|
||||||
{
|
{
|
||||||
room_avatars_.insert(roomid, img);
|
room_avatars_.insert(roomid, img);
|
||||||
|
|
||||||
if (current_room_.id() != roomid)
|
if (current_room_ != roomid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
top_bar_->updateRoomAvatar(img.toImage());
|
top_bar_->updateRoomAvatar(img.toImage());
|
||||||
|
@ -199,17 +234,22 @@ void ChatPage::updateOwnProfileInfo(const QUrl &avatar_url, const QString &displ
|
||||||
client_->fetchOwnAvatar(avatar_url);
|
client_->fetchOwnAvatar(avatar_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPage::changeTopRoomInfo(const RoomInfo &info)
|
void ChatPage::changeTopRoomInfo(const QString &room_id)
|
||||||
{
|
{
|
||||||
top_bar_->updateRoomName(info.name());
|
if (!state_manager_.contains(room_id))
|
||||||
top_bar_->updateRoomTopic(info.topic());
|
return;
|
||||||
|
|
||||||
if (room_avatars_.contains(info.id()))
|
auto state = state_manager_[room_id];
|
||||||
top_bar_->updateRoomAvatar(room_avatars_.value(info.id()).toImage());
|
|
||||||
|
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
|
else
|
||||||
top_bar_->updateRoomAvatarFromName(info.name());
|
top_bar_->updateRoomAvatarFromName(state.resolveName());
|
||||||
|
|
||||||
current_room_ = info;
|
current_room_ = room_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPage::showUnreadMessageNotification(int count)
|
void ChatPage::showUnreadMessageNotification(int count)
|
||||||
|
@ -221,6 +261,88 @@ void ChatPage::showUnreadMessageNotification(int count)
|
||||||
emit changeWindowTitle(QString("nheko (%1)").arg(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()
|
ChatPage::~ChatPage()
|
||||||
{
|
{
|
||||||
sync_timer_->stop();
|
sync_timer_->stop();
|
||||||
|
|
|
@ -25,10 +25,11 @@
|
||||||
#include "ImageItem.h"
|
#include "ImageItem.h"
|
||||||
#include "ImageOverlayDialog.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)
|
: QWidget(parent)
|
||||||
, url_{url}
|
|
||||||
, text_{body}
|
|
||||||
, event_{event}
|
, event_{event}
|
||||||
, client_{client}
|
, client_{client}
|
||||||
{
|
{
|
||||||
|
@ -37,6 +38,9 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client, const Event &event, co
|
||||||
setCursor(Qt::PointingHandCursor);
|
setCursor(Qt::PointingHandCursor);
|
||||||
setAttribute(Qt::WA_Hover, true);
|
setAttribute(Qt::WA_Hover, true);
|
||||||
|
|
||||||
|
url_ = event.msgContent().url();
|
||||||
|
text_ = event.content().body();
|
||||||
|
|
||||||
QList<QString> url_parts = url_.toString().split("mxc://");
|
QList<QString> url_parts = url_.toString().split("mxc://");
|
||||||
|
|
||||||
if (url_parts.size() != 2) {
|
if (url_parts.size() != 2) {
|
||||||
|
|
|
@ -194,10 +194,12 @@ void MatrixClient::onInitialSyncResponse(QNetworkReply *reply)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.deserialize(json);
|
response.deserialize(json);
|
||||||
emit initialSyncCompleted(response);
|
|
||||||
} catch (DeserializationException &e) {
|
} catch (DeserializationException &e) {
|
||||||
qWarning() << "Sync malformed response" << e.what();
|
qWarning() << "Sync malformed response" << e.what();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit initialSyncCompleted(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatrixClient::onSyncResponse(QNetworkReply *reply)
|
void MatrixClient::onSyncResponse(QNetworkReply *reply)
|
||||||
|
|
|
@ -19,12 +19,13 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
|
||||||
#include "Ripple.h"
|
#include "Ripple.h"
|
||||||
#include "RoomInfo.h"
|
|
||||||
#include "RoomInfoListItem.h"
|
#include "RoomInfoListItem.h"
|
||||||
|
#include "RoomState.h"
|
||||||
|
|
||||||
RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
|
RoomInfoListItem::RoomInfoListItem(RoomState state, QString room_id, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, info_(info)
|
, state_(state)
|
||||||
|
, room_id_(room_id)
|
||||||
, is_pressed_(false)
|
, is_pressed_(false)
|
||||||
, max_height_(60)
|
, max_height_(60)
|
||||||
, unread_msg_count_(0)
|
, unread_msg_count_(0)
|
||||||
|
@ -43,6 +44,9 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
|
||||||
|
|
||||||
setMaximumSize(parent->width(), max_height_);
|
setMaximumSize(parent->width(), max_height_);
|
||||||
|
|
||||||
|
QString room_name = state_.resolveName();
|
||||||
|
QString room_topic = state_.topic.content().topic().simplified();
|
||||||
|
|
||||||
topLayout_ = new QHBoxLayout(this);
|
topLayout_ = new QHBoxLayout(this);
|
||||||
topLayout_->setSpacing(0);
|
topLayout_->setSpacing(0);
|
||||||
topLayout_->setMargin(0);
|
topLayout_->setMargin(0);
|
||||||
|
@ -60,7 +64,7 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
|
||||||
textLayout_->setContentsMargins(0, 5, 0, 5);
|
textLayout_->setContentsMargins(0, 5, 0, 5);
|
||||||
|
|
||||||
roomAvatar_ = new Avatar(avatarWidget_);
|
roomAvatar_ = new Avatar(avatarWidget_);
|
||||||
roomAvatar_->setLetter(QChar(info_.name()[0]));
|
roomAvatar_->setLetter(QChar(room_name[0]));
|
||||||
roomAvatar_->setSize(max_height_ - 20);
|
roomAvatar_->setSize(max_height_ - 20);
|
||||||
roomAvatar_->setTextColor("#555459");
|
roomAvatar_->setTextColor("#555459");
|
||||||
roomAvatar_->setBackgroundColor("#d6dde3");
|
roomAvatar_->setBackgroundColor("#d6dde3");
|
||||||
|
@ -76,12 +80,12 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
|
||||||
|
|
||||||
avatarLayout_->addWidget(roomAvatar_);
|
avatarLayout_->addWidget(roomAvatar_);
|
||||||
|
|
||||||
roomName_ = new QLabel(info_.name(), textWidget_);
|
roomName_ = new QLabel(room_name, textWidget_);
|
||||||
roomName_->setMaximumSize(parent->width() - max_height_, 20);
|
roomName_->setMaximumSize(parent->width() - max_height_, 20);
|
||||||
roomName_->setFont(QFont("Open Sans", 11));
|
roomName_->setFont(QFont("Open Sans", 11));
|
||||||
roomName_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
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_->setMaximumSize(parent->width() - max_height_, 20);
|
||||||
roomTopic_->setFont(QFont("Open Sans", 10));
|
roomTopic_->setFont(QFont("Open Sans", 10));
|
||||||
roomTopic_->setStyleSheet("color: #171919");
|
roomTopic_->setStyleSheet("color: #171919");
|
||||||
|
@ -93,8 +97,8 @@ RoomInfoListItem::RoomInfoListItem(RoomInfo info, QWidget *parent)
|
||||||
topLayout_->addWidget(avatarWidget_);
|
topLayout_->addWidget(avatarWidget_);
|
||||||
topLayout_->addWidget(textWidget_);
|
topLayout_->addWidget(textWidget_);
|
||||||
|
|
||||||
setElidedText(roomName_, info_.name(), parent->width() - max_height_);
|
setElidedText(roomName_, room_name, parent->width() - max_height_);
|
||||||
setElidedText(roomTopic_, info_.topic(), parent->width() - max_height_);
|
setElidedText(roomTopic_, room_topic, parent->width() - max_height_);
|
||||||
|
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
path.addRoundedRect(rect(), 0, 0);
|
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)
|
void RoomInfoListItem::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
emit clicked(info_);
|
emit clicked(room_id_);
|
||||||
|
|
||||||
setPressedState(true);
|
setPressedState(true);
|
||||||
|
|
||||||
|
|
|
@ -57,32 +57,6 @@ void RoomList::clear()
|
||||||
rooms_.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)
|
void RoomList::updateUnreadMessageCount(const QString &roomid, int count)
|
||||||
{
|
{
|
||||||
if (!rooms_.contains(roomid)) {
|
if (!rooms_.contains(roomid)) {
|
||||||
|
@ -105,27 +79,21 @@ void RoomList::calculateUnreadMessageCount()
|
||||||
emit totalUnreadMessageCountUpdated(total_unread_msgs);
|
emit totalUnreadMessageCountUpdated(total_unread_msgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomList::setInitialRooms(const Rooms &rooms)
|
void RoomList::setInitialRooms(const QMap<QString, RoomState> &states)
|
||||||
{
|
{
|
||||||
rooms_.clear();
|
rooms_.clear();
|
||||||
|
|
||||||
for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); it++) {
|
for (auto it = states.constBegin(); it != states.constEnd(); it++) {
|
||||||
RoomInfo info = RoomList::extractRoomInfo(it.value().state());
|
auto room_id = it.key();
|
||||||
info.setId(it.key());
|
auto state = it.value();
|
||||||
|
|
||||||
if (info.name().isEmpty())
|
if (!state.avatar.content().url().toString().isEmpty())
|
||||||
continue;
|
client_->fetchRoomAvatar(room_id, state.avatar.content().url());
|
||||||
|
|
||||||
if (!info.avatarUrl().isEmpty())
|
RoomInfoListItem *room_item = new RoomInfoListItem(state, room_id, ui->scrollArea);
|
||||||
client_->fetchRoomAvatar(info.id(), info.avatarUrl());
|
connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom);
|
||||||
|
|
||||||
RoomInfoListItem *room_item = new RoomInfoListItem(info, ui->scrollArea);
|
rooms_.insert(room_id, room_item);
|
||||||
connect(room_item,
|
|
||||||
SIGNAL(clicked(const RoomInfo &)),
|
|
||||||
this,
|
|
||||||
SLOT(highlightSelectedRoom(const RoomInfo &)));
|
|
||||||
|
|
||||||
rooms_.insert(it.key(), room_item);
|
|
||||||
|
|
||||||
int pos = ui->scrollVerticalLayout->count() - 1;
|
int pos = ui->scrollVerticalLayout->count() - 1;
|
||||||
ui->scrollVerticalLayout->insertWidget(pos, room_item);
|
ui->scrollVerticalLayout->insertWidget(pos, room_item);
|
||||||
|
@ -134,29 +102,51 @@ void RoomList::setInitialRooms(const Rooms &rooms)
|
||||||
if (rooms_.isEmpty())
|
if (rooms_.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: Move this into its own function.
|
|
||||||
auto first_room = rooms_.first();
|
auto first_room = rooms_.first();
|
||||||
first_room->setPressedState(true);
|
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";
|
qDebug() << "RoomList: clicked unknown roomid";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Send a read receipt for the last event.
|
// TODO: Send a read receipt for the last event.
|
||||||
auto room = rooms_[info.id()];
|
auto room = rooms_[room_id];
|
||||||
room->clearUnreadMessageCount();
|
room->clearUnreadMessageCount();
|
||||||
|
|
||||||
calculateUnreadMessageCount();
|
calculateUnreadMessageCount();
|
||||||
|
|
||||||
for (auto it = rooms_.constBegin(); it != rooms_.constEnd(); it++) {
|
for (auto it = rooms_.constBegin(); it != rooms_.constEnd(); it++) {
|
||||||
if (it.key() != info.id())
|
if (it.key() != room_id)
|
||||||
it.value()->setPressedState(false);
|
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())
|
if (!data.isArray())
|
||||||
throw DeserializationException("State is not a JSON array");
|
throw DeserializationException("State is not a JSON array");
|
||||||
|
|
||||||
QJsonArray event_array = data.toArray();
|
events_ = 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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::deserialize(const QJsonValue &data)
|
void Timeline::deserialize(const QJsonValue &data)
|
||||||
|
@ -194,17 +182,5 @@ void Timeline::deserialize(const QJsonValue &data)
|
||||||
if (!object.value("events").isArray())
|
if (!object.value("events").isArray())
|
||||||
throw DeserializationException("timeline/events is not a JSON array");
|
throw DeserializationException("timeline/events is not a JSON array");
|
||||||
|
|
||||||
auto timeline_events = object.value("events").toArray();
|
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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "ImageItem.h"
|
#include "ImageItem.h"
|
||||||
#include "TimelineItem.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)
|
TimelineItem::TimelineItem(const QString &userid, const QString &color, const QString &body, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +40,7 @@ TimelineItem::TimelineItem(const QString &body, QWidget *parent)
|
||||||
setupLayout();
|
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)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
|
@ -58,7 +61,7 @@ TimelineItem::TimelineItem(ImageItem *image, const Event &event, const QString &
|
||||||
setLayout(top_layout_);
|
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)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
|
@ -73,16 +76,31 @@ TimelineItem::TimelineItem(ImageItem *image, const Event &event, QWidget *parent
|
||||||
setLayout(top_layout_);
|
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)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
auto body = event.content().value("body").toString().trimmed().toHtmlEscaped();
|
auto body = event.content().body().trimmed().toHtmlEscaped();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
||||||
|
|
||||||
generateTimestamp(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)
|
if (with_sender)
|
||||||
generateBody(event.sender(), color, body);
|
generateBody(event.sender(), color, body);
|
||||||
|
|
|
@ -16,17 +16,25 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QtWidgets/QLabel>
|
#include <QtWidgets/QLabel>
|
||||||
#include <QtWidgets/QSpacerItem>
|
#include <QtWidgets/QSpacerItem>
|
||||||
|
|
||||||
|
#include "Event.h"
|
||||||
|
#include "MessageEvent.h"
|
||||||
|
#include "MessageEventContent.h"
|
||||||
|
|
||||||
#include "ImageItem.h"
|
#include "ImageItem.h"
|
||||||
#include "TimelineItem.h"
|
#include "TimelineItem.h"
|
||||||
#include "TimelineView.h"
|
#include "TimelineView.h"
|
||||||
#include "TimelineViewManager.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)
|
: QWidget(parent)
|
||||||
, client_{client}
|
, client_{client}
|
||||||
{
|
{
|
||||||
|
@ -53,53 +61,80 @@ void TimelineView::sliderRangeChanged(int min, int max)
|
||||||
scroll_area_->verticalScrollBar()->setValue(max);
|
scroll_area_->verticalScrollBar()->setValue(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimelineView::addEvents(const QList<Event> &events)
|
int TimelineView::addEvents(const QJsonArray &events)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
auto local_user = settings.value("auth/user_id").toString();
|
auto local_user = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
int message_count = 0;
|
int message_count = 0;
|
||||||
|
events::EventType ty;
|
||||||
|
|
||||||
for (const auto &event : events) {
|
for (const auto &event : events) {
|
||||||
if (event.type() == "m.room.message") {
|
ty = events::extractEventType(event.toObject());
|
||||||
auto msg_type = event.content().value("msgtype").toString();
|
|
||||||
|
|
||||||
if (isPendingMessage(event, local_user)) {
|
if (ty == events::RoomMessage) {
|
||||||
removePendingMessage(event);
|
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;
|
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)));
|
SLOT(sliderRangeChanged(int, int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineView::addImageItem(const QString &body,
|
void TimelineView::addHistoryItem(const events::MessageEvent<msgs::Image> &event, const QString &color, bool with_sender)
|
||||||
const QUrl &url,
|
|
||||||
const Event &event,
|
|
||||||
const QString &color,
|
|
||||||
bool with_sender)
|
|
||||||
{
|
{
|
||||||
auto image = new ImageItem(client_, event, body, url);
|
auto image = new ImageItem(client_, event);
|
||||||
|
|
||||||
if (with_sender) {
|
if (with_sender) {
|
||||||
auto item = new TimelineItem(image, event, color, scroll_widget_);
|
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_);
|
TimelineItem *item = new TimelineItem(event, with_sender, color, scroll_widget_);
|
||||||
scroll_layout_->addWidget(item);
|
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")
|
if (e.sender() != local_userid)
|
||||||
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")
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (const auto &msg : pending_msgs_) {
|
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 true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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++) {
|
for (auto it = pending_msgs_.begin(); it != pending_msgs_.end(); it++) {
|
||||||
int index = std::distance(pending_msgs_.begin(), 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);
|
pending_msgs_.removeAt(index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,11 +54,11 @@ void TimelineViewManager::messageSent(const QString &event_id, const QString &ro
|
||||||
|
|
||||||
void TimelineViewManager::sendTextMessage(const QString &msg)
|
void TimelineViewManager::sendTextMessage(const QString &msg)
|
||||||
{
|
{
|
||||||
auto room = active_room_;
|
auto room_id = active_room_;
|
||||||
auto view = views_[room.id()];
|
auto view = views_[room_id];
|
||||||
|
|
||||||
view->addUserTextMessage(msg, client_->transactionId());
|
view->addUserTextMessage(msg, client_->transactionId());
|
||||||
client_->sendTextMessage(room.id(), msg);
|
client_->sendTextMessage(room_id, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineViewManager::clearAll()
|
void TimelineViewManager::clearAll()
|
||||||
|
@ -95,7 +95,7 @@ void TimelineViewManager::sync(const Rooms &rooms)
|
||||||
auto roomid = it.key();
|
auto roomid = it.key();
|
||||||
|
|
||||||
if (!views_.contains(roomid)) {
|
if (!views_.contains(roomid)) {
|
||||||
qDebug() << "Ignoring event from unknown room";
|
qDebug() << "Ignoring event from unknown room" << roomid;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,26 +105,25 @@ void TimelineViewManager::sync(const Rooms &rooms)
|
||||||
int msgs_added = view->addEvents(events);
|
int msgs_added = view->addEvents(events);
|
||||||
|
|
||||||
if (msgs_added > 0) {
|
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.
|
// unread count (if any) should be cleared.
|
||||||
auto isAppActive = QApplication::activeWindow() != nullptr;
|
auto isAppActive = QApplication::activeWindow() != nullptr;
|
||||||
|
|
||||||
if (roomid != active_room_.id() || !isAppActive)
|
if (roomid != active_room_ || !isAppActive)
|
||||||
emit unreadMessages(roomid, msgs_added);
|
emit unreadMessages(roomid, msgs_added);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineViewManager::setHistoryView(const RoomInfo &info)
|
void TimelineViewManager::setHistoryView(const QString &room_id)
|
||||||
{
|
{
|
||||||
if (!views_.contains(info.id())) {
|
if (!views_.contains(room_id)) {
|
||||||
qDebug() << "Room List id is not present in view manager";
|
qDebug() << "Room ID from RoomList is not present in ViewManager" << room_id;
|
||||||
qDebug() << info.name();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
active_room_ = info;
|
active_room_ = room_id;
|
||||||
auto widget = views_.value(info.id());
|
auto widget = views_.value(room_id);
|
||||||
|
|
||||||
setCurrentWidget(widget);
|
setCurrentWidget(widget);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ matrix::events::EventType matrix::events::extractEventType(const QJsonObject &ob
|
||||||
return EventType::RoomJoinRules;
|
return EventType::RoomJoinRules;
|
||||||
else if (type == "m.room.member")
|
else if (type == "m.room.member")
|
||||||
return EventType::RoomMember;
|
return EventType::RoomMember;
|
||||||
|
else if (type == "m.room.message")
|
||||||
|
return EventType::RoomMessage;
|
||||||
else if (type == "m.room.name")
|
else if (type == "m.room.name")
|
||||||
return EventType::RoomName;
|
return EventType::RoomName;
|
||||||
else if (type == "m.room.power_levels")
|
else if (type == "m.room.power_levels")
|
||||||
|
@ -59,3 +61,22 @@ matrix::events::EventType matrix::events::extractEventType(const QJsonObject &ob
|
||||||
else
|
else
|
||||||
return EventType::Unsupported;
|
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.history_visibility"}}), EventType::RoomHistoryVisibility);
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.join_rules"}}), EventType::RoomJoinRules);
|
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.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.name"}}), EventType::RoomName);
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}), EventType::RoomPowerLevels);
|
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}), EventType::RoomPowerLevels);
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.topic"}}), EventType::RoomTopic);
|
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