mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-22 03:00:46 +03:00
Migrate to matrix-structs for event and response parsing
This commit is contained in:
parent
1976a3280c
commit
a605e4486f
77 changed files with 648 additions and 4962 deletions
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -evx
|
|
||||||
|
|
||||||
sudo apt-get -qq update
|
|
||||||
sudo apt-get install -y libgtest-dev
|
|
||||||
wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz
|
|
||||||
tar xf release-1.8.0.tar.gz
|
|
||||||
cd googletest-release-1.8.0
|
|
||||||
|
|
||||||
cmake -DBUILD_SHARED_LIBS=ON .
|
|
||||||
make
|
|
||||||
sudo cp -a googletest/include/gtest /usr/include
|
|
||||||
sudo cp -a googlemock/gtest/*.so /usr/lib/
|
|
||||||
|
|
||||||
sudo ldconfig -v | grep gtest
|
|
||||||
|
|
||||||
cd $TRAVIS_BUILD_DIR
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -evx
|
|
||||||
|
|
||||||
cmake -DBUILD_TESTS=ON -H. -Bbuild && cmake --build build
|
|
||||||
|
|
||||||
cd build && GTEST_COLOR=1 ctest --verbose
|
|
|
@ -14,7 +14,6 @@ matrix:
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
env:
|
env:
|
||||||
- COMPILER=g++-6
|
- COMPILER=g++-6
|
||||||
- RUN_TESTS=1
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources: ['ubuntu-toolchain-r-test']
|
sources: ['ubuntu-toolchain-r-test']
|
||||||
|
@ -30,7 +29,6 @@ matrix:
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- export CXX=${COMPILER}
|
- export CXX=${COMPILER}
|
||||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/gtest.sh; fi
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install qt5 lmdb clang-format; fi
|
- if [ $TRAVIS_OS_NAME == osx ]; then brew update && brew install qt5 lmdb clang-format; fi
|
||||||
|
@ -45,7 +43,6 @@ script:
|
||||||
- make -C build -j2
|
- make -C build -j2
|
||||||
- if [ $TRAVIS_OS_NAME == osx ]; then make lint; fi
|
- if [ $TRAVIS_OS_NAME == osx ]; then make lint; fi
|
||||||
- if [ $TRAVIS_OS_NAME == osx ]; then ./.ci/macos/deploy.sh; fi
|
- if [ $TRAVIS_OS_NAME == osx ]; then ./.ci/macos/deploy.sh; fi
|
||||||
- if [ $RUN_TESTS == 1 ]; then ./.ci/linux/run-tests.sh; fi
|
|
||||||
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/deploy.sh; fi
|
- if [ $TRAVIS_OS_NAME == linux ]; then ./.ci/linux/deploy.sh; fi
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.1)
|
||||||
|
|
||||||
option(BUILD_TESTS "Build all tests" OFF)
|
|
||||||
option(APPVEYOR_BUILD "Build on appveyor" OFF)
|
option(APPVEYOR_BUILD "Build on appveyor" OFF)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
@ -122,6 +121,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
-Werror \
|
-Werror \
|
||||||
-pipe \
|
-pipe \
|
||||||
-pedantic \
|
-pedantic \
|
||||||
|
-ferror-limit=3 \
|
||||||
-Wunreachable-code")
|
-Wunreachable-code")
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
|
@ -200,7 +200,6 @@ set(SRC_FILES
|
||||||
src/RoomState.cc
|
src/RoomState.cc
|
||||||
src/SideBarActions.cc
|
src/SideBarActions.cc
|
||||||
src/Splitter.cc
|
src/Splitter.cc
|
||||||
src/Sync.cc
|
|
||||||
src/TextInputWidget.cc
|
src/TextInputWidget.cc
|
||||||
src/TopRoomBar.cc
|
src/TopRoomBar.cc
|
||||||
src/TrayIcon.cc
|
src/TrayIcon.cc
|
||||||
|
@ -211,35 +210,8 @@ set(SRC_FILES
|
||||||
src/main.cc
|
src/main.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MATRIX_EVENTS
|
|
||||||
src/events/Event.cc
|
|
||||||
|
|
||||||
src/events/AliasesEventContent.cc
|
|
||||||
src/events/AvatarEventContent.cc
|
|
||||||
src/events/CanonicalAliasEventContent.cc
|
|
||||||
src/events/CreateEventContent.cc
|
|
||||||
src/events/HistoryVisibilityEventContent.cc
|
|
||||||
src/events/JoinRulesEventContent.cc
|
|
||||||
src/events/MemberEventContent.cc
|
|
||||||
src/events/MessageEventContent.cc
|
|
||||||
src/events/NameEventContent.cc
|
|
||||||
src/events/PowerLevelsEventContent.cc
|
|
||||||
src/events/TopicEventContent.cc
|
|
||||||
|
|
||||||
src/events/messages/Audio.cc
|
|
||||||
src/events/messages/Emote.cc
|
|
||||||
src/events/messages/File.cc
|
|
||||||
src/events/messages/Image.cc
|
|
||||||
src/events/messages/Location.cc
|
|
||||||
src/events/messages/Notice.cc
|
|
||||||
src/events/messages/Text.cc
|
|
||||||
src/events/messages/Video.cc
|
|
||||||
)
|
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
include_directories(include/ui)
|
include_directories(include/ui)
|
||||||
include_directories(include/events)
|
|
||||||
include_directories(include/events/messages)
|
|
||||||
|
|
||||||
include_directories(libs/lmdbxx)
|
include_directories(libs/lmdbxx)
|
||||||
include_directories(${LMDB_INCLUDE_DIR})
|
include_directories(${LMDB_INCLUDE_DIR})
|
||||||
|
@ -324,35 +296,9 @@ file(APPEND ${_qrc} "</qresource> </RCC>")
|
||||||
qt5_add_resources(LANG_QRC ${_qrc})
|
qt5_add_resources(LANG_QRC ${_qrc})
|
||||||
qt5_add_resources(QRC resources/res.qrc)
|
qt5_add_resources(QRC resources/res.qrc)
|
||||||
|
|
||||||
#
|
|
||||||
# Matrix events library.
|
|
||||||
#
|
|
||||||
add_library(matrix_events ${MATRIX_EVENTS} src/Deserializable.cc)
|
|
||||||
target_link_libraries(matrix_events Qt5::Core)
|
|
||||||
|
|
||||||
add_subdirectory(libs/matrix-structs)
|
add_subdirectory(libs/matrix-structs)
|
||||||
|
|
||||||
if (BUILD_TESTS)
|
set(COMMON_LIBS matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent)
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
|
||||||
include_directories(${GTEST_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
add_executable(events_test tests/events.cc)
|
|
||||||
target_link_libraries(events_test matrix_events ${GTEST_BOTH_LIBRARIES})
|
|
||||||
|
|
||||||
add_executable(event_collection_test tests/event_collection.cc)
|
|
||||||
target_link_libraries(event_collection_test matrix_events ${GTEST_BOTH_LIBRARIES})
|
|
||||||
|
|
||||||
add_executable(message_events tests/message_events.cc)
|
|
||||||
target_link_libraries(message_events matrix_events ${GTEST_BOTH_LIBRARIES})
|
|
||||||
|
|
||||||
add_test(MatrixEvents events_test)
|
|
||||||
add_test(MatrixEventCollection event_collection_test)
|
|
||||||
add_test(MatrixMessageEvents message_events)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(COMMON_LIBS matrix_events matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent)
|
|
||||||
|
|
||||||
if(APPVEYOR_BUILD)
|
if(APPVEYOR_BUILD)
|
||||||
set(NHEKO_LIBS ${COMMON_LIBS} lmdb)
|
set(NHEKO_LIBS ${COMMON_LIBS} lmdb)
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -1,17 +1,12 @@
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug
|
@cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=Debug
|
||||||
@cmake --build build
|
@cmake --build build
|
||||||
|
|
||||||
release-debug:
|
release-debug:
|
||||||
@cmake -DBUILD_TESTS=OFF -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
@cmake -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
@cmake --build build
|
@cmake --build build
|
||||||
|
|
||||||
test:
|
|
||||||
@cmake -DBUILD_TESTS=ON -H. -GNinja -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
@cmake --build build
|
|
||||||
@cd build && GTEST_COLOR=1 ctest --verbose
|
|
||||||
|
|
||||||
linux-appimage:
|
linux-appimage:
|
||||||
@./.ci/linux/deploy.sh
|
@./.ci/linux/deploy.sh
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "MemberEventContent.h"
|
#include <mtx.hpp>
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "StateEvent.h"
|
|
||||||
|
|
||||||
class Cache;
|
class Cache;
|
||||||
class MatrixClient;
|
class MatrixClient;
|
||||||
|
@ -37,14 +35,11 @@ class RoomSettings;
|
||||||
class RoomState;
|
class RoomState;
|
||||||
class SideBarActions;
|
class SideBarActions;
|
||||||
class Splitter;
|
class Splitter;
|
||||||
class SyncResponse;
|
|
||||||
class TextInputWidget;
|
class TextInputWidget;
|
||||||
class TimelineViewManager;
|
class TimelineViewManager;
|
||||||
class TopRoomBar;
|
class TopRoomBar;
|
||||||
class TypingDisplay;
|
class TypingDisplay;
|
||||||
class UserInfoWidget;
|
class UserInfoWidget;
|
||||||
class JoinedRoom;
|
|
||||||
class LeftRoom;
|
|
||||||
|
|
||||||
constexpr int CONSENSUS_TIMEOUT = 1000;
|
constexpr int CONSENSUS_TIMEOUT = 1000;
|
||||||
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
constexpr int SHOW_CONTENT_TIMEOUT = 3000;
|
||||||
|
@ -76,8 +71,8 @@ private slots:
|
||||||
void updateTopBarAvatar(const QString &roomid, const QPixmap &img);
|
void updateTopBarAvatar(const QString &roomid, const QPixmap &img);
|
||||||
void updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name);
|
void updateOwnProfileInfo(const QUrl &avatar_url, const QString &display_name);
|
||||||
void setOwnAvatar(const QPixmap &img);
|
void setOwnAvatar(const QPixmap &img);
|
||||||
void initialSyncCompleted(const SyncResponse &response);
|
void initialSyncCompleted(const mtx::responses::Sync &response);
|
||||||
void syncCompleted(const SyncResponse &response);
|
void syncCompleted(const mtx::responses::Sync &response);
|
||||||
void syncFailed(const QString &msg);
|
void syncFailed(const QString &msg);
|
||||||
void changeTopRoomInfo(const QString &room_id);
|
void changeTopRoomInfo(const QString &room_id);
|
||||||
void logout();
|
void logout();
|
||||||
|
@ -87,26 +82,34 @@ private slots:
|
||||||
private:
|
private:
|
||||||
using UserID = QString;
|
using UserID = QString;
|
||||||
using RoomStates = QMap<UserID, RoomState>;
|
using RoomStates = QMap<UserID, RoomState>;
|
||||||
using JoinedRooms = QMap<UserID, JoinedRoom>;
|
using Membership = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
using LeftRooms = QMap<UserID, LeftRoom>;
|
using Memberships = std::map<std::string, Membership>;
|
||||||
using Membership = matrix::events::StateEvent<matrix::events::MemberEventContent>;
|
|
||||||
using Memberships = QMap<UserID, Membership>;
|
using JoinedRooms = std::map<std::string, mtx::responses::JoinedRoom>;
|
||||||
|
using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>;
|
||||||
|
|
||||||
void removeLeftRooms(const LeftRooms &rooms);
|
void removeLeftRooms(const LeftRooms &rooms);
|
||||||
void updateJoinedRooms(const JoinedRooms &rooms);
|
void updateJoinedRooms(const JoinedRooms &rooms);
|
||||||
|
|
||||||
Memberships getMemberships(const QJsonArray &events) const;
|
|
||||||
RoomStates generateMembershipDifference(const JoinedRooms &rooms,
|
RoomStates generateMembershipDifference(const JoinedRooms &rooms,
|
||||||
const RoomStates &states) const;
|
const RoomStates &states) const;
|
||||||
|
|
||||||
void updateTypingUsers(const QString &roomid, const QList<QString> &user_ids);
|
void updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids);
|
||||||
void updateUserMetadata(const QJsonArray &events);
|
|
||||||
void updateUserDisplayName(const Membership &event);
|
using MemberEvent = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
void updateUserAvatarUrl(const Membership &event);
|
void updateUserDisplayName(const MemberEvent &event);
|
||||||
|
void updateUserAvatarUrl(const MemberEvent &event);
|
||||||
|
|
||||||
void loadStateFromCache();
|
void loadStateFromCache();
|
||||||
void deleteConfigs();
|
void deleteConfigs();
|
||||||
void resetUI();
|
void resetUI();
|
||||||
|
|
||||||
|
template<class Collection>
|
||||||
|
Memberships getMemberships(const std::vector<Collection> &events) const;
|
||||||
|
|
||||||
|
template<class Collection>
|
||||||
|
void updateUserMetadata(const std::vector<Collection> &collection);
|
||||||
|
|
||||||
QHBoxLayout *topLayout_;
|
QHBoxLayout *topLayout_;
|
||||||
Splitter *splitter;
|
Splitter *splitter;
|
||||||
|
|
||||||
|
@ -153,3 +156,37 @@ private:
|
||||||
// return to the login page.
|
// return to the login page.
|
||||||
int initialSyncFailures = 0;
|
int initialSyncFailures = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Collection>
|
||||||
|
void
|
||||||
|
ChatPage::updateUserMetadata(const std::vector<Collection> &collection)
|
||||||
|
{
|
||||||
|
using Member = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
|
|
||||||
|
for (auto &event : collection) {
|
||||||
|
if (mpark::holds_alternative<Member>(event)) {
|
||||||
|
auto member = mpark::get<Member>(event);
|
||||||
|
|
||||||
|
updateUserAvatarUrl(member);
|
||||||
|
updateUserDisplayName(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Collection>
|
||||||
|
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>>
|
||||||
|
ChatPage::getMemberships(const std::vector<Collection> &collection) const
|
||||||
|
{
|
||||||
|
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> memberships;
|
||||||
|
|
||||||
|
using Member = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
|
|
||||||
|
for (auto &event : collection) {
|
||||||
|
if (mpark::holds_alternative<Member>(event)) {
|
||||||
|
auto member = mpark::get<Member>(event);
|
||||||
|
memberships.emplace(member.state_key, member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memberships;
|
||||||
|
}
|
||||||
|
|
|
@ -20,12 +20,7 @@
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <mtx.hpp>
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
class SyncResponse;
|
|
||||||
class Profile;
|
|
||||||
class RoomMessages;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MatrixClient provides the high level API to communicate with
|
* MatrixClient provides the high level API to communicate with
|
||||||
|
@ -40,7 +35,7 @@ public:
|
||||||
// Client API.
|
// Client API.
|
||||||
void initialSync() noexcept;
|
void initialSync() noexcept;
|
||||||
void sync() noexcept;
|
void sync() noexcept;
|
||||||
void sendRoomMessage(matrix::events::MessageEventType ty,
|
void sendRoomMessage(mtx::events::MessageType ty,
|
||||||
int txnId,
|
int txnId,
|
||||||
const QString &roomid,
|
const QString &roomid,
|
||||||
const QString &msg,
|
const QString &msg,
|
||||||
|
@ -107,15 +102,15 @@ signals:
|
||||||
|
|
||||||
// Returned profile data for the user's account.
|
// Returned profile data for the user's account.
|
||||||
void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name);
|
void getOwnProfileResponse(const QUrl &avatar_url, const QString &display_name);
|
||||||
void initialSyncCompleted(const SyncResponse &response);
|
void initialSyncCompleted(const mtx::responses::Sync &response);
|
||||||
void initialSyncFailed(const QString &msg);
|
void initialSyncFailed(const QString &msg);
|
||||||
void syncCompleted(const SyncResponse &response);
|
void syncCompleted(const mtx::responses::Sync &response);
|
||||||
void syncFailed(const QString &msg);
|
void syncFailed(const QString &msg);
|
||||||
void joinFailed(const QString &msg);
|
void joinFailed(const QString &msg);
|
||||||
void messageSent(const QString &event_id, const QString &roomid, const int txn_id);
|
void messageSent(const QString &event_id, const QString &roomid, const int txn_id);
|
||||||
void messageSendFailed(const QString &roomid, const int txn_id);
|
void messageSendFailed(const QString &roomid, const int txn_id);
|
||||||
void emoteSent(const QString &event_id, const QString &roomid, const int txn_id);
|
void emoteSent(const QString &event_id, const QString &roomid, const int txn_id);
|
||||||
void messagesRetrieved(const QString &room_id, const RoomMessages &msgs);
|
void messagesRetrieved(const QString &room_id, const mtx::responses::Messages &msgs);
|
||||||
void joinedRoom(const QString &room_id);
|
void joinedRoom(const QString &room_id);
|
||||||
void leftRoom(const QString &room_id);
|
void leftRoom(const QString &room_id);
|
||||||
|
|
||||||
|
|
|
@ -21,28 +21,14 @@
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "AliasesEventContent.h"
|
#include <mtx.hpp>
|
||||||
#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"
|
|
||||||
|
|
||||||
#include "Event.h"
|
|
||||||
#include "RoomEvent.h"
|
|
||||||
#include "StateEvent.h"
|
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
|
|
||||||
class RoomState
|
class RoomState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RoomState();
|
RoomState();
|
||||||
RoomState(const QJsonArray &events);
|
RoomState(const mtx::responses::Timeline &timeline);
|
||||||
|
RoomState(const mtx::responses::State &state);
|
||||||
|
|
||||||
// Calculate room data that are not immediatly accessible. Like room name and
|
// Calculate room data that are not immediatly accessible. Like room name and
|
||||||
// avatar.
|
// avatar.
|
||||||
|
@ -50,32 +36,37 @@ public:
|
||||||
// e.g If the room is 1-on-1 name and avatar should be extracted from a user.
|
// e.g If the room is 1-on-1 name and avatar should be extracted from a user.
|
||||||
void resolveName();
|
void resolveName();
|
||||||
void resolveAvatar();
|
void resolveAvatar();
|
||||||
void parse(const QJsonObject &object);
|
void parse(const nlohmann::json &object);
|
||||||
|
|
||||||
QUrl getAvatar() const { return avatar_; };
|
QUrl getAvatar() const { return avatar_; };
|
||||||
QString getName() const { return name_; };
|
QString getName() const { return name_; };
|
||||||
QString getTopic() const { return topic.content().topic().simplified(); };
|
QString getTopic() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(topic.content.topic).simplified();
|
||||||
|
};
|
||||||
|
|
||||||
void removeLeaveMemberships();
|
void removeLeaveMemberships();
|
||||||
void update(const RoomState &state);
|
void update(const RoomState &state);
|
||||||
void updateFromEvents(const QJsonArray &events);
|
|
||||||
|
|
||||||
QJsonObject serialize() const;
|
template<class Collection>
|
||||||
|
void updateFromEvents(const std::vector<Collection> &collection);
|
||||||
|
|
||||||
|
std::string serialize() const;
|
||||||
|
|
||||||
// The latest state events.
|
// The latest state events.
|
||||||
events::StateEvent<events::AliasesEventContent> aliases;
|
mtx::events::StateEvent<mtx::events::state::Aliases> aliases;
|
||||||
events::StateEvent<events::AvatarEventContent> avatar;
|
mtx::events::StateEvent<mtx::events::state::Avatar> avatar;
|
||||||
events::StateEvent<events::CanonicalAliasEventContent> canonical_alias;
|
mtx::events::StateEvent<mtx::events::state::CanonicalAlias> canonical_alias;
|
||||||
events::StateEvent<events::CreateEventContent> create;
|
mtx::events::StateEvent<mtx::events::state::Create> create;
|
||||||
events::StateEvent<events::HistoryVisibilityEventContent> history_visibility;
|
mtx::events::StateEvent<mtx::events::state::HistoryVisibility> history_visibility;
|
||||||
events::StateEvent<events::JoinRulesEventContent> join_rules;
|
mtx::events::StateEvent<mtx::events::state::JoinRules> join_rules;
|
||||||
events::StateEvent<events::NameEventContent> name;
|
mtx::events::StateEvent<mtx::events::state::Name> name;
|
||||||
events::StateEvent<events::PowerLevelsEventContent> power_levels;
|
mtx::events::StateEvent<mtx::events::state::PowerLevels> power_levels;
|
||||||
events::StateEvent<events::TopicEventContent> topic;
|
mtx::events::StateEvent<mtx::events::state::Topic> topic;
|
||||||
|
|
||||||
// Contains the m.room.member events for all the joined users.
|
// Contains the m.room.member events for all the joined users.
|
||||||
using UserID = QString;
|
using UserID = std::string;
|
||||||
QMap<UserID, events::StateEvent<events::MemberEventContent>> memberships;
|
std::map<UserID, mtx::events::StateEvent<mtx::events::state::Member>> memberships;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUrl avatar_;
|
QUrl avatar_;
|
||||||
|
@ -85,3 +76,44 @@ private:
|
||||||
// avatar event this should be empty.
|
// avatar event this should be empty.
|
||||||
QString userAvatar_;
|
QString userAvatar_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class Collection>
|
||||||
|
void
|
||||||
|
RoomState::updateFromEvents(const std::vector<Collection> &collection)
|
||||||
|
{
|
||||||
|
using Aliases = mtx::events::StateEvent<mtx::events::state::Aliases>;
|
||||||
|
using Avatar = mtx::events::StateEvent<mtx::events::state::Avatar>;
|
||||||
|
using CanonicalAlias = mtx::events::StateEvent<mtx::events::state::CanonicalAlias>;
|
||||||
|
using Create = mtx::events::StateEvent<mtx::events::state::Create>;
|
||||||
|
using HistoryVisibility = mtx::events::StateEvent<mtx::events::state::HistoryVisibility>;
|
||||||
|
using JoinRules = mtx::events::StateEvent<mtx::events::state::JoinRules>;
|
||||||
|
using Member = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
|
using Name = mtx::events::StateEvent<mtx::events::state::Name>;
|
||||||
|
using PowerLevels = mtx::events::StateEvent<mtx::events::state::PowerLevels>;
|
||||||
|
using Topic = mtx::events::StateEvent<mtx::events::state::Topic>;
|
||||||
|
|
||||||
|
for (const auto &event : collection) {
|
||||||
|
if (mpark::holds_alternative<Aliases>(event)) {
|
||||||
|
this->aliases = mpark::get<Aliases>(event);
|
||||||
|
} else if (mpark::holds_alternative<Avatar>(event)) {
|
||||||
|
this->avatar = mpark::get<Avatar>(event);
|
||||||
|
} else if (mpark::holds_alternative<CanonicalAlias>(event)) {
|
||||||
|
this->canonical_alias = mpark::get<CanonicalAlias>(event);
|
||||||
|
} else if (mpark::holds_alternative<Create>(event)) {
|
||||||
|
this->create = mpark::get<Create>(event);
|
||||||
|
} else if (mpark::holds_alternative<HistoryVisibility>(event)) {
|
||||||
|
this->history_visibility = mpark::get<HistoryVisibility>(event);
|
||||||
|
} else if (mpark::holds_alternative<JoinRules>(event)) {
|
||||||
|
this->join_rules = mpark::get<JoinRules>(event);
|
||||||
|
} else if (mpark::holds_alternative<Name>(event)) {
|
||||||
|
this->name = mpark::get<Name>(event);
|
||||||
|
} else if (mpark::holds_alternative<Member>(event)) {
|
||||||
|
auto membership = mpark::get<Member>(event);
|
||||||
|
this->memberships.emplace(membership.state_key, membership);
|
||||||
|
} else if (mpark::holds_alternative<PowerLevels>(event)) {
|
||||||
|
this->power_levels = mpark::get<PowerLevels>(event);
|
||||||
|
} else if (mpark::holds_alternative<Topic>(event)) {
|
||||||
|
this->topic = mpark::get<Topic>(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
131
include/Sync.h
131
include/Sync.h
|
@ -1,131 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
class Event : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QJsonObject content() const { return content_; };
|
|
||||||
QJsonObject unsigned_content() const { return unsigned_; };
|
|
||||||
|
|
||||||
QString sender() const { return sender_; };
|
|
||||||
QString state_key() const { return state_key_; };
|
|
||||||
QString type() const { return type_; };
|
|
||||||
QString eventId() const { return event_id_; };
|
|
||||||
|
|
||||||
uint64_t timestamp() const { return origin_server_ts_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonObject content_;
|
|
||||||
QJsonObject unsigned_;
|
|
||||||
|
|
||||||
QString sender_;
|
|
||||||
QString state_key_;
|
|
||||||
QString type_;
|
|
||||||
QString event_id_;
|
|
||||||
|
|
||||||
uint64_t origin_server_ts_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class State : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonArray events() const { return events_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonArray events_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Timeline : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QJsonArray events() const { return events_; };
|
|
||||||
QString previousBatch() const { return prev_batch_; };
|
|
||||||
bool limited() const { return limited_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QJsonArray events_;
|
|
||||||
QString prev_batch_;
|
|
||||||
bool limited_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Add support for account_data, undread_notifications
|
|
||||||
class JoinedRoom : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
State state() const { return state_; };
|
|
||||||
Timeline timeline() const { return timeline_; };
|
|
||||||
QList<QString> typingUserIDs() const { return typingUserIDs_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
State state_;
|
|
||||||
Timeline timeline_;
|
|
||||||
QList<QString> typingUserIDs_;
|
|
||||||
/* AccountData account_data_; */
|
|
||||||
/* UnreadNotifications unread_notifications_; */
|
|
||||||
};
|
|
||||||
|
|
||||||
class LeftRoom : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
State state() const { return state_; };
|
|
||||||
Timeline timeline() const { return timeline_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
State state_;
|
|
||||||
Timeline timeline_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Add support for invited and left rooms.
|
|
||||||
class Rooms : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QMap<QString, JoinedRoom> join() const { return join_; };
|
|
||||||
QMap<QString, LeftRoom> leave() const { return leave_; };
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QMap<QString, JoinedRoom> join_;
|
|
||||||
QMap<QString, LeftRoom> leave_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SyncResponse : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonDocument &data) override;
|
|
||||||
QString nextBatch() const { return next_batch_; };
|
|
||||||
Rooms rooms() const { return rooms_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString next_batch_;
|
|
||||||
Rooms rooms_;
|
|
||||||
};
|
|
|
@ -25,13 +25,10 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "FlatButton.h"
|
#include "FlatButton.h"
|
||||||
#include "Image.h"
|
|
||||||
#include "LoadingIndicator.h"
|
#include "LoadingIndicator.h"
|
||||||
|
|
||||||
#include "emoji/PickButton.h"
|
#include "emoji/PickButton.h"
|
||||||
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
class FilteredTextEdit : public QTextEdit
|
class FilteredTextEdit : public QTextEdit
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
class AliasesEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QList<QString> aliases() const { return aliases_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QList<QString> aliases_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
/*
|
|
||||||
* A picture that is associated with the room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class AvatarEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QUrl url() const { return url_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QUrl url_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,48 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "CanonicalAliasEventContent.h"
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
/*
|
|
||||||
* This event is used to inform the room about which alias should be considered
|
|
||||||
* the canonical one. This could be for display purposes or as suggestion to
|
|
||||||
* users which alias to use to advertise the room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CanonicalAliasEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QString alias() const { return alias_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString alias_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
/*
|
|
||||||
* This is the first event in a room and cannot be changed. It acts as the root
|
|
||||||
* of all other events.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class CreateEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QString creator() const { return creator_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
// The user_id of the room creator. This is set by the homeserver.
|
|
||||||
QString creator_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,183 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class EventType
|
|
||||||
{
|
|
||||||
/// m.room.aliases
|
|
||||||
RoomAliases,
|
|
||||||
/// m.room.avatar
|
|
||||||
RoomAvatar,
|
|
||||||
/// m.room.canonical_alias
|
|
||||||
RoomCanonicalAlias,
|
|
||||||
/// m.room.create
|
|
||||||
RoomCreate,
|
|
||||||
/// m.room.history_visibility
|
|
||||||
RoomHistoryVisibility,
|
|
||||||
/// m.room.join_rules
|
|
||||||
RoomJoinRules,
|
|
||||||
/// m.room.member
|
|
||||||
RoomMember,
|
|
||||||
/// m.room.message
|
|
||||||
RoomMessage,
|
|
||||||
/// m.room.name
|
|
||||||
RoomName,
|
|
||||||
/// m.room.power_levels
|
|
||||||
RoomPowerLevels,
|
|
||||||
/// m.room.topic
|
|
||||||
RoomTopic,
|
|
||||||
// Unsupported event
|
|
||||||
Unsupported,
|
|
||||||
};
|
|
||||||
|
|
||||||
EventType
|
|
||||||
extractEventType(const QJsonObject &data);
|
|
||||||
|
|
||||||
bool
|
|
||||||
isMessageEvent(EventType type);
|
|
||||||
bool
|
|
||||||
isStateEvent(EventType type);
|
|
||||||
|
|
||||||
class UnsignedData
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
double age() const { return age_; }
|
|
||||||
QString transactionId() const { return transaction_id_; }
|
|
||||||
|
|
||||||
bool isEmpty() const { return age_ <= 0 && transaction_id_.isEmpty(); }
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
double age_ = 0;
|
|
||||||
QString transaction_id_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
class Event
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Content content() const;
|
|
||||||
EventType eventType() const;
|
|
||||||
UnsignedData unsignedData() const { return unsignedData_; }
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Content content_;
|
|
||||||
EventType type_;
|
|
||||||
UnsignedData unsignedData_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline Content
|
|
||||||
Event<Content>::content() const
|
|
||||||
{
|
|
||||||
return content_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline EventType
|
|
||||||
Event<Content>::eventType() const
|
|
||||||
{
|
|
||||||
return type_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
void
|
|
||||||
Event<Content>::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("Event is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
content_.deserialize(object.value("content"));
|
|
||||||
type_ = extractEventType(object);
|
|
||||||
|
|
||||||
if (object.contains("unsigned"))
|
|
||||||
unsignedData_.deserialize(object.value("unsigned"));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
QJsonObject
|
|
||||||
Event<Content>::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
switch (type_) {
|
|
||||||
case EventType::RoomAliases:
|
|
||||||
object["type"] = "m.room.aliases";
|
|
||||||
break;
|
|
||||||
case EventType::RoomAvatar:
|
|
||||||
object["type"] = "m.room.avatar";
|
|
||||||
break;
|
|
||||||
case EventType::RoomCanonicalAlias:
|
|
||||||
object["type"] = "m.room.canonical_alias";
|
|
||||||
break;
|
|
||||||
case EventType::RoomCreate:
|
|
||||||
object["type"] = "m.room.create";
|
|
||||||
break;
|
|
||||||
case EventType::RoomHistoryVisibility:
|
|
||||||
object["type"] = "m.room.history_visibility";
|
|
||||||
break;
|
|
||||||
case EventType::RoomJoinRules:
|
|
||||||
object["type"] = "m.room.join_rules";
|
|
||||||
break;
|
|
||||||
case EventType::RoomMember:
|
|
||||||
object["type"] = "m.room.member";
|
|
||||||
break;
|
|
||||||
case EventType::RoomMessage:
|
|
||||||
object["type"] = "m.room.message";
|
|
||||||
break;
|
|
||||||
case EventType::RoomName:
|
|
||||||
object["type"] = "m.room.name";
|
|
||||||
break;
|
|
||||||
case EventType::RoomPowerLevels:
|
|
||||||
object["type"] = "m.room.power_levels";
|
|
||||||
break;
|
|
||||||
case EventType::RoomTopic:
|
|
||||||
object["type"] = "m.room.topic";
|
|
||||||
break;
|
|
||||||
case EventType::Unsupported:
|
|
||||||
qWarning() << "Unsupported type to serialize";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
object["content"] = content_.serialize();
|
|
||||||
|
|
||||||
if (!unsignedData_.isEmpty())
|
|
||||||
object["unsigned"] = unsignedData_.serialize();
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class HistoryVisibility
|
|
||||||
{
|
|
||||||
Invited,
|
|
||||||
Joined,
|
|
||||||
Shared,
|
|
||||||
WorldReadable,
|
|
||||||
};
|
|
||||||
|
|
||||||
class HistoryVisibilityEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HistoryVisibility historyVisibility() const { return history_visibility_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
HistoryVisibility history_visibility_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class JoinRule
|
|
||||||
{
|
|
||||||
// A user who wishes to join the room must first receive
|
|
||||||
// an invite to the room from someone already inside of the room.
|
|
||||||
Invite,
|
|
||||||
|
|
||||||
// Reserved but not yet implemented by the Matrix specification.
|
|
||||||
Knock,
|
|
||||||
|
|
||||||
// Reserved but not yet implemented by the Matrix specification.
|
|
||||||
Private,
|
|
||||||
|
|
||||||
/// Anyone can join the room without any prior action.
|
|
||||||
Public,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Describes how users are allowed to join the room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class JoinRulesEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
JoinRule joinRule() const { return join_rule_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
JoinRule join_rule_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class Membership
|
|
||||||
{
|
|
||||||
// The user is banned.
|
|
||||||
Ban,
|
|
||||||
|
|
||||||
// The user has been invited.
|
|
||||||
Invite,
|
|
||||||
|
|
||||||
// The user has joined.
|
|
||||||
Join,
|
|
||||||
|
|
||||||
// The user has requested to join.
|
|
||||||
Knock,
|
|
||||||
|
|
||||||
// The user has left.
|
|
||||||
Leave,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The current membership state of a user in the room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class MemberEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QUrl avatarUrl() const { return avatar_url_; };
|
|
||||||
QString displayName() const { return display_name_; };
|
|
||||||
Membership membershipState() const { return membership_state_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QUrl avatar_url_;
|
|
||||||
QString display_name_;
|
|
||||||
Membership membership_state_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "MessageEventContent.h"
|
|
||||||
#include "RoomEvent.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
template<class MsgContent>
|
|
||||||
class MessageEvent : public RoomEvent<MessageEventContent>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
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 = 0;
|
|
||||||
|
|
||||||
QString mimetype;
|
|
||||||
};
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class 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 Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QString body() const { return body_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString body_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
/*
|
|
||||||
* A human-friendly room name designed to be displayed to the end-user.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class NameEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QString name() const { return name_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
enum class PowerLevels
|
|
||||||
{
|
|
||||||
User = 0,
|
|
||||||
Moderator = 50,
|
|
||||||
Admin = 100,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Defines the power levels (privileges) of users in the room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class PowerLevelsEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
int banLevel() const { return ban_; };
|
|
||||||
int inviteLevel() const { return invite_; };
|
|
||||||
int kickLevel() const { return kick_; };
|
|
||||||
int redactLevel() const { return redact_; };
|
|
||||||
|
|
||||||
int eventsDefaultLevel() const { return events_default_; };
|
|
||||||
int stateDefaultLevel() const { return state_default_; };
|
|
||||||
int usersDefaultLevel() const { return users_default_; };
|
|
||||||
|
|
||||||
int eventLevel(QString event_type) const;
|
|
||||||
int userLevel(QString user_id) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int ban_ = static_cast<int>(PowerLevels::Moderator);
|
|
||||||
int invite_ = static_cast<int>(PowerLevels::Moderator);
|
|
||||||
int kick_ = static_cast<int>(PowerLevels::Moderator);
|
|
||||||
int redact_ = static_cast<int>(PowerLevels::Moderator);
|
|
||||||
|
|
||||||
int events_default_ = static_cast<int>(PowerLevels::User);
|
|
||||||
int state_default_ = static_cast<int>(PowerLevels::Moderator);
|
|
||||||
int users_default_ = static_cast<int>(PowerLevels::User);
|
|
||||||
|
|
||||||
QMap<QString, int> events_;
|
|
||||||
QMap<QString, int> users_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
#include "Event.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
template<class Content>
|
|
||||||
class RoomEvent : public Event<Content>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString eventId() const;
|
|
||||||
QString roomId() const;
|
|
||||||
QString sender() const;
|
|
||||||
uint64_t timestamp() const;
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString event_id_;
|
|
||||||
QString room_id_;
|
|
||||||
QString sender_;
|
|
||||||
|
|
||||||
uint64_t origin_server_ts_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline QString
|
|
||||||
RoomEvent<Content>::eventId() const
|
|
||||||
{
|
|
||||||
return event_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline QString
|
|
||||||
RoomEvent<Content>::roomId() const
|
|
||||||
{
|
|
||||||
return room_id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline QString
|
|
||||||
RoomEvent<Content>::sender() const
|
|
||||||
{
|
|
||||||
return sender_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline uint64_t
|
|
||||||
RoomEvent<Content>::timestamp() const
|
|
||||||
{
|
|
||||||
return origin_server_ts_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
void
|
|
||||||
RoomEvent<Content>::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
Event<Content>::deserialize(data);
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("event_id"))
|
|
||||||
throw DeserializationException("event_id key is missing");
|
|
||||||
|
|
||||||
if (!object.contains("origin_server_ts"))
|
|
||||||
throw DeserializationException("origin_server_ts key is missing");
|
|
||||||
|
|
||||||
// FIXME: Synapse doesn't include room id?!
|
|
||||||
/* if (!object.contains("room_id")) */
|
|
||||||
/* throw DeserializationException("room_id key is missing"); */
|
|
||||||
|
|
||||||
if (!object.contains("sender"))
|
|
||||||
throw DeserializationException("sender key is missing");
|
|
||||||
|
|
||||||
event_id_ = object.value("event_id").toString();
|
|
||||||
room_id_ = object.value("room_id").toString();
|
|
||||||
sender_ = object.value("sender").toString();
|
|
||||||
origin_server_ts_ = object.value("origin_server_ts").toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
QJsonObject
|
|
||||||
RoomEvent<Content>::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object = Event<Content>::serialize();
|
|
||||||
|
|
||||||
object["event_id"] = event_id_;
|
|
||||||
object["room_id"] = room_id_;
|
|
||||||
object["sender"] = sender_;
|
|
||||||
object["origin_server_ts"] = QJsonValue(static_cast<qint64>(origin_server_ts_));
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "RoomEvent.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
template<class Content>
|
|
||||||
class StateEvent : public RoomEvent<Content>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString stateKey() const;
|
|
||||||
Content previousContent() const;
|
|
||||||
|
|
||||||
void deserialize(const QJsonValue &data);
|
|
||||||
QJsonObject serialize() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString state_key_;
|
|
||||||
Content prev_content_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline QString
|
|
||||||
StateEvent<Content>::stateKey() const
|
|
||||||
{
|
|
||||||
return state_key_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
inline Content
|
|
||||||
StateEvent<Content>::previousContent() const
|
|
||||||
{
|
|
||||||
return prev_content_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
void
|
|
||||||
StateEvent<Content>::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
RoomEvent<Content>::deserialize(data);
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("state_key"))
|
|
||||||
throw DeserializationException("state_key key is missing");
|
|
||||||
|
|
||||||
state_key_ = object.value("state_key").toString();
|
|
||||||
|
|
||||||
if (object.contains("prev_content"))
|
|
||||||
prev_content_.deserialize(object.value("prev_content"));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Content>
|
|
||||||
QJsonObject
|
|
||||||
StateEvent<Content>::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object = RoomEvent<Content>::serialize();
|
|
||||||
|
|
||||||
object["state_key"] = state_key_;
|
|
||||||
|
|
||||||
auto prev = prev_content_.serialize();
|
|
||||||
|
|
||||||
if (!prev.isEmpty())
|
|
||||||
object["prev_content"] = prev;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonValue>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
/*
|
|
||||||
* A topic is a short message detailing what is currently being discussed in the
|
|
||||||
* room.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class TopicEventContent
|
|
||||||
: public Deserializable
|
|
||||||
, public Serializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonValue &data) override;
|
|
||||||
QJsonObject serialize() const override;
|
|
||||||
|
|
||||||
QString topic() const { return topic_; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString topic_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
namespace messages {
|
|
||||||
struct AudioInfo
|
|
||||||
{
|
|
||||||
uint64_t duration;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
QString mimetype;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Audio : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString url() const { return url_; };
|
|
||||||
AudioInfo info() const { return info_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonObject &object) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString url_;
|
|
||||||
AudioInfo info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
namespace messages {
|
|
||||||
class Emote : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void deserialize(const QJsonObject &obj) override;
|
|
||||||
};
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
namespace messages {
|
|
||||||
struct FileInfo
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
QString mimetype;
|
|
||||||
QString thumbnail_url;
|
|
||||||
ThumbnailInfo thumbnail_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
class File : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString url() const { return url_; };
|
|
||||||
QString filename() const { return filename_; };
|
|
||||||
FileInfo info() const { return info_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonObject &object) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString url_;
|
|
||||||
QString filename_;
|
|
||||||
|
|
||||||
FileInfo info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
namespace messages {
|
|
||||||
struct ImageInfo
|
|
||||||
{
|
|
||||||
int h;
|
|
||||||
int w;
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
QString mimetype;
|
|
||||||
QString thumbnail_url;
|
|
||||||
ThumbnailInfo thumbnail_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Image : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString url() const { return url_; };
|
|
||||||
ImageInfo info() const { return info_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonObject &object) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString url_;
|
|
||||||
ImageInfo info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#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:
|
|
||||||
QString geoUri() const { return geo_uri_; };
|
|
||||||
LocationInfo info() const { return info_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonObject &object) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString geo_uri_;
|
|
||||||
|
|
||||||
LocationInfo info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#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
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#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
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace matrix {
|
|
||||||
namespace events {
|
|
||||||
namespace messages {
|
|
||||||
struct VideoInfo
|
|
||||||
{
|
|
||||||
int h;
|
|
||||||
int w;
|
|
||||||
int size = 0;
|
|
||||||
int duration;
|
|
||||||
|
|
||||||
QString mimetype;
|
|
||||||
QString thumbnail_url;
|
|
||||||
ThumbnailInfo thumbnail_info;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Video : public Deserializable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString url() const { return url_; };
|
|
||||||
VideoInfo info() const { return info_; };
|
|
||||||
|
|
||||||
void deserialize(const QJsonObject &object) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString url_;
|
|
||||||
VideoInfo info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace messages
|
|
||||||
} // namespace events
|
|
||||||
} // namespace matrix
|
|
|
@ -25,16 +25,7 @@
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
#include "Audio.h"
|
|
||||||
#include "Emote.h"
|
|
||||||
#include "File.h"
|
|
||||||
#include "Image.h"
|
|
||||||
#include "Notice.h"
|
|
||||||
#include "Text.h"
|
|
||||||
#include "Video.h"
|
|
||||||
|
|
||||||
#include "AvatarProvider.h"
|
#include "AvatarProvider.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "RoomInfoListItem.h"
|
#include "RoomInfoListItem.h"
|
||||||
#include "TimelineViewManager.h"
|
#include "TimelineViewManager.h"
|
||||||
|
|
||||||
|
@ -44,26 +35,23 @@ class VideoItem;
|
||||||
class FileItem;
|
class FileItem;
|
||||||
class Avatar;
|
class Avatar;
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
class TimelineItem : public QWidget
|
class TimelineItem : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TimelineItem(const events::MessageEvent<msgs::Notice> &e,
|
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
TimelineItem(const events::MessageEvent<msgs::Text> &e,
|
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
TimelineItem(const events::MessageEvent<msgs::Emote> &e,
|
TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
// For local messages.
|
// For local messages.
|
||||||
// m.text & m.emote
|
// m.text & m.emote
|
||||||
TimelineItem(events::MessageEventType ty,
|
TimelineItem(mtx::events::MessageType ty,
|
||||||
const QString &userid,
|
const QString &userid,
|
||||||
QString body,
|
QString body,
|
||||||
bool withSender,
|
bool withSender,
|
||||||
|
@ -75,19 +63,19 @@ public:
|
||||||
TimelineItem(VideoItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
|
TimelineItem(VideoItem *item, const QString &userid, bool withSender, QWidget *parent = 0);
|
||||||
|
|
||||||
TimelineItem(ImageItem *img,
|
TimelineItem(ImageItem *img,
|
||||||
const events::MessageEvent<msgs::Image> &e,
|
const mtx::events::RoomEvent<mtx::events::msg::Image> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
TimelineItem(FileItem *file,
|
TimelineItem(FileItem *file,
|
||||||
const events::MessageEvent<msgs::File> &e,
|
const mtx::events::RoomEvent<mtx::events::msg::File> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
TimelineItem(AudioItem *audio,
|
TimelineItem(AudioItem *audio,
|
||||||
const events::MessageEvent<msgs::Audio> &e,
|
const mtx::events::RoomEvent<mtx::events::msg::Audio> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
TimelineItem(VideoItem *video,
|
TimelineItem(VideoItem *video,
|
||||||
const events::MessageEvent<msgs::Video> &e,
|
const mtx::events::RoomEvent<mtx::events::msg::Video> &e,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent);
|
QWidget *parent);
|
||||||
|
|
||||||
|
@ -185,16 +173,17 @@ TimelineItem::setupWidgetLayout(Widget *widget,
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
event_id_ = event.eventId();
|
event_id_ = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(sender);
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||||
event.sender(),
|
sender,
|
||||||
msgDescription,
|
msgDescription,
|
||||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))};
|
||||||
|
|
||||||
generateTimestamp(timestamp);
|
generateTimestamp(timestamp);
|
||||||
|
|
||||||
|
@ -209,7 +198,7 @@ TimelineItem::setupWidgetLayout(Widget *widget,
|
||||||
|
|
||||||
mainLayout_->addLayout(headerLayout_);
|
mainLayout_->addLayout(headerLayout_);
|
||||||
|
|
||||||
AvatarProvider::resolve(event.sender(), this);
|
AvatarProvider::resolve(sender, this);
|
||||||
} else {
|
} else {
|
||||||
setupSimpleLayout();
|
setupSimpleLayout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,39 +27,27 @@
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
#include "Audio.h"
|
#include <mtx.hpp>
|
||||||
#include "Emote.h"
|
|
||||||
#include "File.h"
|
|
||||||
#include "Image.h"
|
|
||||||
#include "Notice.h"
|
|
||||||
#include "Text.h"
|
|
||||||
#include "Video.h"
|
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "TimelineItem.h"
|
#include "TimelineItem.h"
|
||||||
|
|
||||||
class FloatingButton;
|
class FloatingButton;
|
||||||
class RoomMessages;
|
|
||||||
class ScrollBar;
|
class ScrollBar;
|
||||||
class Timeline;
|
|
||||||
struct DescInfo;
|
struct DescInfo;
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
matrix::events::MessageEventType ty;
|
mtx::events::MessageType ty;
|
||||||
int txn_id;
|
int txn_id;
|
||||||
QString body;
|
QString body;
|
||||||
QString filename;
|
QString filename;
|
||||||
QString event_id;
|
QString event_id;
|
||||||
TimelineItem *widget;
|
TimelineItem *widget;
|
||||||
|
|
||||||
PendingMessage(matrix::events::MessageEventType ty,
|
PendingMessage(mtx::events::MessageType ty,
|
||||||
int txn_id,
|
int txn_id,
|
||||||
QString body,
|
QString body,
|
||||||
QString filename,
|
QString filename,
|
||||||
|
@ -86,7 +74,7 @@ class TimelineView : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TimelineView(const Timeline &timeline,
|
TimelineView(const mtx::responses::Timeline &timeline,
|
||||||
QSharedPointer<MatrixClient> client,
|
QSharedPointer<MatrixClient> client,
|
||||||
const QString &room_id,
|
const QString &room_id,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
@ -95,10 +83,10 @@ public:
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
// Add new events at the end of the timeline.
|
// Add new events at the end of the timeline.
|
||||||
int addEvents(const Timeline &timeline);
|
int addEvents(const mtx::responses::Timeline &timeline);
|
||||||
void addUserMessage(matrix::events::MessageEventType ty, const QString &msg);
|
void addUserMessage(mtx::events::MessageType ty, const QString &msg);
|
||||||
|
|
||||||
template<class Widget, events::MessageEventType MsgType>
|
template<class Widget, mtx::events::MessageType MsgType>
|
||||||
void addUserMessage(const QString &url, const QString &filename);
|
void addUserMessage(const QString &url, const QString &filename);
|
||||||
void updatePendingMessage(int txn_id, QString event_id);
|
void updatePendingMessage(int txn_id, QString event_id);
|
||||||
void scrollDown();
|
void scrollDown();
|
||||||
|
@ -109,7 +97,7 @@ public slots:
|
||||||
void fetchHistory();
|
void fetchHistory();
|
||||||
|
|
||||||
// Add old events at the top of the timeline.
|
// Add old events at the top of the timeline.
|
||||||
void addBackwardsEvents(const QString &room_id, const RoomMessages &msgs);
|
void addBackwardsEvents(const QString &room_id, const mtx::responses::Messages &msgs);
|
||||||
|
|
||||||
// Whether or not the initial batch has been loaded.
|
// Whether or not the initial batch has been loaded.
|
||||||
bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; }
|
bool hasLoaded() { return scroll_layout_->count() > 1 || isTimelineFinished; }
|
||||||
|
@ -135,13 +123,14 @@ private:
|
||||||
void notifyForLastEvent();
|
void notifyForLastEvent();
|
||||||
void readLastEvent() const;
|
void readLastEvent() const;
|
||||||
QString getLastEventId() const;
|
QString getLastEventId() const;
|
||||||
|
QString getEventSender(const mtx::events::collections::TimelineEvents &event) const;
|
||||||
|
|
||||||
template<class Event, class Widget>
|
template<class Event, class Widget>
|
||||||
TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction);
|
TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction);
|
||||||
|
|
||||||
// TODO: Remove this eventually.
|
// TODO: Remove this eventually.
|
||||||
template<class Event>
|
template<class Event>
|
||||||
TimelineItem *processMessageEvent(const QJsonObject &event, TimelineDirection direction);
|
TimelineItem *processMessageEvent(const Event &event, TimelineDirection direction);
|
||||||
|
|
||||||
// For events with custom display widgets.
|
// For events with custom display widgets.
|
||||||
template<class Event, class Widget>
|
template<class Event, class Widget>
|
||||||
|
@ -164,7 +153,8 @@ private:
|
||||||
void handleNewUserMessage(PendingMessage msg);
|
void handleNewUserMessage(PendingMessage msg);
|
||||||
|
|
||||||
// Return nullptr if the event couldn't be parsed.
|
// Return nullptr if the event couldn't be parsed.
|
||||||
TimelineItem *parseMessageEvent(const QJsonObject &event, TimelineDirection direction);
|
TimelineItem *parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
|
||||||
|
TimelineDirection direction);
|
||||||
|
|
||||||
QVBoxLayout *top_layout_;
|
QVBoxLayout *top_layout_;
|
||||||
QVBoxLayout *scroll_layout_;
|
QVBoxLayout *scroll_layout_;
|
||||||
|
@ -207,7 +197,7 @@ private:
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Widget, events::MessageEventType MsgType>
|
template<class Widget, mtx::events::MessageType MsgType>
|
||||||
void
|
void
|
||||||
TimelineView::addUserMessage(const QString &url, const QString &filename)
|
TimelineView::addUserMessage(const QString &url, const QString &filename)
|
||||||
{
|
{
|
||||||
|
@ -252,62 +242,50 @@ TimelineView::createTimelineItem(const Event &event, bool withSender)
|
||||||
|
|
||||||
template<class Event>
|
template<class Event>
|
||||||
TimelineItem *
|
TimelineItem *
|
||||||
TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction)
|
TimelineView::processMessageEvent(const Event &event, TimelineDirection direction)
|
||||||
{
|
{
|
||||||
Event event;
|
const auto event_id = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
try {
|
if (isDuplicate(event_id))
|
||||||
event.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
qWarning() << e.what() << data;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDuplicate(event.eventId()))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
eventIds_[event.eventId()] = true;
|
eventIds_[event_id] = true;
|
||||||
|
|
||||||
QString txnid = event.unsignedData().transactionId();
|
const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id);
|
||||||
if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) {
|
if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) {
|
||||||
removePendingMessage(txnid);
|
removePendingMessage(txnid);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto with_sender = isSenderRendered(event.sender(), direction);
|
auto with_sender = isSenderRendered(sender, direction);
|
||||||
|
|
||||||
updateLastSender(event.sender(), direction);
|
updateLastSender(sender, direction);
|
||||||
|
|
||||||
return createTimelineItem<Event>(event, with_sender);
|
return createTimelineItem<Event>(event, with_sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Event, class Widget>
|
template<class Event, class Widget>
|
||||||
TimelineItem *
|
TimelineItem *
|
||||||
TimelineView::processMessageEvent(const QJsonObject &data, TimelineDirection direction)
|
TimelineView::processMessageEvent(const Event &event, TimelineDirection direction)
|
||||||
{
|
{
|
||||||
Event event;
|
const auto event_id = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
try {
|
if (isDuplicate(event_id))
|
||||||
event.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
qWarning() << e.what() << data;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDuplicate(event.eventId()))
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
eventIds_[event.eventId()] = true;
|
eventIds_[event_id] = true;
|
||||||
|
|
||||||
QString txnid = event.unsignedData().transactionId();
|
const QString txnid = QString::fromStdString(event.unsigned_data.transaction_id);
|
||||||
if (!txnid.isEmpty() && isPendingMessage(txnid, event.sender(), local_user_)) {
|
if (!txnid.isEmpty() && isPendingMessage(txnid, sender, local_user_)) {
|
||||||
removePendingMessage(txnid);
|
removePendingMessage(txnid);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto with_sender = isSenderRendered(event.sender(), direction);
|
auto with_sender = isSenderRendered(sender, direction);
|
||||||
|
|
||||||
updateLastSender(event.sender(), direction);
|
updateLastSender(sender, direction);
|
||||||
|
|
||||||
return createTimelineItem<Event, Widget>(event, with_sender);
|
return createTimelineItem<Event, Widget>(event, with_sender);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,10 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
|
|
||||||
#include "MessageEvent.h"
|
#include <mtx.hpp>
|
||||||
|
|
||||||
class JoinedRoom;
|
|
||||||
class MatrixClient;
|
class MatrixClient;
|
||||||
class RoomInfoListItem;
|
class RoomInfoListItem;
|
||||||
class Rooms;
|
|
||||||
class TimelineView;
|
class TimelineView;
|
||||||
struct DescInfo;
|
struct DescInfo;
|
||||||
|
|
||||||
|
@ -39,14 +37,14 @@ public:
|
||||||
~TimelineViewManager();
|
~TimelineViewManager();
|
||||||
|
|
||||||
// Initialize with timeline events.
|
// Initialize with timeline events.
|
||||||
void initialize(const Rooms &rooms);
|
void initialize(const mtx::responses::Rooms &rooms);
|
||||||
// Empty initialization.
|
// Empty initialization.
|
||||||
void initialize(const QList<QString> &rooms);
|
void initialize(const QList<QString> &rooms);
|
||||||
|
|
||||||
void addRoom(const JoinedRoom &room, const QString &room_id);
|
void addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id);
|
||||||
void addRoom(const QString &room_id);
|
void addRoom(const QString &room_id);
|
||||||
|
|
||||||
void sync(const Rooms &rooms);
|
void sync(const mtx::responses::Rooms &rooms);
|
||||||
void clearAll();
|
void clearAll();
|
||||||
|
|
||||||
// Check if all the timelines have been loaded.
|
// Check if all the timelines have been loaded.
|
||||||
|
|
|
@ -24,12 +24,9 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Audio.h"
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace events = matrix::events;
|
#include <mtx.hpp>
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
class AudioItem : public QWidget
|
class AudioItem : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -46,7 +43,7 @@ class AudioItem : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioItem(QSharedPointer<MatrixClient> client,
|
AudioItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::Audio> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Audio> &event,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
AudioItem(QSharedPointer<MatrixClient> client,
|
AudioItem(QSharedPointer<MatrixClient> client,
|
||||||
|
@ -94,7 +91,7 @@ private:
|
||||||
QString readableFileSize_;
|
QString readableFileSize_;
|
||||||
QString filenameToSave_;
|
QString filenameToSave_;
|
||||||
|
|
||||||
events::MessageEvent<msgs::Audio> event_;
|
mtx::events::RoomEvent<mtx::events::msg::Audio> event_;
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
|
|
||||||
QMediaPlayer *player_;
|
QMediaPlayer *player_;
|
||||||
|
|
|
@ -23,12 +23,9 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "File.h"
|
#include <mtx.hpp>
|
||||||
#include "MatrixClient.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace events = matrix::events;
|
#include "MatrixClient.h"
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
class FileItem : public QWidget
|
class FileItem : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -40,7 +37,7 @@ class FileItem : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileItem(QSharedPointer<MatrixClient> client,
|
FileItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::File> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::File> &event,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
FileItem(QSharedPointer<MatrixClient> client,
|
FileItem(QSharedPointer<MatrixClient> client,
|
||||||
|
@ -75,7 +72,7 @@ private:
|
||||||
QString readableFileSize_;
|
QString readableFileSize_;
|
||||||
QString filenameToSave_;
|
QString filenameToSave_;
|
||||||
|
|
||||||
events::MessageEvent<msgs::File> event_;
|
mtx::events::RoomEvent<mtx::events::msg::File> event_;
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
|
|
||||||
QIcon icon_;
|
QIcon icon_;
|
||||||
|
|
|
@ -22,19 +22,16 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Image.h"
|
#include <mtx.hpp>
|
||||||
#include "MatrixClient.h"
|
|
||||||
#include "MessageEvent.h"
|
|
||||||
|
|
||||||
namespace events = matrix::events;
|
#include "MatrixClient.h"
|
||||||
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 events::MessageEvent<msgs::Image> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Image> &event,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
ImageItem(QSharedPointer<MatrixClient> client,
|
ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
|
@ -72,7 +69,7 @@ private:
|
||||||
|
|
||||||
int bottom_height_ = 30;
|
int bottom_height_ = 30;
|
||||||
|
|
||||||
events::MessageEvent<msgs::Image> event_;
|
mtx::events::RoomEvent<mtx::events::msg::Image> event_;
|
||||||
|
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,11 +23,8 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "Video.h"
|
|
||||||
|
|
||||||
namespace events = matrix::events;
|
#include <mtx.hpp>
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
class VideoItem : public QWidget
|
class VideoItem : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -35,7 +32,7 @@ class VideoItem : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VideoItem(QSharedPointer<MatrixClient> client,
|
VideoItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::Video> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Video> &event,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
VideoItem(QSharedPointer<MatrixClient> client,
|
VideoItem(QSharedPointer<MatrixClient> client,
|
||||||
|
@ -53,6 +50,6 @@ private:
|
||||||
|
|
||||||
QLabel *label_;
|
QLabel *label_;
|
||||||
|
|
||||||
events::MessageEvent<msgs::Video> event_;
|
mtx::events::RoomEvent<mtx::events::msg::Video> event_;
|
||||||
QSharedPointer<MatrixClient> client_;
|
QSharedPointer<MatrixClient> client_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 190f297478153930780a119268b908076599c8db
|
Subproject commit ea10ea843bccebf54b7b4ebdf1be92a3624597b4
|
65
src/Cache.cc
65
src/Cache.cc
|
@ -22,11 +22,8 @@
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "MemberEventContent.h"
|
|
||||||
#include "RoomState.h"
|
#include "RoomState.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
|
|
||||||
static const lmdb::val NEXT_BATCH_KEY("next_batch");
|
static const lmdb::val NEXT_BATCH_KEY("next_batch");
|
||||||
static const lmdb::val transactionID("transaction_id");
|
static const lmdb::val transactionID("transaction_id");
|
||||||
|
|
||||||
|
@ -122,13 +119,10 @@ Cache::setState(const QString &nextBatchToken, const QMap<QString, RoomState> &s
|
||||||
void
|
void
|
||||||
Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state)
|
Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state)
|
||||||
{
|
{
|
||||||
auto stateEvents = QJsonDocument(state.serialize()).toBinaryData();
|
auto stateEvents = state.serialize();
|
||||||
auto id = roomid.toUtf8();
|
auto id = roomid.toUtf8();
|
||||||
|
|
||||||
lmdb::dbi_put(txn,
|
lmdb::dbi_put(txn, roomDb_, lmdb::val(id.data(), id.size()), lmdb::val(stateEvents));
|
||||||
roomDb_,
|
|
||||||
lmdb::val(id.data(), id.size()),
|
|
||||||
lmdb::val(stateEvents.data(), stateEvents.size()));
|
|
||||||
|
|
||||||
for (const auto &membership : state.memberships) {
|
for (const auto &membership : state.memberships) {
|
||||||
lmdb::dbi membersDb =
|
lmdb::dbi membersDb =
|
||||||
|
@ -136,31 +130,29 @@ Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &s
|
||||||
|
|
||||||
// The user_id this membership event relates to, is used
|
// The user_id this membership event relates to, is used
|
||||||
// as the index on the membership database.
|
// as the index on the membership database.
|
||||||
auto key = membership.stateKey().toUtf8();
|
auto key = membership.second.state_key;
|
||||||
auto memberEvent = QJsonDocument(membership.serialize()).toBinaryData();
|
|
||||||
|
|
||||||
switch (membership.content().membershipState()) {
|
// Serialize membership event.
|
||||||
|
nlohmann::json data = membership.second;
|
||||||
|
std::string memberEvent = data.dump();
|
||||||
|
|
||||||
|
switch (membership.second.content.membership) {
|
||||||
// We add or update (e.g invite -> join) a new user to the membership
|
// We add or update (e.g invite -> join) a new user to the membership
|
||||||
// list.
|
// list.
|
||||||
case events::Membership::Invite:
|
case mtx::events::state::Membership::Invite:
|
||||||
case events::Membership::Join: {
|
case mtx::events::state::Membership::Join: {
|
||||||
lmdb::dbi_put(txn,
|
lmdb::dbi_put(txn, membersDb, lmdb::val(key), lmdb::val(memberEvent));
|
||||||
membersDb,
|
|
||||||
lmdb::val(key.data(), key.size()),
|
|
||||||
lmdb::val(memberEvent.data(), memberEvent.size()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We remove the user from the membership list.
|
// We remove the user from the membership list.
|
||||||
case events::Membership::Leave:
|
case mtx::events::state::Membership::Leave:
|
||||||
case events::Membership::Ban: {
|
case mtx::events::state::Membership::Ban: {
|
||||||
lmdb::dbi_del(txn,
|
lmdb::dbi_del(txn, membersDb, lmdb::val(key), lmdb::val(memberEvent));
|
||||||
membersDb,
|
|
||||||
lmdb::val(key.data(), key.size()),
|
|
||||||
lmdb::val(memberEvent.data(), memberEvent.size()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case events::Membership::Knock: {
|
case mtx::events::state::Membership::Knock: {
|
||||||
qWarning() << "Skipping knock membership" << roomid << key;
|
qWarning()
|
||||||
|
<< "Skipping knock membership" << roomid << QString::fromStdString(key);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,14 +186,13 @@ Cache::states()
|
||||||
// Retrieve all the room names.
|
// Retrieve all the room names.
|
||||||
while (cursor.get(room, stateData, MDB_NEXT)) {
|
while (cursor.get(room, stateData, MDB_NEXT)) {
|
||||||
auto roomid = QString::fromUtf8(room.data(), room.size());
|
auto roomid = QString::fromUtf8(room.data(), room.size());
|
||||||
auto json =
|
auto json = nlohmann::json::parse(stateData);
|
||||||
QJsonDocument::fromBinaryData(QByteArray(stateData.data(), stateData.size()));
|
|
||||||
|
|
||||||
RoomState state;
|
RoomState state;
|
||||||
state.parse(json.object());
|
state.parse(json);
|
||||||
|
|
||||||
auto memberDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
|
auto memberDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
|
||||||
QMap<QString, events::StateEvent<events::MemberEventContent>> members;
|
std::map<std::string, mtx::events::StateEvent<mtx::events::state::Member>> members;
|
||||||
|
|
||||||
auto memberCursor = lmdb::cursor::open(txn, memberDb);
|
auto memberCursor = lmdb::cursor::open(txn, memberDb);
|
||||||
|
|
||||||
|
@ -209,17 +200,15 @@ Cache::states()
|
||||||
std::string memberContent;
|
std::string memberContent;
|
||||||
|
|
||||||
while (memberCursor.get(memberId, memberContent, MDB_NEXT)) {
|
while (memberCursor.get(memberId, memberContent, MDB_NEXT)) {
|
||||||
auto userid = QString::fromUtf8(memberId.data(), memberId.size());
|
auto userid = QString::fromStdString(memberId);
|
||||||
auto data = QJsonDocument::fromBinaryData(
|
|
||||||
QByteArray(memberContent.data(), memberContent.size()));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
events::StateEvent<events::MemberEventContent> member;
|
auto data = nlohmann::json::parse(memberContent);
|
||||||
member.deserialize(data.object());
|
mtx::events::StateEvent<mtx::events::state::Member> member = data;
|
||||||
members.insert(userid, member);
|
members.emplace(memberId, member);
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << e.what();
|
qWarning() << "Fault while parsing member event" << e.what()
|
||||||
qWarning() << "Fault while parsing member event" << data.object();
|
<< QString::fromStdString(memberContent);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
278
src/ChatPage.cc
278
src/ChatPage.cc
|
@ -32,7 +32,6 @@
|
||||||
#include "RoomState.h"
|
#include "RoomState.h"
|
||||||
#include "SideBarActions.h"
|
#include "SideBarActions.h"
|
||||||
#include "Splitter.h"
|
#include "Splitter.h"
|
||||||
#include "Sync.h"
|
|
||||||
#include "TextInputWidget.h"
|
#include "TextInputWidget.h"
|
||||||
#include "Theme.h"
|
#include "Theme.h"
|
||||||
#include "TopRoomBar.h"
|
#include "TopRoomBar.h"
|
||||||
|
@ -44,8 +43,6 @@
|
||||||
constexpr int MAX_INITIAL_SYNC_FAILURES = 5;
|
constexpr int MAX_INITIAL_SYNC_FAILURES = 5;
|
||||||
constexpr int SYNC_RETRY_TIMEOUT = 10000;
|
constexpr int SYNC_RETRY_TIMEOUT = 10000;
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
|
|
||||||
ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, client_(client)
|
, client_(client)
|
||||||
|
@ -219,15 +216,13 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
view_manager_->queueAudioMessage(roomid, filename, url);
|
view_manager_->queueAudioMessage(roomid, filename, url);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(client_.data(),
|
connect(
|
||||||
SIGNAL(roomAvatarRetrieved(const QString &, const QPixmap &)),
|
client_.data(), &MatrixClient::roomAvatarRetrieved, this, &ChatPage::updateTopBarAvatar);
|
||||||
this,
|
|
||||||
SLOT(updateTopBarAvatar(const QString &, const QPixmap &)));
|
|
||||||
|
|
||||||
connect(client_.data(),
|
connect(client_.data(),
|
||||||
SIGNAL(initialSyncCompleted(const SyncResponse &)),
|
&MatrixClient::initialSyncCompleted,
|
||||||
this,
|
this,
|
||||||
SLOT(initialSyncCompleted(const SyncResponse &)));
|
&ChatPage::initialSyncCompleted);
|
||||||
connect(client_.data(), &MatrixClient::initialSyncFailed, this, [=](const QString &msg) {
|
connect(client_.data(), &MatrixClient::initialSyncFailed, this, [=](const QString &msg) {
|
||||||
if (client_->getHomeServer().isEmpty()) {
|
if (client_->getHomeServer().isEmpty()) {
|
||||||
deleteConfigs();
|
deleteConfigs();
|
||||||
|
@ -251,29 +246,17 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
|
|
||||||
client_->initialSync();
|
client_->initialSync();
|
||||||
});
|
});
|
||||||
connect(client_.data(),
|
connect(client_.data(), &MatrixClient::syncCompleted, this, &ChatPage::syncCompleted);
|
||||||
SIGNAL(syncCompleted(const SyncResponse &)),
|
connect(client_.data(), &MatrixClient::syncFailed, this, &ChatPage::syncFailed);
|
||||||
this,
|
|
||||||
SLOT(syncCompleted(const SyncResponse &)));
|
|
||||||
connect(client_.data(),
|
|
||||||
SIGNAL(syncFailed(const QString &)),
|
|
||||||
this,
|
|
||||||
SLOT(syncFailed(const QString &)));
|
|
||||||
connect(client_.data(),
|
connect(client_.data(),
|
||||||
&MatrixClient::getOwnProfileResponse,
|
&MatrixClient::getOwnProfileResponse,
|
||||||
this,
|
this,
|
||||||
&ChatPage::updateOwnProfileInfo);
|
&ChatPage::updateOwnProfileInfo);
|
||||||
connect(client_.data(),
|
connect(client_.data(), &MatrixClient::ownAvatarRetrieved, this, &ChatPage::setOwnAvatar);
|
||||||
SIGNAL(ownAvatarRetrieved(const QPixmap &)),
|
|
||||||
this,
|
|
||||||
SLOT(setOwnAvatar(const QPixmap &)));
|
|
||||||
connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() {
|
connect(client_.data(), &MatrixClient::joinedRoom, this, [=]() {
|
||||||
emit showNotification("You joined the room.");
|
emit showNotification("You joined the room.");
|
||||||
});
|
});
|
||||||
connect(client_.data(),
|
connect(client_.data(), &MatrixClient::leftRoom, this, &ChatPage::removeRoom);
|
||||||
SIGNAL(leftRoom(const QString &)),
|
|
||||||
this,
|
|
||||||
SLOT(removeRoom(const QString &)));
|
|
||||||
|
|
||||||
showContentTimer_ = new QTimer(this);
|
showContentTimer_ = new QTimer(this);
|
||||||
showContentTimer_->setSingleShot(true);
|
showContentTimer_->setSingleShot(true);
|
||||||
|
@ -383,32 +366,34 @@ ChatPage::syncFailed(const QString &msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::syncCompleted(const SyncResponse &response)
|
ChatPage::syncCompleted(const mtx::responses::Sync &response)
|
||||||
{
|
{
|
||||||
updateJoinedRooms(response.rooms().join());
|
updateJoinedRooms(response.rooms.join);
|
||||||
removeLeftRooms(response.rooms().leave());
|
removeLeftRooms(response.rooms.leave);
|
||||||
|
|
||||||
auto stateDiff = generateMembershipDifference(response.rooms().join(), state_manager_);
|
const auto nextBatchToken = QString::fromStdString(response.next_batch);
|
||||||
QtConcurrent::run(cache_.data(), &Cache::setState, response.nextBatch(), stateDiff);
|
|
||||||
|
auto stateDiff = generateMembershipDifference(response.rooms.join, state_manager_);
|
||||||
|
QtConcurrent::run(cache_.data(), &Cache::setState, nextBatchToken, stateDiff);
|
||||||
|
|
||||||
room_list_->sync(state_manager_, settingsManager_);
|
room_list_->sync(state_manager_, settingsManager_);
|
||||||
view_manager_->sync(response.rooms());
|
view_manager_->sync(response.rooms);
|
||||||
|
|
||||||
client_->setNextBatchToken(response.nextBatch());
|
client_->setNextBatchToken(nextBatchToken);
|
||||||
client_->sync();
|
client_->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::initialSyncCompleted(const SyncResponse &response)
|
ChatPage::initialSyncCompleted(const mtx::responses::Sync &response)
|
||||||
{
|
{
|
||||||
auto joined = response.rooms().join();
|
auto joined = response.rooms.join;
|
||||||
|
|
||||||
for (auto it = joined.constBegin(); it != joined.constEnd(); ++it) {
|
for (auto it = joined.cbegin(); it != joined.cend(); ++it) {
|
||||||
RoomState room_state;
|
RoomState room_state;
|
||||||
|
|
||||||
// Build the current state from the timeline and state events.
|
// Build the current state from the timeline and state events.
|
||||||
room_state.updateFromEvents(it.value().state().events());
|
room_state.updateFromEvents(it->second.state.events);
|
||||||
room_state.updateFromEvents(it.value().timeline().events());
|
room_state.updateFromEvents(it->second.timeline.events);
|
||||||
|
|
||||||
// Remove redundant memberships.
|
// Remove redundant memberships.
|
||||||
room_state.removeLeaveMemberships();
|
room_state.removeLeaveMemberships();
|
||||||
|
@ -417,27 +402,32 @@ ChatPage::initialSyncCompleted(const SyncResponse &response)
|
||||||
room_state.resolveName();
|
room_state.resolveName();
|
||||||
room_state.resolveAvatar();
|
room_state.resolveAvatar();
|
||||||
|
|
||||||
state_manager_.insert(it.key(), room_state);
|
const auto room_id = QString::fromStdString(it->first);
|
||||||
settingsManager_.insert(it.key(),
|
|
||||||
QSharedPointer<RoomSettings>(new RoomSettings(it.key())));
|
state_manager_.insert(room_id, room_state);
|
||||||
|
settingsManager_.insert(room_id,
|
||||||
|
QSharedPointer<RoomSettings>(new RoomSettings(room_id)));
|
||||||
|
|
||||||
for (const auto membership : room_state.memberships) {
|
for (const auto membership : room_state.memberships) {
|
||||||
updateUserDisplayName(membership);
|
updateUserDisplayName(membership.second);
|
||||||
updateUserAvatarUrl(membership);
|
updateUserAvatarUrl(membership.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
QtConcurrent::run(cache_.data(), &Cache::setState, response.nextBatch(), state_manager_);
|
QtConcurrent::run(cache_.data(),
|
||||||
|
&Cache::setState,
|
||||||
|
QString::fromStdString(response.next_batch),
|
||||||
|
state_manager_);
|
||||||
|
|
||||||
// Populate timelines with messages.
|
// Populate timelines with messages.
|
||||||
view_manager_->initialize(response.rooms());
|
view_manager_->initialize(response.rooms);
|
||||||
|
|
||||||
// Initialize room list.
|
// Initialize room list.
|
||||||
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
room_list_->setInitialRooms(settingsManager_, state_manager_);
|
||||||
|
|
||||||
client_->setNextBatchToken(response.nextBatch());
|
client_->setNextBatchToken(QString::fromStdString(response.next_batch));
|
||||||
client_->sync();
|
client_->sync();
|
||||||
|
|
||||||
emit contentLoaded();
|
emit contentLoaded();
|
||||||
|
@ -527,8 +517,8 @@ ChatPage::loadStateFromCache()
|
||||||
|
|
||||||
// Resolve user avatars.
|
// Resolve user avatars.
|
||||||
for (const auto membership : room_state.memberships) {
|
for (const auto membership : room_state.memberships) {
|
||||||
updateUserDisplayName(membership);
|
updateUserDisplayName(membership.second);
|
||||||
updateUserAvatarUrl(membership);
|
updateUserAvatarUrl(membership.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +569,8 @@ ChatPage::showQuickSwitcher()
|
||||||
QMap<QString, QString> rooms;
|
QMap<QString, QString> rooms;
|
||||||
|
|
||||||
for (auto it = state_manager_.constBegin(); it != state_manager_.constEnd(); ++it) {
|
for (auto it = state_manager_.constBegin(); it != state_manager_.constEnd(); ++it) {
|
||||||
QString deambiguator = it.value().canonical_alias.content().alias();
|
QString deambiguator =
|
||||||
|
QString::fromStdString(it.value().canonical_alias.content.alias);
|
||||||
if (deambiguator == "")
|
if (deambiguator == "")
|
||||||
deambiguator = it.key();
|
deambiguator = it.key();
|
||||||
rooms.insert(it.value().getName() + " (" + deambiguator + ")", it.key());
|
rooms.insert(it.value().getName() + " (" + deambiguator + ")", it.key());
|
||||||
|
@ -623,7 +614,7 @@ ChatPage::removeRoom(const QString &room_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_ids)
|
ChatPage::updateTypingUsers(const QString &roomid, const std::vector<std::string> &user_ids)
|
||||||
{
|
{
|
||||||
QStringList users;
|
QStringList users;
|
||||||
|
|
||||||
|
@ -631,9 +622,12 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_id
|
||||||
QString user_id = settings.value("auth/user_id").toString();
|
QString user_id = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
for (const auto uid : user_ids) {
|
for (const auto uid : user_ids) {
|
||||||
if (uid == user_id)
|
auto user = QString::fromStdString(uid);
|
||||||
|
|
||||||
|
if (user == user_id)
|
||||||
continue;
|
continue;
|
||||||
users.append(TimelineViewManager::displayName(uid));
|
|
||||||
|
users.append(TimelineViewManager::displayName(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
users.sort();
|
users.sort();
|
||||||
|
@ -646,186 +640,118 @@ ChatPage::updateTypingUsers(const QString &roomid, const QList<QString> &user_id
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::updateUserMetadata(const QJsonArray &events)
|
ChatPage::updateUserAvatarUrl(const mtx::events::StateEvent<mtx::events::state::Member> &membership)
|
||||||
{
|
{
|
||||||
events::EventType ty;
|
auto uid = QString::fromStdString(membership.sender);
|
||||||
|
auto url = QString::fromStdString(membership.content.avatar_url);
|
||||||
|
|
||||||
for (const auto &event : events) {
|
if (!url.isEmpty())
|
||||||
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::RoomMember: {
|
|
||||||
events::StateEvent<events::MemberEventContent> member;
|
|
||||||
member.deserialize(event);
|
|
||||||
|
|
||||||
updateUserAvatarUrl(member);
|
|
||||||
updateUserDisplayName(member);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
qWarning() << e.what() << event;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ChatPage::updateUserAvatarUrl(const events::StateEvent<events::MemberEventContent> &membership)
|
|
||||||
{
|
|
||||||
auto uid = membership.sender();
|
|
||||||
auto url = membership.content().avatarUrl();
|
|
||||||
|
|
||||||
if (!url.toString().isEmpty())
|
|
||||||
AvatarProvider::setAvatarUrl(uid, url);
|
AvatarProvider::setAvatarUrl(uid, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::updateUserDisplayName(const events::StateEvent<events::MemberEventContent> &membership)
|
ChatPage::updateUserDisplayName(
|
||||||
|
const mtx::events::StateEvent<mtx::events::state::Member> &membership)
|
||||||
{
|
{
|
||||||
auto displayName = membership.content().displayName();
|
auto displayName = QString::fromStdString(membership.content.display_name);
|
||||||
|
auto stateKey = QString::fromStdString(membership.state_key);
|
||||||
|
|
||||||
if (!displayName.isEmpty())
|
if (!displayName.isEmpty())
|
||||||
TimelineViewManager::DISPLAY_NAMES.insert(membership.stateKey(), displayName);
|
TimelineViewManager::DISPLAY_NAMES.insert(stateKey, displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::removeLeftRooms(const QMap<QString, LeftRoom> &rooms)
|
ChatPage::removeLeftRooms(const std::map<std::string, mtx::responses::LeftRoom> &rooms)
|
||||||
{
|
{
|
||||||
for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) {
|
for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) {
|
||||||
if (state_manager_.contains(it.key()))
|
const auto room_id = QString::fromStdString(it->first);
|
||||||
removeRoom(it.key());
|
|
||||||
|
if (state_manager_.contains(room_id))
|
||||||
|
removeRoom(room_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ChatPage::updateJoinedRooms(const QMap<QString, JoinedRoom> &rooms)
|
ChatPage::updateJoinedRooms(const std::map<std::string, mtx::responses::JoinedRoom> &rooms)
|
||||||
{
|
{
|
||||||
for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) {
|
for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) {
|
||||||
updateTypingUsers(it.key(), it.value().typingUserIDs());
|
const auto roomid = QString::fromStdString(it->first);
|
||||||
|
|
||||||
const auto newStateEvents = it.value().state().events();
|
updateTypingUsers(roomid, it->second.ephemeral.typing);
|
||||||
const auto newTimelineEvents = it.value().timeline().events();
|
|
||||||
|
const auto newStateEvents = it->second.state;
|
||||||
|
const auto newTimelineEvents = it->second.timeline;
|
||||||
|
|
||||||
// Merge the new updates for rooms that we are tracking.
|
// Merge the new updates for rooms that we are tracking.
|
||||||
if (state_manager_.contains(it.key())) {
|
if (state_manager_.contains(roomid)) {
|
||||||
auto oldState = &state_manager_[it.key()];
|
auto oldState = &state_manager_[roomid];
|
||||||
oldState->updateFromEvents(newStateEvents);
|
oldState->updateFromEvents(newStateEvents.events);
|
||||||
oldState->updateFromEvents(newTimelineEvents);
|
oldState->updateFromEvents(newTimelineEvents.events);
|
||||||
oldState->resolveName();
|
oldState->resolveName();
|
||||||
oldState->resolveAvatar();
|
oldState->resolveAvatar();
|
||||||
} else {
|
} else {
|
||||||
// Build the current state from the timeline and state events.
|
// Build the current state from the timeline and state events.
|
||||||
RoomState room_state;
|
RoomState room_state;
|
||||||
room_state.updateFromEvents(newStateEvents);
|
room_state.updateFromEvents(newStateEvents.events);
|
||||||
room_state.updateFromEvents(newTimelineEvents);
|
room_state.updateFromEvents(newTimelineEvents.events);
|
||||||
|
|
||||||
// Resolve room name and avatar. e.g in case of one-to-one chats.
|
// Resolve room name and avatar. e.g in case of one-to-one chats.
|
||||||
room_state.resolveName();
|
room_state.resolveName();
|
||||||
room_state.resolveAvatar();
|
room_state.resolveAvatar();
|
||||||
|
|
||||||
state_manager_.insert(it.key(), room_state);
|
state_manager_.insert(roomid, room_state);
|
||||||
|
|
||||||
settingsManager_.insert(
|
settingsManager_.insert(
|
||||||
it.key(), QSharedPointer<RoomSettings>(new RoomSettings(it.key())));
|
roomid, QSharedPointer<RoomSettings>(new RoomSettings(roomid)));
|
||||||
|
|
||||||
view_manager_->addRoom(it.value(), it.key());
|
view_manager_->addRoom(it->second, roomid);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUserMetadata(newStateEvents);
|
updateUserMetadata(newStateEvents.events);
|
||||||
updateUserMetadata(newTimelineEvents);
|
updateUserMetadata(newTimelineEvents.events);
|
||||||
|
|
||||||
if (it.key() == current_room_)
|
if (roomid == current_room_)
|
||||||
changeTopRoomInfo(it.key());
|
changeTopRoomInfo(roomid);
|
||||||
|
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, RoomState>
|
QMap<QString, RoomState>
|
||||||
ChatPage::generateMembershipDifference(const QMap<QString, JoinedRoom> &rooms,
|
ChatPage::generateMembershipDifference(
|
||||||
const QMap<QString, RoomState> &states) const
|
const std::map<std::string, mtx::responses::JoinedRoom> &rooms,
|
||||||
|
const QMap<QString, RoomState> &states) const
|
||||||
{
|
{
|
||||||
QMap<QString, RoomState> stateDiff;
|
QMap<QString, RoomState> stateDiff;
|
||||||
|
|
||||||
for (auto it = rooms.constBegin(); it != rooms.constEnd(); ++it) {
|
for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) {
|
||||||
if (!states.contains(it.key()))
|
const auto room_id = QString::fromStdString(it->first);
|
||||||
|
|
||||||
|
if (!states.contains(room_id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto events = it.value().state().events();
|
auto all_memberships = getMemberships(it->second.state.events);
|
||||||
|
auto timelineMemberships = getMemberships(it->second.timeline.events);
|
||||||
|
|
||||||
for (auto event : it.value().timeline().events())
|
// We have to process first the state events and then the timeline.
|
||||||
events.append(event);
|
for (auto mm = timelineMemberships.cbegin(); mm != timelineMemberships.cend(); ++mm)
|
||||||
|
all_memberships.emplace(mm->first, mm->second);
|
||||||
|
|
||||||
RoomState local;
|
RoomState local;
|
||||||
local.aliases = states[it.key()].aliases;
|
local.aliases = states[room_id].aliases;
|
||||||
local.avatar = states[it.key()].avatar;
|
local.avatar = states[room_id].avatar;
|
||||||
local.canonical_alias = states[it.key()].canonical_alias;
|
local.canonical_alias = states[room_id].canonical_alias;
|
||||||
local.history_visibility = states[it.key()].history_visibility;
|
local.history_visibility = states[room_id].history_visibility;
|
||||||
local.join_rules = states[it.key()].join_rules;
|
local.join_rules = states[room_id].join_rules;
|
||||||
local.name = states[it.key()].name;
|
local.name = states[room_id].name;
|
||||||
local.power_levels = states[it.key()].power_levels;
|
local.power_levels = states[room_id].power_levels;
|
||||||
local.topic = states[it.key()].topic;
|
local.topic = states[room_id].topic;
|
||||||
local.memberships = getMemberships(events);
|
local.memberships = all_memberships;
|
||||||
|
|
||||||
stateDiff.insert(it.key(), local);
|
stateDiff.insert(room_id, local);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateDiff;
|
return stateDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
using Memberships = QMap<QString, matrix::events::StateEvent<events::MemberEventContent>>;
|
|
||||||
|
|
||||||
Memberships
|
|
||||||
ChatPage::getMemberships(const QJsonArray &events) const
|
|
||||||
{
|
|
||||||
Memberships memberships;
|
|
||||||
|
|
||||||
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::RoomMember: {
|
|
||||||
events::StateEvent<events::MemberEventContent> member;
|
|
||||||
member.deserialize(event);
|
|
||||||
memberships.insert(member.stateKey(), member);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
qWarning() << e.what() << event;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return memberships;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatPage::~ChatPage() {}
|
ChatPage::~ChatPage() {}
|
||||||
|
|
|
@ -30,12 +30,7 @@
|
||||||
|
|
||||||
#include "Login.h"
|
#include "Login.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "MessageEvent.h"
|
|
||||||
#include "Register.h"
|
#include "Register.h"
|
||||||
#include "RoomMessages.h"
|
|
||||||
#include "Sync.h"
|
|
||||||
|
|
||||||
#include "mtx.hpp"
|
|
||||||
|
|
||||||
MatrixClient::MatrixClient(QString server, QObject *parent)
|
MatrixClient::MatrixClient(QString server, QObject *parent)
|
||||||
: QNetworkAccessManager(parent)
|
: QNetworkAccessManager(parent)
|
||||||
|
@ -239,26 +234,17 @@ MatrixClient::sync() noexcept
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = reply->readAll();
|
|
||||||
|
|
||||||
if (data.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto json = QJsonDocument::fromJson(data);
|
|
||||||
|
|
||||||
SyncResponse response;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.deserialize(json);
|
mtx::responses::Sync response = nlohmann::json::parse(reply->readAll());
|
||||||
emit syncCompleted(response);
|
emit syncCompleted(response);
|
||||||
} catch (DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "Sync malformed response" << e.what();
|
qWarning() << "Sync malformed response" << e.what();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty,
|
MatrixClient::sendRoomMessage(mtx::events::MessageType ty,
|
||||||
int txnId,
|
int txnId,
|
||||||
const QString &roomid,
|
const QString &roomid,
|
||||||
const QString &msg,
|
const QString &msg,
|
||||||
|
@ -283,19 +269,19 @@ MatrixClient::sendRoomMessage(matrix::events::MessageEventType ty,
|
||||||
QJsonObject info = {{"size", fileinfo.size()}, {"mimetype", mime.name()}};
|
QJsonObject info = {{"size", fileinfo.size()}, {"mimetype", mime.name()}};
|
||||||
|
|
||||||
switch (ty) {
|
switch (ty) {
|
||||||
case matrix::events::MessageEventType::Text:
|
case mtx::events::MessageType::Text:
|
||||||
body = {{"msgtype", "m.text"}, {"body", msg}};
|
body = {{"msgtype", "m.text"}, {"body", msg}};
|
||||||
break;
|
break;
|
||||||
case matrix::events::MessageEventType::Emote:
|
case mtx::events::MessageType::Emote:
|
||||||
body = {{"msgtype", "m.emote"}, {"body", msg}};
|
body = {{"msgtype", "m.emote"}, {"body", msg}};
|
||||||
break;
|
break;
|
||||||
case matrix::events::MessageEventType::Image:
|
case mtx::events::MessageType::Image:
|
||||||
body = {{"msgtype", "m.image"}, {"body", msg}, {"url", url}, {"info", info}};
|
body = {{"msgtype", "m.image"}, {"body", msg}, {"url", url}, {"info", info}};
|
||||||
break;
|
break;
|
||||||
case matrix::events::MessageEventType::File:
|
case mtx::events::MessageType::File:
|
||||||
body = {{"msgtype", "m.file"}, {"body", msg}, {"url", url}, {"info", info}};
|
body = {{"msgtype", "m.file"}, {"body", msg}, {"url", url}, {"info", info}};
|
||||||
break;
|
break;
|
||||||
case matrix::events::MessageEventType::Audio:
|
case mtx::events::MessageType::Audio:
|
||||||
body = {{"msgtype", "m.audio"}, {"body", msg}, {"url", url}, {"info", info}};
|
body = {{"msgtype", "m.audio"}, {"body", msg}, {"url", url}, {"info", info}};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -371,23 +357,14 @@ MatrixClient::initialSync() noexcept
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = reply->readAll();
|
|
||||||
|
|
||||||
if (data.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto json = QJsonDocument::fromJson(data);
|
|
||||||
|
|
||||||
SyncResponse response;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.deserialize(json);
|
mtx::responses::Sync response = nlohmann::json::parse(reply->readAll());
|
||||||
|
emit initialSyncCompleted(response);
|
||||||
} catch (DeserializationException &e) {
|
} catch (DeserializationException &e) {
|
||||||
qWarning() << "Sync malformed response" << e.what();
|
qWarning() << "Sync malformed response" << e.what();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit initialSyncCompleted(response);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,18 +663,15 @@ MatrixClient::messages(const QString &roomid, const QString &from_token, int lim
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = reply->readAll();
|
|
||||||
|
|
||||||
RoomMessages msgs;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msgs.deserialize(QJsonDocument::fromJson(data));
|
mtx::responses::Messages messages =
|
||||||
} catch (const DeserializationException &e) {
|
nlohmann::json::parse(reply->readAll().data());
|
||||||
|
|
||||||
|
emit messagesRetrieved(roomid, messages);
|
||||||
|
} catch (std::exception &e) {
|
||||||
qWarning() << "Room messages from" << roomid << e.what();
|
qWarning() << "Room messages from" << roomid << e.what();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit messagesRetrieved(roomid, msgs);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "RoomList.h"
|
#include "RoomList.h"
|
||||||
#include "RoomSettings.h"
|
#include "RoomSettings.h"
|
||||||
#include "RoomState.h"
|
#include "RoomState.h"
|
||||||
#include "Sync.h"
|
|
||||||
|
|
||||||
RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
|
RoomList::RoomList(QSharedPointer<MatrixClient> client, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
|
316
src/RoomState.cc
316
src/RoomState.cc
|
@ -15,15 +15,19 @@
|
||||||
* 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 <QDebug>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QJsonObject>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include "RoomState.h"
|
#include "RoomState.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
|
|
||||||
RoomState::RoomState() {}
|
RoomState::RoomState() {}
|
||||||
RoomState::RoomState(const QJsonArray &events) { updateFromEvents(events); }
|
RoomState::RoomState(const mtx::responses::Timeline &timeline)
|
||||||
|
{
|
||||||
|
updateFromEvents(timeline.events);
|
||||||
|
}
|
||||||
|
RoomState::RoomState(const mtx::responses::State &state) { updateFromEvents(state.events); }
|
||||||
|
|
||||||
void
|
void
|
||||||
RoomState::resolveName()
|
RoomState::resolveName()
|
||||||
|
@ -31,19 +35,19 @@ RoomState::resolveName()
|
||||||
name_ = "Empty Room";
|
name_ = "Empty Room";
|
||||||
userAvatar_.clear();
|
userAvatar_.clear();
|
||||||
|
|
||||||
if (!name.content().name().isEmpty()) {
|
if (!name.content.name.empty()) {
|
||||||
name_ = name.content().name().simplified();
|
name_ = QString::fromStdString(name.content.name).simplified();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canonical_alias.content().alias().isEmpty()) {
|
if (!canonical_alias.content.alias.empty()) {
|
||||||
name_ = canonical_alias.content().alias().simplified();
|
name_ = QString::fromStdString(canonical_alias.content.alias).simplified();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Doesn't follow the spec guidelines.
|
// FIXME: Doesn't follow the spec guidelines.
|
||||||
if (aliases.content().aliases().size() != 0) {
|
if (aliases.content.aliases.size() != 0) {
|
||||||
name_ = aliases.content().aliases()[0].simplified();
|
name_ = QString::fromStdString(aliases.content.aliases[0]).simplified();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,16 +56,20 @@ RoomState::resolveName()
|
||||||
|
|
||||||
// TODO: Display names should be sorted alphabetically.
|
// TODO: Display names should be sorted alphabetically.
|
||||||
for (const auto membership : memberships) {
|
for (const auto membership : memberships) {
|
||||||
if (membership.stateKey() == user_id)
|
const auto stateKey = QString::fromStdString(membership.second.state_key);
|
||||||
|
|
||||||
|
if (stateKey == user_id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (membership.content().membershipState() == events::Membership::Join) {
|
if (membership.second.content.membership == mtx::events::state::Membership::Join) {
|
||||||
userAvatar_ = membership.stateKey();
|
userAvatar_ = stateKey;
|
||||||
|
auto displayName =
|
||||||
|
QString::fromStdString(membership.second.content.display_name);
|
||||||
|
|
||||||
if (membership.content().displayName().isEmpty())
|
if (displayName.isEmpty())
|
||||||
name_ = membership.stateKey();
|
name_ = stateKey;
|
||||||
else
|
else
|
||||||
name_ = membership.content().displayName();
|
name_ = displayName;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -76,12 +84,13 @@ void
|
||||||
RoomState::resolveAvatar()
|
RoomState::resolveAvatar()
|
||||||
{
|
{
|
||||||
if (userAvatar_.isEmpty()) {
|
if (userAvatar_.isEmpty()) {
|
||||||
avatar_ = avatar.content().url();
|
avatar_ = QString::fromStdString(avatar.content.url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memberships.contains(userAvatar_)) {
|
if (memberships.count(userAvatar_.toStdString()) != 0) {
|
||||||
avatar_ = memberships[userAvatar_].content().avatarUrl();
|
avatar_ =
|
||||||
|
QString::fromStdString(memberships[userAvatar_.toStdString()].content.avatar_url);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Setting room avatar from unknown user id" << userAvatar_;
|
qWarning() << "Setting room avatar from unknown user id" << userAvatar_;
|
||||||
}
|
}
|
||||||
|
@ -91,8 +100,8 @@ RoomState::resolveAvatar()
|
||||||
void
|
void
|
||||||
RoomState::removeLeaveMemberships()
|
RoomState::removeLeaveMemberships()
|
||||||
{
|
{
|
||||||
for (auto it = memberships.begin(); it != memberships.end();) {
|
for (auto it = memberships.cbegin(); it != memberships.cend();) {
|
||||||
if (it.value().content().membershipState() == events::Membership::Leave) {
|
if (it->second.content.membership == mtx::events::state::Membership::Leave) {
|
||||||
it = memberships.erase(it);
|
it = memberships.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
|
@ -106,49 +115,51 @@ RoomState::update(const RoomState &state)
|
||||||
bool needsNameCalculation = false;
|
bool needsNameCalculation = false;
|
||||||
bool needsAvatarCalculation = false;
|
bool needsAvatarCalculation = false;
|
||||||
|
|
||||||
if (aliases.eventId() != state.aliases.eventId()) {
|
if (aliases.event_id != state.aliases.event_id)
|
||||||
aliases = state.aliases;
|
aliases = state.aliases;
|
||||||
}
|
|
||||||
|
|
||||||
if (avatar.eventId() != state.avatar.eventId()) {
|
if (avatar.event_id != state.avatar.event_id) {
|
||||||
avatar = state.avatar;
|
avatar = state.avatar;
|
||||||
needsAvatarCalculation = true;
|
needsAvatarCalculation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canonical_alias.eventId() != state.canonical_alias.eventId()) {
|
if (canonical_alias.event_id != state.canonical_alias.event_id) {
|
||||||
canonical_alias = state.canonical_alias;
|
canonical_alias = state.canonical_alias;
|
||||||
needsNameCalculation = true;
|
needsNameCalculation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (create.eventId() != state.create.eventId())
|
if (create.event_id != state.create.event_id)
|
||||||
create = state.create;
|
create = state.create;
|
||||||
if (history_visibility.eventId() != state.history_visibility.eventId())
|
|
||||||
|
if (history_visibility.event_id != state.history_visibility.event_id)
|
||||||
history_visibility = state.history_visibility;
|
history_visibility = state.history_visibility;
|
||||||
if (join_rules.eventId() != state.join_rules.eventId())
|
|
||||||
|
if (join_rules.event_id != state.join_rules.event_id)
|
||||||
join_rules = state.join_rules;
|
join_rules = state.join_rules;
|
||||||
|
|
||||||
if (name.eventId() != state.name.eventId()) {
|
if (name.event_id != state.name.event_id) {
|
||||||
name = state.name;
|
name = state.name;
|
||||||
needsNameCalculation = true;
|
needsNameCalculation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (power_levels.eventId() != state.power_levels.eventId())
|
if (power_levels.event_id != state.power_levels.event_id)
|
||||||
power_levels = state.power_levels;
|
power_levels = state.power_levels;
|
||||||
if (topic.eventId() != state.topic.eventId())
|
|
||||||
|
if (topic.event_id != state.topic.event_id)
|
||||||
topic = state.topic;
|
topic = state.topic;
|
||||||
|
|
||||||
for (auto it = state.memberships.constBegin(); it != state.memberships.constEnd(); ++it) {
|
for (auto it = state.memberships.cbegin(); it != state.memberships.cend(); ++it) {
|
||||||
auto membershipState = it.value().content().membershipState();
|
auto membershipState = it->second.content.membership;
|
||||||
|
|
||||||
if (it.key() == userAvatar_) {
|
if (it->first == userAvatar_.toStdString()) {
|
||||||
needsNameCalculation = true;
|
needsNameCalculation = true;
|
||||||
needsAvatarCalculation = true;
|
needsAvatarCalculation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (membershipState == events::Membership::Leave)
|
if (membershipState == mtx::events::state::Membership::Leave)
|
||||||
this->memberships.remove(it.key());
|
this->memberships.erase(this->memberships.find(it->first));
|
||||||
else
|
else
|
||||||
this->memberships.insert(it.key(), it.value());
|
this->memberships.emplace(it->first, it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsNameCalculation)
|
if (needsNameCalculation)
|
||||||
|
@ -158,235 +169,126 @@ RoomState::update(const RoomState &state)
|
||||||
resolveAvatar();
|
resolveAvatar();
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject
|
std::string
|
||||||
RoomState::serialize() const
|
RoomState::serialize() const
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
nlohmann::json obj;
|
||||||
|
|
||||||
if (!aliases.eventId().isEmpty())
|
if (!aliases.event_id.empty())
|
||||||
obj["aliases"] = aliases.serialize();
|
obj["aliases"] = aliases;
|
||||||
|
|
||||||
if (!avatar.eventId().isEmpty())
|
if (!avatar.event_id.empty())
|
||||||
obj["avatar"] = avatar.serialize();
|
obj["avatar"] = avatar;
|
||||||
|
|
||||||
if (!canonical_alias.eventId().isEmpty())
|
if (!canonical_alias.event_id.empty())
|
||||||
obj["canonical_alias"] = canonical_alias.serialize();
|
obj["canonical_alias"] = canonical_alias;
|
||||||
|
|
||||||
if (!create.eventId().isEmpty())
|
if (!create.event_id.empty())
|
||||||
obj["create"] = create.serialize();
|
obj["create"] = create;
|
||||||
|
|
||||||
if (!history_visibility.eventId().isEmpty())
|
if (!history_visibility.event_id.empty())
|
||||||
obj["history_visibility"] = history_visibility.serialize();
|
obj["history_visibility"] = history_visibility;
|
||||||
|
|
||||||
if (!join_rules.eventId().isEmpty())
|
if (!join_rules.event_id.empty())
|
||||||
obj["join_rules"] = join_rules.serialize();
|
obj["join_rules"] = join_rules;
|
||||||
|
|
||||||
if (!name.eventId().isEmpty())
|
if (!name.event_id.empty())
|
||||||
obj["name"] = name.serialize();
|
obj["name"] = name;
|
||||||
|
|
||||||
if (!power_levels.eventId().isEmpty())
|
if (!power_levels.event_id.empty())
|
||||||
obj["power_levels"] = power_levels.serialize();
|
obj["power_levels"] = power_levels;
|
||||||
|
|
||||||
if (!topic.eventId().isEmpty())
|
if (!topic.event_id.empty())
|
||||||
obj["topic"] = topic.serialize();
|
obj["topic"] = topic;
|
||||||
|
|
||||||
return obj;
|
return obj.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RoomState::parse(const QJsonObject &object)
|
RoomState::parse(const nlohmann::json &object)
|
||||||
{
|
{
|
||||||
// FIXME: Make this less versbose.
|
if (object.count("aliases") != 0) {
|
||||||
|
|
||||||
if (object.contains("aliases")) {
|
|
||||||
events::StateEvent<events::AliasesEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["aliases"]);
|
aliases = object.at("aliases")
|
||||||
aliases = event;
|
.get<mtx::events::StateEvent<mtx::events::state::Aliases>>();
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - aliases" << e.what();
|
qWarning() << "RoomState::parse - aliases" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("avatar")) {
|
if (object.count("avatar") != 0) {
|
||||||
events::StateEvent<events::AvatarEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["avatar"]);
|
avatar = object.at("avatar")
|
||||||
avatar = event;
|
.get<mtx::events::StateEvent<mtx::events::state::Avatar>>();
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - avatar" << e.what();
|
qWarning() << "RoomState::parse - avatar" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("canonical_alias")) {
|
if (object.count("canonical_alias") != 0) {
|
||||||
events::StateEvent<events::CanonicalAliasEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["canonical_alias"]);
|
canonical_alias =
|
||||||
canonical_alias = event;
|
object.at("canonical_alias")
|
||||||
} catch (const DeserializationException &e) {
|
.get<mtx::events::StateEvent<mtx::events::state::CanonicalAlias>>();
|
||||||
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - canonical_alias" << e.what();
|
qWarning() << "RoomState::parse - canonical_alias" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("create")) {
|
if (object.count("create") != 0) {
|
||||||
events::StateEvent<events::CreateEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["create"]);
|
create = object.at("create")
|
||||||
create = event;
|
.get<mtx::events::StateEvent<mtx::events::state::Create>>();
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - create" << e.what();
|
qWarning() << "RoomState::parse - create" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("history_visibility")) {
|
if (object.count("history_visibility") != 0) {
|
||||||
events::StateEvent<events::HistoryVisibilityEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["history_visibility"]);
|
history_visibility =
|
||||||
history_visibility = event;
|
object.at("history_visibility")
|
||||||
} catch (const DeserializationException &e) {
|
.get<mtx::events::StateEvent<mtx::events::state::HistoryVisibility>>();
|
||||||
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - history_visibility" << e.what();
|
qWarning() << "RoomState::parse - history_visibility" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("join_rules")) {
|
if (object.count("join_rules") != 0) {
|
||||||
events::StateEvent<events::JoinRulesEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["join_rules"]);
|
join_rules =
|
||||||
join_rules = event;
|
object.at("join_rules")
|
||||||
} catch (const DeserializationException &e) {
|
.get<mtx::events::StateEvent<mtx::events::state::JoinRules>>();
|
||||||
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - join_rules" << e.what();
|
qWarning() << "RoomState::parse - join_rules" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("name")) {
|
if (object.count("name") != 0) {
|
||||||
events::StateEvent<events::NameEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["name"]);
|
name = object.at("name")
|
||||||
name = event;
|
.get<mtx::events::StateEvent<mtx::events::state::Name>>();
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - name" << e.what();
|
qWarning() << "RoomState::parse - name" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("power_levels")) {
|
if (object.count("power_levels") != 0) {
|
||||||
events::StateEvent<events::PowerLevelsEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["power_levels"]);
|
power_levels =
|
||||||
power_levels = event;
|
object.at("power_levels")
|
||||||
} catch (const DeserializationException &e) {
|
.get<mtx::events::StateEvent<mtx::events::state::PowerLevels>>();
|
||||||
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - power_levels" << e.what();
|
qWarning() << "RoomState::parse - power_levels" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("topic")) {
|
if (object.count("topic") != 0) {
|
||||||
events::StateEvent<events::TopicEventContent> event;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.deserialize(object["topic"]);
|
topic = object.at("topic")
|
||||||
topic = event;
|
.get<mtx::events::StateEvent<mtx::events::state::Topic>>();
|
||||||
} catch (const DeserializationException &e) {
|
} catch (std::exception &e) {
|
||||||
qWarning() << "RoomState::parse - topic" << e.what();
|
qWarning() << "RoomState::parse - topic" << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
RoomState::updateFromEvents(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);
|
|
||||||
this->aliases = aliases;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomAvatar: {
|
|
||||||
events::StateEvent<events::AvatarEventContent> avatar;
|
|
||||||
avatar.deserialize(event);
|
|
||||||
this->avatar = avatar;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomCanonicalAlias: {
|
|
||||||
events::StateEvent<events::CanonicalAliasEventContent>
|
|
||||||
canonical_alias;
|
|
||||||
canonical_alias.deserialize(event);
|
|
||||||
this->canonical_alias = canonical_alias;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomCreate: {
|
|
||||||
events::StateEvent<events::CreateEventContent> create;
|
|
||||||
create.deserialize(event);
|
|
||||||
this->create = create;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomHistoryVisibility: {
|
|
||||||
events::StateEvent<events::HistoryVisibilityEventContent>
|
|
||||||
history_visibility;
|
|
||||||
history_visibility.deserialize(event);
|
|
||||||
this->history_visibility = history_visibility;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomJoinRules: {
|
|
||||||
events::StateEvent<events::JoinRulesEventContent> join_rules;
|
|
||||||
join_rules.deserialize(event);
|
|
||||||
this->join_rules = join_rules;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomName: {
|
|
||||||
events::StateEvent<events::NameEventContent> name;
|
|
||||||
name.deserialize(event);
|
|
||||||
this->name = name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomMember: {
|
|
||||||
events::StateEvent<events::MemberEventContent> member;
|
|
||||||
member.deserialize(event);
|
|
||||||
|
|
||||||
this->memberships.insert(member.stateKey(), member);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomPowerLevels: {
|
|
||||||
events::StateEvent<events::PowerLevelsEventContent> power_levels;
|
|
||||||
power_levels.deserialize(event);
|
|
||||||
this->power_levels = power_levels;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case events::EventType::RoomTopic: {
|
|
||||||
events::StateEvent<events::TopicEventContent> topic;
|
|
||||||
topic.deserialize(event);
|
|
||||||
this->topic = topic;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
qWarning() << e.what() << event;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
307
src/Sync.cc
307
src/Sync.cc
|
@ -1,307 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "Sync.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
SyncResponse::deserialize(const QJsonDocument &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("Sync response is not a JSON object");
|
|
||||||
|
|
||||||
QJsonObject object = data.object();
|
|
||||||
|
|
||||||
if (!object.contains("next_batch"))
|
|
||||||
throw DeserializationException("Sync: missing next_batch parameter");
|
|
||||||
|
|
||||||
if (object.contains("rooms")) {
|
|
||||||
if (!object.value("rooms").isObject()) {
|
|
||||||
throw DeserializationException("Sync: rooms is not a JSON object");
|
|
||||||
}
|
|
||||||
rooms_.deserialize(object.value("rooms"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("presence")) {
|
|
||||||
if (!object.value("presence").isObject()) {
|
|
||||||
throw DeserializationException("Sync: presence is not a JSON object");
|
|
||||||
}
|
|
||||||
// TODO: implement presence handling
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("account_data")) {
|
|
||||||
if (!object.value("account_data").isObject()) {
|
|
||||||
throw DeserializationException("Sync: account_data is not a JSON object");
|
|
||||||
}
|
|
||||||
// TODO: implement account_data handling
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("to_device")) {
|
|
||||||
if (!object.value("to_device").isObject()) {
|
|
||||||
throw DeserializationException("Sync: to_device is not a JSON object");
|
|
||||||
}
|
|
||||||
// TODO: implement to_device handling
|
|
||||||
}
|
|
||||||
|
|
||||||
// for device_lists updates (for e2e)
|
|
||||||
if (object.contains("device_lists")) {
|
|
||||||
if (!object.value("device_lists").isObject()) {
|
|
||||||
throw DeserializationException("Sync: device_lists is not a JSON object");
|
|
||||||
}
|
|
||||||
// TODO: implement device_lists handling
|
|
||||||
}
|
|
||||||
|
|
||||||
next_batch_ = object.value("next_batch").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Rooms::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("Rooms value is not a JSON object");
|
|
||||||
|
|
||||||
QJsonObject object = data.toObject();
|
|
||||||
|
|
||||||
if (object.contains("join")) {
|
|
||||||
if (!object.value("join").isObject())
|
|
||||||
throw DeserializationException("rooms/join must be a JSON object");
|
|
||||||
|
|
||||||
auto join = object.value("join").toObject();
|
|
||||||
|
|
||||||
for (auto it = join.constBegin(); it != join.constEnd(); ++it) {
|
|
||||||
JoinedRoom tmp_room;
|
|
||||||
try {
|
|
||||||
tmp_room.deserialize(it.value());
|
|
||||||
join_.insert(it.key(), tmp_room);
|
|
||||||
} catch (DeserializationException &e) {
|
|
||||||
qWarning() << e.what();
|
|
||||||
qWarning() << "Skipping malformed object for room" << it.key();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("invite")) {
|
|
||||||
if (!object.value("invite").isObject()) {
|
|
||||||
throw DeserializationException("rooms/invite must be a JSON object");
|
|
||||||
}
|
|
||||||
// TODO: Implement invite handling
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("leave")) {
|
|
||||||
if (!object.value("leave").isObject()) {
|
|
||||||
throw DeserializationException("rooms/leave must be a JSON object");
|
|
||||||
}
|
|
||||||
auto leave = object.value("leave").toObject();
|
|
||||||
|
|
||||||
for (auto it = leave.constBegin(); it != leave.constEnd(); ++it) {
|
|
||||||
LeftRoom tmp_room;
|
|
||||||
|
|
||||||
try {
|
|
||||||
tmp_room.deserialize(it.value());
|
|
||||||
leave_.insert(it.key(), tmp_room);
|
|
||||||
} catch (DeserializationException &e) {
|
|
||||||
qWarning() << e.what();
|
|
||||||
qWarning() << "Skipping malformed object for room" << it.key();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
JoinedRoom::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("JoinedRoom is not a JSON object");
|
|
||||||
|
|
||||||
QJsonObject object = data.toObject();
|
|
||||||
|
|
||||||
if (object.contains("state")) {
|
|
||||||
if (!object.value("state").isObject()) {
|
|
||||||
throw DeserializationException("join/state should be an object");
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject state = object.value("state").toObject();
|
|
||||||
|
|
||||||
if (state.contains("events")) {
|
|
||||||
if (!state.value("events").isArray()) {
|
|
||||||
throw DeserializationException(
|
|
||||||
"join/state/events should be an array");
|
|
||||||
}
|
|
||||||
|
|
||||||
state_.deserialize(state.value("events"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("timeline")) {
|
|
||||||
if (!object.value("timeline").isObject())
|
|
||||||
throw DeserializationException("join/timeline should be an object");
|
|
||||||
timeline_.deserialize(object.value("timeline"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("ephemeral")) {
|
|
||||||
if (!object.value("ephemeral").isObject())
|
|
||||||
throw DeserializationException("join/ephemeral should be an object");
|
|
||||||
|
|
||||||
QJsonObject ephemeral = object.value("ephemeral").toObject();
|
|
||||||
|
|
||||||
if (ephemeral.contains("events")) {
|
|
||||||
if (!ephemeral.value("events").isArray())
|
|
||||||
qWarning() << "join/ephemeral/events should be an array";
|
|
||||||
|
|
||||||
auto ephemeralEvents = ephemeral.value("events").toArray();
|
|
||||||
|
|
||||||
for (const auto e : ephemeralEvents) {
|
|
||||||
auto obj = e.toObject();
|
|
||||||
|
|
||||||
if (obj.contains("type") && obj.value("type") == "m.typing") {
|
|
||||||
auto ids = obj.value("content")
|
|
||||||
.toObject()
|
|
||||||
.value("user_ids")
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
for (const auto uid : ids)
|
|
||||||
typingUserIDs_.push_back(uid.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("account_data")) {
|
|
||||||
if (!object.value("account_data").isObject())
|
|
||||||
throw DeserializationException("join/account_data is not a JSON object");
|
|
||||||
// TODO: Implement account_data handling
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.contains("unread_notifications")) {
|
|
||||||
if (!object.value("unread_notifications").isObject()) {
|
|
||||||
throw DeserializationException(
|
|
||||||
"join/unread_notifications is not a JSON object");
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject unreadNotifications = object.value("unread_notifications").toObject();
|
|
||||||
|
|
||||||
if (unreadNotifications.contains("highlight_count")) {
|
|
||||||
// TODO: Implement unread_notifications handling
|
|
||||||
}
|
|
||||||
if (unreadNotifications.contains("notification_count")) {
|
|
||||||
// TODO: Implement unread_notifications handling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LeftRoom::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("LeftRoom is not a JSON object");
|
|
||||||
|
|
||||||
QJsonObject object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("state"))
|
|
||||||
throw DeserializationException("leave/state is missing");
|
|
||||||
|
|
||||||
if (!object.contains("timeline"))
|
|
||||||
throw DeserializationException("leave/timeline is missing");
|
|
||||||
|
|
||||||
if (!object.value("state").isObject())
|
|
||||||
throw DeserializationException("leave/state should be an object");
|
|
||||||
|
|
||||||
QJsonObject state = object.value("state").toObject();
|
|
||||||
|
|
||||||
if (!state.contains("events"))
|
|
||||||
throw DeserializationException("leave/state/events is missing");
|
|
||||||
|
|
||||||
state_.deserialize(state.value("events"));
|
|
||||||
timeline_.deserialize(object.value("timeline"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Event::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("Event is not a JSON object");
|
|
||||||
|
|
||||||
QJsonObject object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("content"))
|
|
||||||
throw DeserializationException("event/content is missing");
|
|
||||||
|
|
||||||
if (!object.contains("unsigned"))
|
|
||||||
throw DeserializationException("event/content is missing");
|
|
||||||
|
|
||||||
if (!object.contains("sender"))
|
|
||||||
throw DeserializationException("event/sender is missing");
|
|
||||||
|
|
||||||
if (!object.contains("event_id"))
|
|
||||||
throw DeserializationException("event/event_id is missing");
|
|
||||||
|
|
||||||
// TODO: Make this optional
|
|
||||||
/* if (!object.contains("state_key")) */
|
|
||||||
/* throw DeserializationException("event/state_key is missing"); */
|
|
||||||
|
|
||||||
if (!object.contains("type"))
|
|
||||||
throw DeserializationException("event/type is missing");
|
|
||||||
|
|
||||||
if (!object.contains("origin_server_ts"))
|
|
||||||
throw DeserializationException("event/origin_server_ts is missing");
|
|
||||||
|
|
||||||
content_ = object.value("content").toObject();
|
|
||||||
unsigned_ = object.value("unsigned").toObject();
|
|
||||||
|
|
||||||
sender_ = object.value("sender").toString();
|
|
||||||
state_key_ = object.value("state_key").toString();
|
|
||||||
type_ = object.value("type").toString();
|
|
||||||
event_id_ = object.value("event_id").toString();
|
|
||||||
|
|
||||||
origin_server_ts_ = object.value("origin_server_ts").toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
State::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isArray())
|
|
||||||
throw DeserializationException("State is not a JSON array");
|
|
||||||
|
|
||||||
events_ = data.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Timeline::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("Timeline is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("events"))
|
|
||||||
throw DeserializationException("timeline/events is missing");
|
|
||||||
|
|
||||||
if (!object.contains("prev_batch"))
|
|
||||||
throw DeserializationException("timeline/prev_batch is missing");
|
|
||||||
|
|
||||||
if (!object.contains("limited"))
|
|
||||||
throw DeserializationException("timeline/limited is missing");
|
|
||||||
|
|
||||||
prev_batch_ = object.value("prev_batch").toString();
|
|
||||||
limited_ = object.value("limited").toBool();
|
|
||||||
|
|
||||||
if (!object.value("events").isArray())
|
|
||||||
throw DeserializationException("timeline/events is not a JSON array");
|
|
||||||
|
|
||||||
events_ = object.value("events").toArray();
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <QJsonArray>
|
|
||||||
|
|
||||||
#include "AliasesEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
AliasesEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("AliasesEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("aliases") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("aliases key is missing");
|
|
||||||
|
|
||||||
auto aliases = object.value("aliases").toArray();
|
|
||||||
|
|
||||||
for (const auto &alias : aliases)
|
|
||||||
aliases_.push_back(alias.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
AliasesEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
QJsonArray aliases;
|
|
||||||
|
|
||||||
for (const auto &alias : aliases_)
|
|
||||||
aliases.push_back(alias);
|
|
||||||
|
|
||||||
if (aliases.size() > 0)
|
|
||||||
object["aliases"] = aliases;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "AvatarEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
AvatarEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("AvatarEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("url") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("url key is missing");
|
|
||||||
|
|
||||||
url_ = QUrl(object.value("url").toString());
|
|
||||||
|
|
||||||
if (!url_.isValid())
|
|
||||||
qWarning() << "Invalid avatar url" << url_;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
AvatarEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!url_.isEmpty())
|
|
||||||
object["url"] = url_.toString();
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "CanonicalAliasEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
CanonicalAliasEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("CanonicalAliasEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("alias") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("alias key is missing");
|
|
||||||
|
|
||||||
alias_ = object.value("alias").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
CanonicalAliasEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!alias_.isEmpty())
|
|
||||||
object["alias"] = alias_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "CreateEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
CreateEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("CreateEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("creator") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("creator key is missing");
|
|
||||||
|
|
||||||
creator_ = object.value("creator").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
CreateEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!creator_.isEmpty())
|
|
||||||
object["creator"] = creator_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "events/Event.h"
|
|
||||||
|
|
||||||
#include "AliasesEventContent.h"
|
|
||||||
#include "AvatarEventContent.h"
|
|
||||||
#include "CanonicalAliasEventContent.h"
|
|
||||||
#include "CreateEventContent.h"
|
|
||||||
#include "Deserializable.h"
|
|
||||||
#include "HistoryVisibilityEventContent.h"
|
|
||||||
#include "JoinRulesEventContent.h"
|
|
||||||
#include "MemberEventContent.h"
|
|
||||||
#include "NameEventContent.h"
|
|
||||||
#include "PowerLevelsEventContent.h"
|
|
||||||
#include "TopicEventContent.h"
|
|
||||||
|
|
||||||
matrix::events::EventType
|
|
||||||
matrix::events::extractEventType(const QJsonObject &object)
|
|
||||||
{
|
|
||||||
if (!object.contains("type"))
|
|
||||||
throw DeserializationException("Missing event type");
|
|
||||||
|
|
||||||
auto type = object.value("type").toString();
|
|
||||||
|
|
||||||
if (type == "m.room.aliases")
|
|
||||||
return EventType::RoomAliases;
|
|
||||||
else if (type == "m.room.avatar")
|
|
||||||
return EventType::RoomAvatar;
|
|
||||||
else if (type == "m.room.canonical_alias")
|
|
||||||
return EventType::RoomCanonicalAlias;
|
|
||||||
else if (type == "m.room.create")
|
|
||||||
return EventType::RoomCreate;
|
|
||||||
else if (type == "m.room.history_visibility")
|
|
||||||
return EventType::RoomHistoryVisibility;
|
|
||||||
else if (type == "m.room.join_rules")
|
|
||||||
return EventType::RoomJoinRules;
|
|
||||||
else if (type == "m.room.member")
|
|
||||||
return EventType::RoomMember;
|
|
||||||
else if (type == "m.room.message")
|
|
||||||
return EventType::RoomMessage;
|
|
||||||
else if (type == "m.room.name")
|
|
||||||
return EventType::RoomName;
|
|
||||||
else if (type == "m.room.power_levels")
|
|
||||||
return EventType::RoomPowerLevels;
|
|
||||||
else if (type == "m.room.topic")
|
|
||||||
return EventType::RoomTopic;
|
|
||||||
else
|
|
||||||
return EventType::Unsupported;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
matrix::events::isStateEvent(EventType type)
|
|
||||||
{
|
|
||||||
return type == EventType::RoomAliases || type == EventType::RoomAvatar ||
|
|
||||||
type == EventType::RoomCanonicalAlias || type == EventType::RoomCreate ||
|
|
||||||
type == EventType::RoomHistoryVisibility || type == EventType::RoomJoinRules ||
|
|
||||||
type == EventType::RoomMember || type == EventType::RoomName ||
|
|
||||||
type == EventType::RoomPowerLevels || type == EventType::RoomTopic;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
matrix::events::isMessageEvent(EventType type)
|
|
||||||
{
|
|
||||||
return type == EventType::RoomMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
matrix::events::UnsignedData::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("UnsignedData is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
transaction_id_ = object.value("transaction_id").toString();
|
|
||||||
age_ = object.value("age").toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
matrix::events::UnsignedData::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!transaction_id_.isEmpty())
|
|
||||||
object["transaction_id"] = transaction_id_;
|
|
||||||
|
|
||||||
if (age_ > 0)
|
|
||||||
object["age"] = age_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "HistoryVisibilityEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
HistoryVisibilityEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException(
|
|
||||||
"HistoryVisibilityEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("history_visibility") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("history_visibility key is missing");
|
|
||||||
|
|
||||||
auto value = object.value("history_visibility").toString();
|
|
||||||
|
|
||||||
if (value == "invited")
|
|
||||||
history_visibility_ = HistoryVisibility::Invited;
|
|
||||||
else if (value == "joined")
|
|
||||||
history_visibility_ = HistoryVisibility::Joined;
|
|
||||||
else if (value == "shared")
|
|
||||||
history_visibility_ = HistoryVisibility::Shared;
|
|
||||||
else if (value == "world_readable")
|
|
||||||
history_visibility_ = HistoryVisibility::WorldReadable;
|
|
||||||
else
|
|
||||||
throw DeserializationException(
|
|
||||||
QString("Unknown history_visibility value: %1").arg(value).toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
HistoryVisibilityEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (history_visibility_ == HistoryVisibility::Invited)
|
|
||||||
object["history_visibility"] = "invited";
|
|
||||||
else if (history_visibility_ == HistoryVisibility::Joined)
|
|
||||||
object["history_visibility"] = "joined";
|
|
||||||
else if (history_visibility_ == HistoryVisibility::Shared)
|
|
||||||
object["history_visibility"] = "shared";
|
|
||||||
else if (history_visibility_ == HistoryVisibility::WorldReadable)
|
|
||||||
object["history_visibility"] = "world_readable";
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "JoinRulesEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
JoinRulesEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("JoinRulesEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("join_rule") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("join_rule key is missing");
|
|
||||||
|
|
||||||
auto value = object.value("join_rule").toString();
|
|
||||||
|
|
||||||
if (value == "invite")
|
|
||||||
join_rule_ = JoinRule::Invite;
|
|
||||||
else if (value == "knock")
|
|
||||||
join_rule_ = JoinRule::Knock;
|
|
||||||
else if (value == "private")
|
|
||||||
join_rule_ = JoinRule::Private;
|
|
||||||
else if (value == "public")
|
|
||||||
join_rule_ = JoinRule::Public;
|
|
||||||
else
|
|
||||||
throw DeserializationException(
|
|
||||||
QString("Unknown join_rule value: %1").arg(value).toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
JoinRulesEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (join_rule_ == JoinRule::Invite)
|
|
||||||
object["join_rule"] = "invite";
|
|
||||||
else if (join_rule_ == JoinRule::Knock)
|
|
||||||
object["join_rule"] = "knock";
|
|
||||||
else if (join_rule_ == JoinRule::Private)
|
|
||||||
object["join_rule"] = "private";
|
|
||||||
else if (join_rule_ == JoinRule::Public)
|
|
||||||
object["join_rule"] = "public";
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "MemberEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
MemberEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("MemberEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (!object.contains("membership"))
|
|
||||||
throw DeserializationException("membership key is missing");
|
|
||||||
|
|
||||||
auto value = object.value("membership").toString();
|
|
||||||
|
|
||||||
if (value == "ban")
|
|
||||||
membership_state_ = Membership::Ban;
|
|
||||||
else if (value == "invite")
|
|
||||||
membership_state_ = Membership::Invite;
|
|
||||||
else if (value == "join")
|
|
||||||
membership_state_ = Membership::Join;
|
|
||||||
else if (value == "knock")
|
|
||||||
membership_state_ = Membership::Knock;
|
|
||||||
else if (value == "leave")
|
|
||||||
membership_state_ = Membership::Leave;
|
|
||||||
else
|
|
||||||
throw DeserializationException(
|
|
||||||
QString("Unknown membership value: %1").arg(value).toUtf8().constData());
|
|
||||||
|
|
||||||
if (object.contains("avatar_url"))
|
|
||||||
avatar_url_ = QUrl(object.value("avatar_url").toString());
|
|
||||||
|
|
||||||
if (!avatar_url_.toString().isEmpty() && !avatar_url_.isValid())
|
|
||||||
qWarning() << "Invalid avatar url" << avatar_url_;
|
|
||||||
|
|
||||||
if (object.contains("displayname"))
|
|
||||||
display_name_ = object.value("displayname").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
MemberEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (membership_state_ == Membership::Ban)
|
|
||||||
object["membership"] = "ban";
|
|
||||||
else if (membership_state_ == Membership::Invite)
|
|
||||||
object["membership"] = "invite";
|
|
||||||
else if (membership_state_ == Membership::Join)
|
|
||||||
object["membership"] = "join";
|
|
||||||
else if (membership_state_ == Membership::Knock)
|
|
||||||
object["membership"] = "knock";
|
|
||||||
else if (membership_state_ == Membership::Leave)
|
|
||||||
object["membership"] = "leave";
|
|
||||||
|
|
||||||
if (!avatar_url_.isEmpty())
|
|
||||||
object["avatar_url"] = avatar_url_.toString();
|
|
||||||
|
|
||||||
if (!display_name_.isEmpty())
|
|
||||||
object["displayname"] = display_name_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
MessageEventContent::serialize() const
|
|
||||||
{
|
|
||||||
// TODO: Add for all the message contents.
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "NameEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
NameEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("NameEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("name") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("name key is missing");
|
|
||||||
|
|
||||||
name_ = object.value("name").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
NameEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!name_.isEmpty())
|
|
||||||
object["name"] = name_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <QJsonObject>
|
|
||||||
|
|
||||||
#include "Deserializable.h"
|
|
||||||
#include "PowerLevelsEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
PowerLevelsEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("PowerLevelsEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("ban") != QJsonValue::Undefined)
|
|
||||||
ban_ = object.value("ban").toInt();
|
|
||||||
|
|
||||||
if (object.value("invite") != QJsonValue::Undefined)
|
|
||||||
invite_ = object.value("invite").toInt();
|
|
||||||
|
|
||||||
if (object.value("kick") != QJsonValue::Undefined)
|
|
||||||
kick_ = object.value("kick").toInt();
|
|
||||||
|
|
||||||
if (object.value("redact") != QJsonValue::Undefined)
|
|
||||||
redact_ = object.value("redact").toInt();
|
|
||||||
|
|
||||||
if (object.value("events_default") != QJsonValue::Undefined)
|
|
||||||
events_default_ = object.value("events_default").toInt();
|
|
||||||
|
|
||||||
if (object.value("state_default") != QJsonValue::Undefined)
|
|
||||||
state_default_ = object.value("state_default").toInt();
|
|
||||||
|
|
||||||
if (object.value("users_default") != QJsonValue::Undefined)
|
|
||||||
users_default_ = object.value("users_default").toInt();
|
|
||||||
|
|
||||||
if (object.value("users").isObject()) {
|
|
||||||
auto users = object.value("users").toObject();
|
|
||||||
|
|
||||||
for (auto it = users.constBegin(); it != users.constEnd(); ++it)
|
|
||||||
users_.insert(it.key(), it.value().toInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.value("events").isObject()) {
|
|
||||||
auto events = object.value("events").toObject();
|
|
||||||
|
|
||||||
for (auto it = events.constBegin(); it != events.constEnd(); ++it)
|
|
||||||
events_.insert(it.key(), it.value().toInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
PowerLevelsEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
object["ban"] = ban_;
|
|
||||||
object["invite"] = invite_;
|
|
||||||
object["kick"] = kick_;
|
|
||||||
object["redact"] = redact_;
|
|
||||||
|
|
||||||
object["events_default"] = events_default_;
|
|
||||||
object["users_default"] = users_default_;
|
|
||||||
object["state_default"] = state_default_;
|
|
||||||
|
|
||||||
QJsonObject users;
|
|
||||||
QJsonObject events;
|
|
||||||
|
|
||||||
for (auto it = users_.constBegin(); it != users_.constEnd(); ++it)
|
|
||||||
users.insert(it.key(), it.value());
|
|
||||||
|
|
||||||
for (auto it = events_.constBegin(); it != events_.constEnd(); ++it)
|
|
||||||
events.insert(it.key(), it.value());
|
|
||||||
|
|
||||||
object["users"] = users;
|
|
||||||
object["events"] = events;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
PowerLevelsEventContent::eventLevel(QString event_type) const
|
|
||||||
{
|
|
||||||
if (events_.contains(event_type))
|
|
||||||
return events_[event_type];
|
|
||||||
|
|
||||||
return events_default_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
PowerLevelsEventContent::userLevel(QString userid) const
|
|
||||||
{
|
|
||||||
if (users_.contains(userid))
|
|
||||||
return users_[userid];
|
|
||||||
|
|
||||||
return users_default_;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 "TopicEventContent.h"
|
|
||||||
|
|
||||||
using namespace matrix::events;
|
|
||||||
|
|
||||||
void
|
|
||||||
TopicEventContent::deserialize(const QJsonValue &data)
|
|
||||||
{
|
|
||||||
if (!data.isObject())
|
|
||||||
throw DeserializationException("TopicEventContent is not a JSON object");
|
|
||||||
|
|
||||||
auto object = data.toObject();
|
|
||||||
|
|
||||||
if (object.value("topic") == QJsonValue::Undefined)
|
|
||||||
throw DeserializationException("topic key is missing");
|
|
||||||
|
|
||||||
topic_ = object.value("topic").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject
|
|
||||||
TopicEventContent::serialize() const
|
|
||||||
{
|
|
||||||
QJsonObject object;
|
|
||||||
|
|
||||||
if (!topic_.isEmpty())
|
|
||||||
object["topic"] = topic_;
|
|
||||||
|
|
||||||
return object;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.value("msgtype") != "m.file")
|
|
||||||
throw DeserializationException("invalid msgtype for file");
|
|
||||||
|
|
||||||
url_ = object.value("url").toString();
|
|
||||||
filename_ = object.value("filename").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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Sync.h"
|
|
||||||
|
|
||||||
#include "timeline/TimelineItem.h"
|
#include "timeline/TimelineItem.h"
|
||||||
#include "timeline/widgets/AudioItem.h"
|
#include "timeline/widgets/AudioItem.h"
|
||||||
|
@ -32,9 +31,6 @@
|
||||||
static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)");
|
static const QRegExp URL_REGEX("((?:https?|ftp)://\\S+)");
|
||||||
static const QString URL_HTML = "<a href=\"\\1\">\\1</a>";
|
static const QString URL_HTML = "<a href=\"\\1\">\\1</a>";
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineItem::init()
|
TimelineItem::init()
|
||||||
{
|
{
|
||||||
|
@ -71,7 +67,7 @@ TimelineItem::init()
|
||||||
/*
|
/*
|
||||||
* For messages created locally.
|
* For messages created locally.
|
||||||
*/
|
*/
|
||||||
TimelineItem::TimelineItem(events::MessageEventType ty,
|
TimelineItem::TimelineItem(mtx::events::MessageType ty,
|
||||||
const QString &userid,
|
const QString &userid,
|
||||||
QString body,
|
QString body,
|
||||||
bool withSender,
|
bool withSender,
|
||||||
|
@ -83,7 +79,7 @@ TimelineItem::TimelineItem(events::MessageEventType ty,
|
||||||
auto displayName = TimelineViewManager::displayName(userid);
|
auto displayName = TimelineViewManager::displayName(userid);
|
||||||
auto timestamp = QDateTime::currentDateTime();
|
auto timestamp = QDateTime::currentDateTime();
|
||||||
|
|
||||||
if (ty == events::MessageEventType::Emote) {
|
if (ty == mtx::events::MessageType::Emote) {
|
||||||
body = QString("* %1 %2").arg(displayName).arg(body);
|
body = QString("* %1 %2").arg(displayName).arg(body);
|
||||||
descriptionMsg_ = {"", userid, body, descriptiveTime(timestamp)};
|
descriptionMsg_ = {"", userid, body, descriptiveTime(timestamp)};
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,64 +148,65 @@ TimelineItem::TimelineItem(VideoItem *video,
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem::TimelineItem(ImageItem *image,
|
TimelineItem::TimelineItem(ImageItem *image,
|
||||||
const events::MessageEvent<msgs::Image> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Image> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupWidgetLayout<events::MessageEvent<msgs::Image>, ImageItem>(
|
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Image>, ImageItem>(
|
||||||
image, event, " sent an image", with_sender);
|
image, event, " sent an image", with_sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem::TimelineItem(FileItem *file,
|
TimelineItem::TimelineItem(FileItem *file,
|
||||||
const events::MessageEvent<msgs::File> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::File> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupWidgetLayout<events::MessageEvent<msgs::File>, FileItem>(
|
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::File>, FileItem>(
|
||||||
file, event, " sent a file", with_sender);
|
file, event, " sent a file", with_sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem::TimelineItem(AudioItem *audio,
|
TimelineItem::TimelineItem(AudioItem *audio,
|
||||||
const events::MessageEvent<msgs::Audio> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Audio> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupWidgetLayout<events::MessageEvent<msgs::Audio>, AudioItem>(
|
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Audio>, AudioItem>(
|
||||||
audio, event, " sent an audio clip", with_sender);
|
audio, event, " sent an audio clip", with_sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem::TimelineItem(VideoItem *video,
|
TimelineItem::TimelineItem(VideoItem *video,
|
||||||
const events::MessageEvent<msgs::Video> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Video> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupWidgetLayout<events::MessageEvent<msgs::Video>, VideoItem>(
|
setupWidgetLayout<mtx::events::RoomEvent<mtx::events::msg::Video>, VideoItem>(
|
||||||
video, event, " sent a video clip", with_sender);
|
video, event, " sent a video clip", with_sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to display remote notice messages.
|
* Used to display remote notice messages.
|
||||||
*/
|
*/
|
||||||
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Notice> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
event_id_ = event.eventId();
|
event_id_ = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
descriptionMsg_ = {TimelineViewManager::displayName(event.sender()),
|
descriptionMsg_ = {TimelineViewManager::displayName(sender),
|
||||||
event.sender(),
|
sender,
|
||||||
" sent a notification",
|
" sent a notification",
|
||||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))};
|
||||||
|
|
||||||
auto body = event.content().body().trimmed().toHtmlEscaped();
|
auto body = QString::fromStdString(event.content.body).trimmed().toHtmlEscaped();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
|
||||||
|
|
||||||
generateTimestamp(timestamp);
|
generateTimestamp(timestamp);
|
||||||
|
|
||||||
|
@ -218,14 +215,14 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
||||||
body = "<i>" + body + "</i>";
|
body = "<i>" + body + "</i>";
|
||||||
|
|
||||||
if (with_sender) {
|
if (with_sender) {
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(sender);
|
||||||
|
|
||||||
generateBody(displayName, body);
|
generateBody(displayName, body);
|
||||||
setupAvatarLayout(displayName);
|
setupAvatarLayout(displayName);
|
||||||
|
|
||||||
mainLayout_->addLayout(headerLayout_);
|
mainLayout_->addLayout(headerLayout_);
|
||||||
|
|
||||||
AvatarProvider::resolve(event.sender(), this);
|
AvatarProvider::resolve(sender, this);
|
||||||
} else {
|
} else {
|
||||||
generateBody(body);
|
generateBody(body);
|
||||||
setupSimpleLayout();
|
setupSimpleLayout();
|
||||||
|
@ -237,24 +234,25 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Notice> &event,
|
||||||
/*
|
/*
|
||||||
* Used to display remote emote messages.
|
* Used to display remote emote messages.
|
||||||
*/
|
*/
|
||||||
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
|
TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Emote> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
event_id_ = event.eventId();
|
event_id_ = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
auto body = event.content().body().trimmed();
|
auto body = QString::fromStdString(event.content.body).trimmed();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(sender);
|
||||||
auto emoteMsg = QString("* %1 %2").arg(displayName).arg(body);
|
auto emoteMsg = QString("* %1 %2").arg(displayName).arg(body);
|
||||||
|
|
||||||
descriptionMsg_ = {"",
|
descriptionMsg_ = {"",
|
||||||
event.sender(),
|
sender,
|
||||||
emoteMsg,
|
emoteMsg,
|
||||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))};
|
||||||
|
|
||||||
generateTimestamp(timestamp);
|
generateTimestamp(timestamp);
|
||||||
emoteMsg = emoteMsg.toHtmlEscaped();
|
emoteMsg = emoteMsg.toHtmlEscaped();
|
||||||
|
@ -266,7 +264,7 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
|
||||||
setupAvatarLayout(displayName);
|
setupAvatarLayout(displayName);
|
||||||
mainLayout_->addLayout(headerLayout_);
|
mainLayout_->addLayout(headerLayout_);
|
||||||
|
|
||||||
AvatarProvider::resolve(event.sender(), this);
|
AvatarProvider::resolve(sender, this);
|
||||||
} else {
|
} else {
|
||||||
generateBody(emoteMsg);
|
generateBody(emoteMsg);
|
||||||
setupSimpleLayout();
|
setupSimpleLayout();
|
||||||
|
@ -278,24 +276,25 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Emote> &event,
|
||||||
/*
|
/*
|
||||||
* Used to display remote text messages.
|
* Used to display remote text messages.
|
||||||
*/
|
*/
|
||||||
TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event,
|
TimelineItem::TimelineItem(const mtx::events::RoomEvent<mtx::events::msg::Text> &event,
|
||||||
bool with_sender,
|
bool with_sender,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
|
||||||
event_id_ = event.eventId();
|
event_id_ = QString::fromStdString(event.event_id);
|
||||||
|
const auto sender = QString::fromStdString(event.sender);
|
||||||
|
|
||||||
auto body = event.content().body().trimmed();
|
auto body = QString::fromStdString(event.content.body).trimmed();
|
||||||
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.timestamp());
|
auto timestamp = QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
|
||||||
auto displayName = TimelineViewManager::displayName(event.sender());
|
auto displayName = TimelineViewManager::displayName(sender);
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
descriptionMsg_ = {event.sender() == settings.value("auth/user_id") ? "You" : displayName,
|
descriptionMsg_ = {sender == settings.value("auth/user_id") ? "You" : displayName,
|
||||||
event.sender(),
|
sender,
|
||||||
QString(": %1").arg(body),
|
QString(": %1").arg(body),
|
||||||
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.timestamp()))};
|
descriptiveTime(QDateTime::fromMSecsSinceEpoch(event.origin_server_ts))};
|
||||||
|
|
||||||
generateTimestamp(timestamp);
|
generateTimestamp(timestamp);
|
||||||
|
|
||||||
|
@ -309,7 +308,7 @@ TimelineItem::TimelineItem(const events::MessageEvent<msgs::Text> &event,
|
||||||
|
|
||||||
mainLayout_->addLayout(headerLayout_);
|
mainLayout_->addLayout(headerLayout_);
|
||||||
|
|
||||||
AvatarProvider::resolve(event.sender(), this);
|
AvatarProvider::resolve(sender, this);
|
||||||
} else {
|
} else {
|
||||||
generateBody(body);
|
generateBody(body);
|
||||||
setupSimpleLayout();
|
setupSimpleLayout();
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#include "FloatingButton.h"
|
#include "FloatingButton.h"
|
||||||
#include "RoomMessages.h"
|
#include "RoomMessages.h"
|
||||||
#include "ScrollBar.h"
|
#include "ScrollBar.h"
|
||||||
#include "Sync.h"
|
|
||||||
|
|
||||||
#include "timeline/TimelineView.h"
|
#include "timeline/TimelineView.h"
|
||||||
#include "timeline/widgets/AudioItem.h"
|
#include "timeline/widgets/AudioItem.h"
|
||||||
|
@ -30,23 +29,7 @@
|
||||||
#include "timeline/widgets/ImageItem.h"
|
#include "timeline/widgets/ImageItem.h"
|
||||||
#include "timeline/widgets/VideoItem.h"
|
#include "timeline/widgets/VideoItem.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
TimelineView::TimelineView(const mtx::responses::Timeline &timeline,
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
static bool
|
|
||||||
isRedactedEvent(const QJsonObject &event)
|
|
||||||
{
|
|
||||||
if (event.contains("redacted_because"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (event.contains("unsigned") &&
|
|
||||||
event.value("unsigned").toObject().contains("redacted_because"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimelineView::TimelineView(const Timeline &timeline,
|
|
||||||
QSharedPointer<MatrixClient> client,
|
QSharedPointer<MatrixClient> client,
|
||||||
const QString &room_id,
|
const QString &room_id,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
|
@ -167,12 +150,12 @@ TimelineView::sliderMoved(int position)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msgs)
|
TimelineView::addBackwardsEvents(const QString &room_id, const mtx::responses::Messages &msgs)
|
||||||
{
|
{
|
||||||
if (room_id_ != room_id)
|
if (room_id_ != room_id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (msgs.chunk().count() == 0) {
|
if (msgs.chunk.size() == 0) {
|
||||||
isTimelineFinished = true;
|
isTimelineFinished = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -186,12 +169,11 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg
|
||||||
|
|
||||||
// Parse in reverse order to determine where we should not show sender's
|
// Parse in reverse order to determine where we should not show sender's
|
||||||
// name.
|
// name.
|
||||||
auto ii = msgs.chunk().size();
|
auto ii = msgs.chunk.size();
|
||||||
while (ii != 0) {
|
while (ii != 0) {
|
||||||
--ii;
|
--ii;
|
||||||
|
|
||||||
TimelineItem *item =
|
TimelineItem *item = parseMessageEvent(msgs.chunk[ii], TimelineDirection::Top);
|
||||||
parseMessageEvent(msgs.chunk().at(ii).toObject(), TimelineDirection::Top);
|
|
||||||
|
|
||||||
if (item != nullptr)
|
if (item != nullptr)
|
||||||
items.push_back(item);
|
items.push_back(item);
|
||||||
|
@ -210,11 +192,11 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg
|
||||||
|
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
|
|
||||||
prev_batch_token_ = msgs.end();
|
prev_batch_token_ = QString::fromStdString(msgs.end);
|
||||||
isPaginationInProgress_ = false;
|
isPaginationInProgress_ = false;
|
||||||
|
|
||||||
// Exclude the top stretch.
|
// Exclude the top stretch.
|
||||||
if (!msgs.chunk().isEmpty() && scroll_layout_->count() > 1)
|
if (msgs.chunk.size() != 0 && scroll_layout_->count() > 1)
|
||||||
notifyForLastEvent();
|
notifyForLastEvent();
|
||||||
|
|
||||||
// If this batch is the first being rendered (i.e the first and the last
|
// If this batch is the first being rendered (i.e the first and the last
|
||||||
|
@ -224,63 +206,59 @@ TimelineView::addBackwardsEvents(const QString &room_id, const RoomMessages &msg
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineItem *
|
TimelineItem *
|
||||||
TimelineView::parseMessageEvent(const QJsonObject &event, TimelineDirection direction)
|
TimelineView::parseMessageEvent(const mtx::events::collections::TimelineEvents &event,
|
||||||
|
TimelineDirection direction)
|
||||||
{
|
{
|
||||||
events::EventType ty = events::extractEventType(event);
|
namespace msg = mtx::events::msg;
|
||||||
|
using AudioEvent = mtx::events::RoomEvent<msg::Audio>;
|
||||||
|
using EmoteEvent = mtx::events::RoomEvent<msg::Emote>;
|
||||||
|
using FileEvent = mtx::events::RoomEvent<msg::File>;
|
||||||
|
using ImageEvent = mtx::events::RoomEvent<msg::Image>;
|
||||||
|
using NoticeEvent = mtx::events::RoomEvent<msg::Notice>;
|
||||||
|
using TextEvent = mtx::events::RoomEvent<msg::Text>;
|
||||||
|
using VideoEvent = mtx::events::RoomEvent<msg::Video>;
|
||||||
|
|
||||||
if (ty == events::EventType::RoomMessage) {
|
if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Audio>>(event)) {
|
||||||
events::MessageEventType msg_type = events::extractMessageEventType(event);
|
auto audio = mpark::get<mtx::events::RoomEvent<msg::Audio>>(event);
|
||||||
|
return processMessageEvent<AudioEvent, AudioItem>(audio, direction);
|
||||||
using Audio = events::MessageEvent<msgs::Audio>;
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Emote>>(event)) {
|
||||||
using Emote = events::MessageEvent<msgs::Emote>;
|
auto emote = mpark::get<mtx::events::RoomEvent<msg::Emote>>(event);
|
||||||
using File = events::MessageEvent<msgs::File>;
|
return processMessageEvent<EmoteEvent>(emote, direction);
|
||||||
using Image = events::MessageEvent<msgs::Image>;
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::File>>(event)) {
|
||||||
using Notice = events::MessageEvent<msgs::Notice>;
|
auto file = mpark::get<mtx::events::RoomEvent<msg::File>>(event);
|
||||||
using Text = events::MessageEvent<msgs::Text>;
|
return processMessageEvent<FileEvent, FileItem>(file, direction);
|
||||||
using Video = events::MessageEvent<msgs::Video>;
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Image>>(event)) {
|
||||||
|
auto image = mpark::get<mtx::events::RoomEvent<msg::Image>>(event);
|
||||||
if (msg_type == events::MessageEventType::Audio) {
|
return processMessageEvent<ImageEvent, ImageItem>(image, direction);
|
||||||
return processMessageEvent<Audio, AudioItem>(event, direction);
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Notice>>(event)) {
|
||||||
} else if (msg_type == events::MessageEventType::Emote) {
|
auto notice = mpark::get<mtx::events::RoomEvent<msg::Notice>>(event);
|
||||||
return processMessageEvent<Emote>(event, direction);
|
return processMessageEvent<NoticeEvent>(notice, direction);
|
||||||
} else if (msg_type == events::MessageEventType::File) {
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Text>>(event)) {
|
||||||
return processMessageEvent<File, FileItem>(event, direction);
|
auto text = mpark::get<mtx::events::RoomEvent<msg::Text>>(event);
|
||||||
} else if (msg_type == events::MessageEventType::Image) {
|
return processMessageEvent<TextEvent>(text, direction);
|
||||||
return processMessageEvent<Image, ImageItem>(event, direction);
|
} else if (mpark::holds_alternative<mtx::events::RoomEvent<msg::Video>>(event)) {
|
||||||
} else if (msg_type == events::MessageEventType::Notice) {
|
auto video = mpark::get<mtx::events::RoomEvent<msg::Video>>(event);
|
||||||
return processMessageEvent<Notice>(event, direction);
|
return processMessageEvent<VideoEvent, VideoItem>(video, direction);
|
||||||
} else if (msg_type == events::MessageEventType::Text) {
|
|
||||||
return processMessageEvent<Text>(event, direction);
|
|
||||||
} else if (msg_type == events::MessageEventType::Video) {
|
|
||||||
return processMessageEvent<Video, VideoItem>(event, direction);
|
|
||||||
} else if (msg_type == events::MessageEventType::Unknown) {
|
|
||||||
// TODO Handle redacted messages.
|
|
||||||
// Silenced for now.
|
|
||||||
if (!isRedactedEvent(event))
|
|
||||||
qWarning() << "Unknown message type" << event;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
TimelineView::addEvents(const Timeline &timeline)
|
TimelineView::addEvents(const mtx::responses::Timeline &timeline)
|
||||||
{
|
{
|
||||||
int message_count = 0;
|
int message_count = 0;
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
QString localUser = settings.value("auth/user_id").toString();
|
QString localUser = settings.value("auth/user_id").toString();
|
||||||
|
|
||||||
for (const auto &event : timeline.events()) {
|
for (const auto &event : timeline.events) {
|
||||||
TimelineItem *item = parseMessageEvent(event.toObject(), TimelineDirection::Bottom);
|
TimelineItem *item = parseMessageEvent(event, TimelineDirection::Bottom);
|
||||||
|
|
||||||
if (item != nullptr) {
|
if (item != nullptr) {
|
||||||
addTimelineItem(item, TimelineDirection::Bottom);
|
addTimelineItem(item, TimelineDirection::Bottom);
|
||||||
|
|
||||||
if (localUser != event.toObject().value("sender").toString())
|
if (localUser != getEventSender(event))
|
||||||
message_count += 1;
|
message_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,15 +268,15 @@ TimelineView::addEvents(const Timeline &timeline)
|
||||||
QApplication::processEvents();
|
QApplication::processEvents();
|
||||||
|
|
||||||
if (isInitialSync) {
|
if (isInitialSync) {
|
||||||
prev_batch_token_ = timeline.previousBatch();
|
prev_batch_token_ = QString::fromStdString(timeline.prev_batch);
|
||||||
isInitialSync = false;
|
isInitialSync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude the top stretch.
|
// Exclude the top stretch.
|
||||||
if (!timeline.events().isEmpty() && scroll_layout_->count() > 1)
|
if (timeline.events.size() != 0 && scroll_layout_->count() > 1)
|
||||||
notifyForLastEvent();
|
notifyForLastEvent();
|
||||||
|
|
||||||
if (isActiveWindow() && isVisible() && timeline.events().size() > 0)
|
if (isActiveWindow() && isVisible() && timeline.events.size() > 0)
|
||||||
readLastEvent();
|
readLastEvent();
|
||||||
|
|
||||||
return message_count;
|
return message_count;
|
||||||
|
@ -403,7 +381,7 @@ TimelineView::updatePendingMessage(int txn_id, QString event_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineView::addUserMessage(matrix::events::MessageEventType ty, const QString &body)
|
TimelineView::addUserMessage(mtx::events::MessageType ty, const QString &body)
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
auto user_id = settings.value("auth/user_id").toString();
|
auto user_id = settings.value("auth/user_id").toString();
|
||||||
|
@ -439,9 +417,9 @@ TimelineView::sendNextPendingMessage()
|
||||||
|
|
||||||
PendingMessage &m = pending_msgs_.head();
|
PendingMessage &m = pending_msgs_.head();
|
||||||
switch (m.ty) {
|
switch (m.ty) {
|
||||||
case matrix::events::MessageEventType::Audio:
|
case mtx::events::MessageType::Audio:
|
||||||
case matrix::events::MessageEventType::Image:
|
case mtx::events::MessageType::Image:
|
||||||
case matrix::events::MessageEventType::File:
|
case mtx::events::MessageType::File:
|
||||||
// FIXME: Improve the API
|
// FIXME: Improve the API
|
||||||
client_->sendRoomMessage(m.ty,
|
client_->sendRoomMessage(m.ty,
|
||||||
m.txn_id,
|
m.txn_id,
|
||||||
|
@ -573,3 +551,81 @@ TimelineView::event(QEvent *event)
|
||||||
|
|
||||||
return QWidget::event(event);
|
return QWidget::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
TimelineView::getEventSender(const mtx::events::collections::TimelineEvents &event) const
|
||||||
|
{
|
||||||
|
using Aliases = mtx::events::StateEvent<mtx::events::state::Aliases>;
|
||||||
|
using Avatar = mtx::events::StateEvent<mtx::events::state::Avatar>;
|
||||||
|
using CanonicalAlias = mtx::events::StateEvent<mtx::events::state::CanonicalAlias>;
|
||||||
|
using Create = mtx::events::StateEvent<mtx::events::state::Create>;
|
||||||
|
using HistoryVisibility = mtx::events::StateEvent<mtx::events::state::HistoryVisibility>;
|
||||||
|
using JoinRules = mtx::events::StateEvent<mtx::events::state::JoinRules>;
|
||||||
|
using Member = mtx::events::StateEvent<mtx::events::state::Member>;
|
||||||
|
using Name = mtx::events::StateEvent<mtx::events::state::Name>;
|
||||||
|
using PowerLevels = mtx::events::StateEvent<mtx::events::state::PowerLevels>;
|
||||||
|
using Topic = mtx::events::StateEvent<mtx::events::state::Topic>;
|
||||||
|
|
||||||
|
using Audio = mtx::events::RoomEvent<mtx::events::msg::Audio>;
|
||||||
|
using Emote = mtx::events::RoomEvent<mtx::events::msg::Emote>;
|
||||||
|
using File = mtx::events::RoomEvent<mtx::events::msg::File>;
|
||||||
|
using Image = mtx::events::RoomEvent<mtx::events::msg::Image>;
|
||||||
|
using Notice = mtx::events::RoomEvent<mtx::events::msg::Notice>;
|
||||||
|
using Text = mtx::events::RoomEvent<mtx::events::msg::Text>;
|
||||||
|
using Video = mtx::events::RoomEvent<mtx::events::msg::Video>;
|
||||||
|
|
||||||
|
if (mpark::holds_alternative<Aliases>(event)) {
|
||||||
|
auto msg = mpark::get<Aliases>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Avatar>(event)) {
|
||||||
|
auto msg = mpark::get<Avatar>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<CanonicalAlias>(event)) {
|
||||||
|
auto msg = mpark::get<CanonicalAlias>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Create>(event)) {
|
||||||
|
auto msg = mpark::get<Create>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<HistoryVisibility>(event)) {
|
||||||
|
auto msg = mpark::get<HistoryVisibility>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<JoinRules>(event)) {
|
||||||
|
auto msg = mpark::get<JoinRules>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Name>(event)) {
|
||||||
|
auto msg = mpark::get<Name>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Member>(event)) {
|
||||||
|
auto msg = mpark::get<Member>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<PowerLevels>(event)) {
|
||||||
|
auto msg = mpark::get<PowerLevels>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Topic>(event)) {
|
||||||
|
auto msg = mpark::get<Topic>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Audio>(event)) {
|
||||||
|
auto msg = mpark::get<Audio>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Emote>(event)) {
|
||||||
|
auto msg = mpark::get<Emote>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<File>(event)) {
|
||||||
|
auto msg = mpark::get<File>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Image>(event)) {
|
||||||
|
auto msg = mpark::get<Image>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Notice>(event)) {
|
||||||
|
auto msg = mpark::get<Notice>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Text>(event)) {
|
||||||
|
auto msg = mpark::get<Text>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
} else if (mpark::holds_alternative<Video>(event)) {
|
||||||
|
auto msg = mpark::get<Video>(event);
|
||||||
|
return QString::fromStdString(msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString("");
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
#include "Sync.h"
|
|
||||||
|
|
||||||
#include "timeline/TimelineView.h"
|
#include "timeline/TimelineView.h"
|
||||||
#include "timeline/TimelineViewManager.h"
|
#include "timeline/TimelineViewManager.h"
|
||||||
|
@ -72,7 +71,7 @@ TimelineViewManager::queueTextMessage(const QString &msg)
|
||||||
auto room_id = active_room_;
|
auto room_id = active_room_;
|
||||||
auto view = views_[room_id];
|
auto view = views_[room_id];
|
||||||
|
|
||||||
view->addUserMessage(matrix::events::MessageEventType::Text, msg);
|
view->addUserMessage(mtx::events::MessageType::Text, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -81,7 +80,7 @@ TimelineViewManager::queueEmoteMessage(const QString &msg)
|
||||||
auto room_id = active_room_;
|
auto room_id = active_room_;
|
||||||
auto view = views_[room_id];
|
auto view = views_[room_id];
|
||||||
|
|
||||||
view->addUserMessage(matrix::events::MessageEventType::Emote, msg);
|
view->addUserMessage(mtx::events::MessageType::Emote, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -96,7 +95,7 @@ TimelineViewManager::queueImageMessage(const QString &roomid,
|
||||||
|
|
||||||
auto view = views_[roomid];
|
auto view = views_[roomid];
|
||||||
|
|
||||||
view->addUserMessage<ImageItem, matrix::events::MessageEventType::Image>(url, filename);
|
view->addUserMessage<ImageItem, mtx::events::MessageType::Image>(url, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -111,7 +110,7 @@ TimelineViewManager::queueFileMessage(const QString &roomid,
|
||||||
|
|
||||||
auto view = views_[roomid];
|
auto view = views_[roomid];
|
||||||
|
|
||||||
view->addUserMessage<FileItem, matrix::events::MessageEventType::File>(url, filename);
|
view->addUserMessage<FileItem, mtx::events::MessageType::File>(url, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -126,7 +125,7 @@ TimelineViewManager::queueAudioMessage(const QString &roomid,
|
||||||
|
|
||||||
auto view = views_[roomid];
|
auto view = views_[roomid];
|
||||||
|
|
||||||
view->addUserMessage<AudioItem, matrix::events::MessageEventType::Audio>(url, filename);
|
view->addUserMessage<AudioItem, mtx::events::MessageType::Audio>(url, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -139,10 +138,10 @@ TimelineViewManager::clearAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::initialize(const Rooms &rooms)
|
TimelineViewManager::initialize(const mtx::responses::Rooms &rooms)
|
||||||
{
|
{
|
||||||
for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); ++it) {
|
for (auto it = rooms.join.cbegin(); it != rooms.join.cend(); ++it) {
|
||||||
addRoom(it.value(), it.key());
|
addRoom(it->second, QString::fromStdString(it->first));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,10 +154,10 @@ TimelineViewManager::initialize(const QList<QString> &rooms)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::addRoom(const JoinedRoom &room, const QString &room_id)
|
TimelineViewManager::addRoom(const mtx::responses::JoinedRoom &room, const QString &room_id)
|
||||||
{
|
{
|
||||||
// Create a history view with the room events.
|
// Create a history view with the room events.
|
||||||
TimelineView *view = new TimelineView(room.timeline(), client_, room_id);
|
TimelineView *view = new TimelineView(room.timeline, client_, room_id);
|
||||||
views_.insert(room_id, QSharedPointer<TimelineView>(view));
|
views_.insert(room_id, QSharedPointer<TimelineView>(view));
|
||||||
|
|
||||||
connect(view,
|
connect(view,
|
||||||
|
@ -195,10 +194,10 @@ TimelineViewManager::addRoom(const QString &room_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimelineViewManager::sync(const Rooms &rooms)
|
TimelineViewManager::sync(const mtx::responses::Rooms &rooms)
|
||||||
{
|
{
|
||||||
for (auto it = rooms.join().constBegin(); it != rooms.join().constEnd(); ++it) {
|
for (auto it = rooms.join.cbegin(); it != rooms.join.cend(); ++it) {
|
||||||
auto roomid = it.key();
|
auto roomid = QString::fromStdString(it->first);
|
||||||
|
|
||||||
if (!views_.contains(roomid)) {
|
if (!views_.contains(roomid)) {
|
||||||
qDebug() << "Ignoring event from unknown room" << roomid;
|
qDebug() << "Ignoring event from unknown room" << roomid;
|
||||||
|
@ -207,7 +206,7 @@ TimelineViewManager::sync(const Rooms &rooms)
|
||||||
|
|
||||||
auto view = views_.value(roomid);
|
auto view = views_.value(roomid);
|
||||||
|
|
||||||
int msgs_added = view->addEvents(it.value().timeline());
|
int msgs_added = view->addEvents(it->second.timeline);
|
||||||
|
|
||||||
if (msgs_added > 0) {
|
if (msgs_added > 0) {
|
||||||
// TODO: When the app window gets active the current
|
// TODO: When the app window gets active the current
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
|
|
||||||
#include "timeline/widgets/AudioItem.h"
|
#include "timeline/widgets/AudioItem.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
constexpr int MaxWidth = 400;
|
constexpr int MaxWidth = 400;
|
||||||
constexpr int Height = 70;
|
constexpr int Height = 70;
|
||||||
constexpr int IconRadius = 22;
|
constexpr int IconRadius = 22;
|
||||||
|
@ -77,15 +74,15 @@ AudioItem::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioItem::AudioItem(QSharedPointer<MatrixClient> client,
|
AudioItem::AudioItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::Audio> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Audio> &event,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, url_{event.msgContent().url()}
|
, url_{QUrl(QString::fromStdString(event.content.url))}
|
||||||
, text_{event.content().body()}
|
, text_{QString::fromStdString(event.content.body)}
|
||||||
, event_{event}
|
, event_{event}
|
||||||
, client_{client}
|
, client_{client}
|
||||||
{
|
{
|
||||||
readableFileSize_ = calculateFileSize(event.msgContent().info().size);
|
readableFileSize_ = calculateFileSize(event.content.info.size);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -151,14 +148,14 @@ AudioItem::mousePressEvent(QMouseEvent *event)
|
||||||
if (filenameToSave_.isEmpty())
|
if (filenameToSave_.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
client_->downloadFile(event_.eventId(), url_);
|
client_->downloadFile(QString::fromStdString(event_.event_id), url_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioItem::fileDownloaded(const QString &event_id, const QByteArray &data)
|
AudioItem::fileDownloaded(const QString &event_id, const QByteArray &data)
|
||||||
{
|
{
|
||||||
if (event_id != event_.eventId())
|
if (event_id != QString::fromStdString(event_.event_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
|
|
||||||
#include "timeline/widgets/FileItem.h"
|
#include "timeline/widgets/FileItem.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
constexpr int MaxWidth = 400;
|
constexpr int MaxWidth = 400;
|
||||||
constexpr int Height = 70;
|
constexpr int Height = 70;
|
||||||
constexpr int IconRadius = 22;
|
constexpr int IconRadius = 22;
|
||||||
|
@ -64,15 +61,15 @@ FileItem::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
FileItem::FileItem(QSharedPointer<MatrixClient> client,
|
FileItem::FileItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::File> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::File> &event,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, url_{event.msgContent().url()}
|
, url_{QString::fromStdString(event.content.url)}
|
||||||
, text_{event.content().body()}
|
, text_{QString::fromStdString(event.content.body)}
|
||||||
, event_{event}
|
, event_{event}
|
||||||
, client_{client}
|
, client_{client}
|
||||||
{
|
{
|
||||||
readableFileSize_ = calculateFileSize(event.msgContent().info().size);
|
readableFileSize_ = calculateFileSize(event.content.info.size);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
@ -138,7 +135,7 @@ FileItem::mousePressEvent(QMouseEvent *event)
|
||||||
if (filenameToSave_.isEmpty())
|
if (filenameToSave_.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
client_->downloadFile(event_.eventId(), url_);
|
client_->downloadFile(QString::fromStdString(event_.event_id), url_);
|
||||||
} else {
|
} else {
|
||||||
openUrl();
|
openUrl();
|
||||||
}
|
}
|
||||||
|
@ -147,7 +144,7 @@ FileItem::mousePressEvent(QMouseEvent *event)
|
||||||
void
|
void
|
||||||
FileItem::fileDownloaded(const QString &event_id, const QByteArray &data)
|
FileItem::fileDownloaded(const QString &event_id, const QByteArray &data)
|
||||||
{
|
{
|
||||||
if (event_id != event_.eventId())
|
if (event_id != QString::fromStdString(event_.event_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -25,11 +25,8 @@
|
||||||
#include "dialogs/ImageOverlay.h"
|
#include "dialogs/ImageOverlay.h"
|
||||||
#include "timeline/widgets/ImageItem.h"
|
#include "timeline/widgets/ImageItem.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::Image> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Image> &event,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, event_{event}
|
, event_{event}
|
||||||
|
@ -39,8 +36,8 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
setCursor(Qt::PointingHandCursor);
|
setCursor(Qt::PointingHandCursor);
|
||||||
setAttribute(Qt::WA_Hover, true);
|
setAttribute(Qt::WA_Hover, true);
|
||||||
|
|
||||||
url_ = event.msgContent().url();
|
url_ = QString::fromStdString(event.content.url);
|
||||||
text_ = event.content().body();
|
text_ = QString::fromStdString(event.content.body);
|
||||||
|
|
||||||
QList<QString> url_parts = url_.toString().split("mxc://");
|
QList<QString> url_parts = url_.toString().split("mxc://");
|
||||||
|
|
||||||
|
@ -53,7 +50,7 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
url_ = QString("%1/_matrix/media/r0/download/%2")
|
url_ = QString("%1/_matrix/media/r0/download/%2")
|
||||||
.arg(client_.data()->getHomeServer().toString(), media_params);
|
.arg(client_.data()->getHomeServer().toString(), media_params);
|
||||||
|
|
||||||
client_.data()->downloadImage(event.eventId(), url_);
|
client_.data()->downloadImage(QString::fromStdString(event.event_id), url_);
|
||||||
|
|
||||||
connect(client_.data(),
|
connect(client_.data(),
|
||||||
SIGNAL(imageDownloaded(const QString &, const QPixmap &)),
|
SIGNAL(imageDownloaded(const QString &, const QPixmap &)),
|
||||||
|
@ -91,7 +88,7 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
|
||||||
void
|
void
|
||||||
ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img)
|
ImageItem::imageDownloaded(const QString &event_id, const QPixmap &img)
|
||||||
{
|
{
|
||||||
if (event_id != event_.eventId())
|
if (event_id != QString::fromStdString(event_.event_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setImage(img);
|
setImage(img);
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
|
|
||||||
#include "timeline/widgets/VideoItem.h"
|
#include "timeline/widgets/VideoItem.h"
|
||||||
|
|
||||||
namespace events = matrix::events;
|
|
||||||
namespace msgs = matrix::events::messages;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
VideoItem::init()
|
VideoItem::init()
|
||||||
{
|
{
|
||||||
|
@ -39,15 +36,15 @@ VideoItem::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoItem::VideoItem(QSharedPointer<MatrixClient> client,
|
VideoItem::VideoItem(QSharedPointer<MatrixClient> client,
|
||||||
const events::MessageEvent<msgs::Video> &event,
|
const mtx::events::RoomEvent<mtx::events::msg::Video> &event,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, url_{event.msgContent().url()}
|
, url_{QString::fromStdString(event.content.url)}
|
||||||
, text_{event.content().body()}
|
, text_{QString::fromStdString(event.content.body)}
|
||||||
, event_{event}
|
, event_{event}
|
||||||
, client_{client}
|
, client_{client}
|
||||||
{
|
{
|
||||||
readableFileSize_ = calculateFileSize(event.msgContent().info().size);
|
readableFileSize_ = calculateFileSize(event.content.info.size);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
707
tests/events.cc
707
tests/events.cc
|
@ -1,707 +0,0 @@
|
||||||
#include <QDebug>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
#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(BaseEvent, Deserialization)
|
|
||||||
{
|
|
||||||
// NameEventContent
|
|
||||||
auto data =
|
|
||||||
QJsonObject{{"content", QJsonObject{{"name", "Room Name"}}}, {"type", "m.room.name"}};
|
|
||||||
|
|
||||||
Event<NameEventContent> name_event;
|
|
||||||
name_event.deserialize(data);
|
|
||||||
EXPECT_EQ(name_event.content().name(), "Room Name");
|
|
||||||
EXPECT_EQ(name_event.serialize(), data);
|
|
||||||
|
|
||||||
// TopicEventContent
|
|
||||||
data = QJsonObject{{"content", QJsonObject{{"topic", "Room Topic"}}},
|
|
||||||
{"unsigned", QJsonObject{{"age", 22}, {"transaction_id", "randomid"}}},
|
|
||||||
{"type", "m.room.topic"}};
|
|
||||||
|
|
||||||
Event<TopicEventContent> topic_event;
|
|
||||||
topic_event.deserialize(data);
|
|
||||||
EXPECT_EQ(topic_event.content().topic(), "Room Topic");
|
|
||||||
EXPECT_EQ(topic_event.unsignedData().age(), 22);
|
|
||||||
EXPECT_EQ(topic_event.unsignedData().transactionId(), "randomid");
|
|
||||||
EXPECT_EQ(topic_event.serialize(), data);
|
|
||||||
|
|
||||||
// AvatarEventContent
|
|
||||||
data = QJsonObject{
|
|
||||||
{"content", QJsonObject{{"url", "https://matrix.org"}}},
|
|
||||||
{"unsigned", QJsonObject{{"age", 1343434343}, {"transaction_id", "m33434.33"}}},
|
|
||||||
{"type", "m.room.avatar"}};
|
|
||||||
|
|
||||||
Event<AvatarEventContent> avatar_event;
|
|
||||||
avatar_event.deserialize(data);
|
|
||||||
EXPECT_EQ(avatar_event.content().url().toString(), "https://matrix.org");
|
|
||||||
EXPECT_EQ(avatar_event.unsignedData().age(), 1343434343);
|
|
||||||
EXPECT_EQ(avatar_event.unsignedData().transactionId(), "m33434.33");
|
|
||||||
EXPECT_EQ(avatar_event.serialize(), data);
|
|
||||||
|
|
||||||
// AliasesEventContent
|
|
||||||
data = QJsonObject{
|
|
||||||
{"content",
|
|
||||||
QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}}},
|
|
||||||
{"unsigned", QJsonObject{{"transaction_id", "m33434.33"}}},
|
|
||||||
{"type", "m.room.aliases"}};
|
|
||||||
|
|
||||||
Event<AliasesEventContent> aliases_event;
|
|
||||||
aliases_event.deserialize(data);
|
|
||||||
EXPECT_EQ(aliases_event.content().aliases().size(), 2);
|
|
||||||
EXPECT_EQ(aliases_event.unsignedData().transactionId(), "m33434.33");
|
|
||||||
EXPECT_EQ(aliases_event.serialize(), data);
|
|
||||||
|
|
||||||
// CreateEventContent
|
|
||||||
data = QJsonObject{{"content", QJsonObject{{"creator", "@alice:matrix.org"}}},
|
|
||||||
{"unsigned", QJsonObject{{"age", 2233}}},
|
|
||||||
{"type", "m.room.create"}};
|
|
||||||
|
|
||||||
Event<CreateEventContent> create_event;
|
|
||||||
create_event.deserialize(data);
|
|
||||||
EXPECT_EQ(create_event.content().creator(), "@alice:matrix.org");
|
|
||||||
EXPECT_EQ(create_event.unsignedData().age(), 2233);
|
|
||||||
EXPECT_EQ(create_event.serialize(), data);
|
|
||||||
|
|
||||||
// JoinRulesEventContent
|
|
||||||
data = QJsonObject{{"content", QJsonObject{{"join_rule", "private"}}},
|
|
||||||
{"type", "m.room.join_rules"}};
|
|
||||||
|
|
||||||
Event<JoinRulesEventContent> join_rules_event;
|
|
||||||
join_rules_event.deserialize(data);
|
|
||||||
EXPECT_EQ(join_rules_event.content().joinRule(), JoinRule::Private);
|
|
||||||
EXPECT_EQ(join_rules_event.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BaseEvent, DeserializationException)
|
|
||||||
{
|
|
||||||
auto data =
|
|
||||||
QJsonObject{{"content", QJsonObject{{"rule", "private"}}}, {"type", "m.room.join_rules"}};
|
|
||||||
|
|
||||||
Event<JoinRulesEventContent> event1;
|
|
||||||
ASSERT_THROW(event1.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}},
|
|
||||||
{"type", "m.room.join_rules"}};
|
|
||||||
|
|
||||||
Event<JoinRulesEventContent> event2;
|
|
||||||
ASSERT_THROW(event2.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
data = QJsonObject{{"contents", QJsonObject{{"join_rule", "private"}}},
|
|
||||||
{"unsigned", QJsonObject{{"age", "222"}}},
|
|
||||||
{"type", "m.room.join_rules"}};
|
|
||||||
|
|
||||||
Event<JoinRulesEventContent> event3;
|
|
||||||
ASSERT_THROW(event3.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(RoomEvent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
|
||||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
|
||||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
|
||||||
{"sender", "@alice:matrix.org"},
|
|
||||||
{"origin_server_ts", 1323238293289323LL},
|
|
||||||
{"type", "m.room.name"}};
|
|
||||||
|
|
||||||
RoomEvent<NameEventContent> event;
|
|
||||||
event.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(event.eventId(), "$asdfafdf8af:matrix.org");
|
|
||||||
EXPECT_EQ(event.roomId(), "!aasdfaeae23r9:matrix.org");
|
|
||||||
EXPECT_EQ(event.sender(), "@alice:matrix.org");
|
|
||||||
EXPECT_EQ(event.timestamp(), 1323238293289323);
|
|
||||||
EXPECT_EQ(event.content().name(), "Name");
|
|
||||||
EXPECT_EQ(event.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(RoomEvent, DeserializationException)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
|
||||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
|
||||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
|
||||||
{"origin_server_ts", 1323238293289323LL},
|
|
||||||
{"type", "m.room.name"}};
|
|
||||||
|
|
||||||
RoomEvent<NameEventContent> event;
|
|
||||||
|
|
||||||
try {
|
|
||||||
event.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("sender key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(StateEvent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"content", QJsonObject{{"name", "Name"}}},
|
|
||||||
{"event_id", "$asdfafdf8af:matrix.org"},
|
|
||||||
{"state_key", "some_state_key"},
|
|
||||||
{"prev_content", QJsonObject{{"name", "Previous Name"}}},
|
|
||||||
{"room_id", "!aasdfaeae23r9:matrix.org"},
|
|
||||||
{"sender", "@alice:matrix.org"},
|
|
||||||
{"origin_server_ts", 1323238293289323LL},
|
|
||||||
{"type", "m.room.name"}};
|
|
||||||
|
|
||||||
StateEvent<NameEventContent> event;
|
|
||||||
event.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(event.eventId(), "$asdfafdf8af:matrix.org");
|
|
||||||
EXPECT_EQ(event.roomId(), "!aasdfaeae23r9:matrix.org");
|
|
||||||
EXPECT_EQ(event.sender(), "@alice:matrix.org");
|
|
||||||
EXPECT_EQ(event.timestamp(), 1323238293289323);
|
|
||||||
EXPECT_EQ(event.content().name(), "Name");
|
|
||||||
EXPECT_EQ(event.stateKey(), "some_state_key");
|
|
||||||
EXPECT_EQ(event.previousContent().name(), "Previous Name");
|
|
||||||
EXPECT_EQ(event.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(StateEvent, DeserializationException)
|
|
||||||
{
|
|
||||||
auto data = 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},
|
|
||||||
{"type", "m.room.name"}};
|
|
||||||
|
|
||||||
StateEvent<NameEventContent> event;
|
|
||||||
|
|
||||||
try {
|
|
||||||
event.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("state_key key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(EventType, Mapping)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.aliases"}}),
|
|
||||||
EventType::RoomAliases);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.avatar"}}), EventType::RoomAvatar);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.canonical_alias"}}),
|
|
||||||
EventType::RoomCanonicalAlias);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.create"}}), EventType::RoomCreate);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.history_visibility"}}),
|
|
||||||
EventType::RoomHistoryVisibility);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.join_rules"}}),
|
|
||||||
EventType::RoomJoinRules);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.member"}}), EventType::RoomMember);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.message"}}),
|
|
||||||
EventType::RoomMessage);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.name"}}), EventType::RoomName);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.power_levels"}}),
|
|
||||||
EventType::RoomPowerLevels);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.topic"}}), EventType::RoomTopic);
|
|
||||||
EXPECT_EQ(extractEventType(QJsonObject{{"type", "m.room.unknown"}}),
|
|
||||||
EventType::Unsupported);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AliasesEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"aliases", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}};
|
|
||||||
|
|
||||||
AliasesEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.aliases().size(), 2);
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AliasesEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"#test:matrix.org", "#test2:matrix.org"};
|
|
||||||
|
|
||||||
AliasesEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AliasesEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", QJsonArray{"#test:matrix.org", "#test2:matrix.org"}}};
|
|
||||||
|
|
||||||
AliasesEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("aliases key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AvatarEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"url", "https://matrix.org/avatar.png"}};
|
|
||||||
|
|
||||||
AvatarEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.url().toString(), "https://matrix.org/avatar.png");
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AvatarEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"key", "url"};
|
|
||||||
|
|
||||||
AvatarEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AvatarEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "https://matrix.org"}};
|
|
||||||
|
|
||||||
AvatarEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("url key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CreateEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"creator", "@alice:matrix.org"}};
|
|
||||||
|
|
||||||
CreateEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.creator(), "@alice:matrix.org");
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CreateEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"creator", "alice"};
|
|
||||||
|
|
||||||
CreateEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CreateEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "@alice:matrix.org"}};
|
|
||||||
|
|
||||||
CreateEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("creator key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(HistoryVisibilityEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"history_visibility", "invited"}};
|
|
||||||
|
|
||||||
HistoryVisibilityEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Invited);
|
|
||||||
|
|
||||||
data = QJsonObject{{"history_visibility", "joined"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Joined);
|
|
||||||
|
|
||||||
data = QJsonObject{{"history_visibility", "shared"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::Shared);
|
|
||||||
|
|
||||||
data = QJsonObject{{"history_visibility", "world_readable"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.historyVisibility(), HistoryVisibility::WorldReadable);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(HistoryVisibilityEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"history_visibility", "alice"};
|
|
||||||
|
|
||||||
HistoryVisibilityEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(HistoryVisibilityEventContent, InvalidHistoryVisibility)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"history_visibility", "wrong"}};
|
|
||||||
|
|
||||||
HistoryVisibilityEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("Unknown history_visibility value: wrong", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(HistoryVisibilityEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "joined"}};
|
|
||||||
|
|
||||||
HistoryVisibilityEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("history_visibility key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JoinRulesEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"join_rule", "invite"}};
|
|
||||||
|
|
||||||
JoinRulesEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.joinRule(), JoinRule::Invite);
|
|
||||||
|
|
||||||
data = QJsonObject{{"join_rule", "knock"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.joinRule(), JoinRule::Knock);
|
|
||||||
|
|
||||||
data = QJsonObject{{"join_rule", "private"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.joinRule(), JoinRule::Private);
|
|
||||||
|
|
||||||
data = QJsonObject{{"join_rule", "public"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.joinRule(), JoinRule::Public);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JoinRulesEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"rule", "alice"};
|
|
||||||
|
|
||||||
JoinRulesEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JoinRulesEventContent, InvalidHistoryVisibility)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"join_rule", "wrong"}};
|
|
||||||
|
|
||||||
JoinRulesEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("Unknown join_rule value: wrong", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(JoinRulesEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "invite"}};
|
|
||||||
|
|
||||||
JoinRulesEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("join_rule key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CanonicalAliasEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"alias", "Room Alias"}};
|
|
||||||
|
|
||||||
CanonicalAliasEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.alias(), "Room Alias");
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CanonicalAliasEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"alias", "Room Alias"};
|
|
||||||
|
|
||||||
CanonicalAliasEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CanonicalAliasEventContent, MissingKey)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "alias"}};
|
|
||||||
|
|
||||||
CanonicalAliasEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("alias key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MemberEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
MemberEventContent content;
|
|
||||||
|
|
||||||
auto data = QJsonObject{{"membership", "join"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.membershipState(), Membership::Join);
|
|
||||||
|
|
||||||
data = QJsonObject{{"membership", "invite"}, {"displayname", "Username"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.membershipState(), Membership::Invite);
|
|
||||||
EXPECT_EQ(content.displayName(), "Username");
|
|
||||||
|
|
||||||
data = QJsonObject{{"membership", "leave"}, {"avatar_url", "https://matrix.org"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.membershipState(), Membership::Leave);
|
|
||||||
EXPECT_EQ(content.avatarUrl().toString(), "https://matrix.org");
|
|
||||||
|
|
||||||
data = QJsonObject{{"membership", "ban"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.membershipState(), Membership::Ban);
|
|
||||||
|
|
||||||
data = QJsonObject{{"membership", "knock"}};
|
|
||||||
|
|
||||||
content.deserialize(data);
|
|
||||||
EXPECT_EQ(content.membershipState(), Membership::Knock);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MemberEventContent, InvalidMembership)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"membership", "wrong"}};
|
|
||||||
|
|
||||||
MemberEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("Unknown membership value: wrong", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MemberEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"name", "join"};
|
|
||||||
|
|
||||||
MemberEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(MemberEventContent, MissingName)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "random"}};
|
|
||||||
|
|
||||||
MemberEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("membership key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NameEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"name", "Room Name"}};
|
|
||||||
|
|
||||||
NameEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.name(), "Room Name");
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NameEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"name", "Room Name"};
|
|
||||||
|
|
||||||
NameEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(NameEventContent, MissingName)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "Room Name"}};
|
|
||||||
|
|
||||||
NameEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("name key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PowerLevelsEventContent, DefaultValues)
|
|
||||||
{
|
|
||||||
PowerLevelsEventContent power_levels;
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.banLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
EXPECT_EQ(power_levels.inviteLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
EXPECT_EQ(power_levels.kickLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
EXPECT_EQ(power_levels.redactLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.eventsDefaultLevel(), static_cast<int>(PowerLevels::User));
|
|
||||||
EXPECT_EQ(power_levels.usersDefaultLevel(), static_cast<int>(PowerLevels::User));
|
|
||||||
EXPECT_EQ(power_levels.stateDefaultLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
|
|
||||||
// Default levels.
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@joe:matrix.org"), static_cast<int>(PowerLevels::User));
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.room.message"), static_cast<int>(PowerLevels::User));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PowerLevelsEventContent, FullDeserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{
|
|
||||||
{"ban", 1},
|
|
||||||
{"invite", 2},
|
|
||||||
{"kick", 3},
|
|
||||||
{"redact", 4},
|
|
||||||
|
|
||||||
{"events_default", 5},
|
|
||||||
{"state_default", 6},
|
|
||||||
{"users_default", 7},
|
|
||||||
|
|
||||||
{"events", QJsonObject{{"m.message.text", 8}, {"m.message.image", 9}}},
|
|
||||||
{"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}},
|
|
||||||
};
|
|
||||||
|
|
||||||
PowerLevelsEventContent power_levels;
|
|
||||||
power_levels.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.banLevel(), 1);
|
|
||||||
EXPECT_EQ(power_levels.inviteLevel(), 2);
|
|
||||||
EXPECT_EQ(power_levels.kickLevel(), 3);
|
|
||||||
EXPECT_EQ(power_levels.redactLevel(), 4);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.eventsDefaultLevel(), 5);
|
|
||||||
EXPECT_EQ(power_levels.stateDefaultLevel(), 6);
|
|
||||||
EXPECT_EQ(power_levels.usersDefaultLevel(), 7);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@alice:matrix.org"), 10);
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@bob:matrix.org"), 11);
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@carl:matrix.org"), 7);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.text"), 8);
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.image"), 9);
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.gif"), 5);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PowerLevelsEventContent, PartialDeserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{
|
|
||||||
{"ban", 1},
|
|
||||||
{"invite", 2},
|
|
||||||
|
|
||||||
{"events_default", 5},
|
|
||||||
{"users_default", 7},
|
|
||||||
|
|
||||||
{"users", QJsonObject{{"@alice:matrix.org", 10}, {"@bob:matrix.org", 11}}},
|
|
||||||
};
|
|
||||||
|
|
||||||
PowerLevelsEventContent power_levels;
|
|
||||||
power_levels.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.banLevel(), 1);
|
|
||||||
EXPECT_EQ(power_levels.inviteLevel(), 2);
|
|
||||||
EXPECT_EQ(power_levels.kickLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
EXPECT_EQ(power_levels.redactLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.eventsDefaultLevel(), 5);
|
|
||||||
EXPECT_EQ(power_levels.stateDefaultLevel(), static_cast<int>(PowerLevels::Moderator));
|
|
||||||
EXPECT_EQ(power_levels.usersDefaultLevel(), 7);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@alice:matrix.org"), 10);
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@bob:matrix.org"), 11);
|
|
||||||
EXPECT_EQ(power_levels.userLevel("@carl:matrix.org"), 7);
|
|
||||||
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.text"), 5);
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.image"), 5);
|
|
||||||
EXPECT_EQ(power_levels.eventLevel("m.message.gif"), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PowerLevelsEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"test", "test2"};
|
|
||||||
|
|
||||||
PowerLevelsEventContent power_levels;
|
|
||||||
|
|
||||||
ASSERT_THROW(power_levels.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TopicEventContent, Deserialization)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"topic", "Room Topic"}};
|
|
||||||
|
|
||||||
TopicEventContent content;
|
|
||||||
content.deserialize(data);
|
|
||||||
|
|
||||||
EXPECT_EQ(content.topic(), "Room Topic");
|
|
||||||
EXPECT_EQ(content.serialize(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TopicEventContent, NotAnObject)
|
|
||||||
{
|
|
||||||
auto data = QJsonArray{"topic", "Room Topic"};
|
|
||||||
|
|
||||||
TopicEventContent content;
|
|
||||||
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TopicEventContent, MissingName)
|
|
||||||
{
|
|
||||||
auto data = QJsonObject{{"key", "Room Name"}};
|
|
||||||
|
|
||||||
TopicEventContent content;
|
|
||||||
ASSERT_THROW(content.deserialize(data), DeserializationException);
|
|
||||||
|
|
||||||
try {
|
|
||||||
content.deserialize(data);
|
|
||||||
} catch (const DeserializationException &e) {
|
|
||||||
ASSERT_STREQ("topic key is missing", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,287 +0,0 @@
|
||||||
#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