Move visitors out of TimelineModel

This commit is contained in:
Nicolas Werner 2019-12-27 21:49:55 +01:00
parent 768ae9a5e0
commit e084543cc0
4 changed files with 571 additions and 446 deletions

View File

@ -219,6 +219,7 @@ set(SRC_FILES
src/ChatPage.cpp
src/CommunitiesListItem.cpp
src/CommunitiesList.cpp
src/EventAccessors.cpp
src/InviteeItem.cpp
src/LoginPage.cpp
src/Logging.cpp

363
src/EventAccessors.cpp Normal file
View File

@ -0,0 +1,363 @@
#include "EventAccessors.h"
#include <type_traits>
namespace {
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const &) = delete;
void operator=(nonesuch const &) = delete;
};
namespace detail {
template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template<class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template<template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
struct EventMsgType
{
template<class E>
using msgtype_t = decltype(E::msgtype);
template<class T>
mtx::events::MessageType operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<msgtype_t, T>::value)
return mtx::events::getMessageType(e.content.msgtype);
return mtx::events::MessageType::Unknown;
}
};
struct EventRoomName
{
template<class T>
std::string operator()(const T &e)
{
if constexpr (std::is_same_v<mtx::events::StateEvent<mtx::events::state::Name>, T>)
return e.content.name;
return "";
}
};
struct EventRoomTopic
{
template<class T>
std::string operator()(const T &e)
{
if constexpr (std::is_same_v<mtx::events::StateEvent<mtx::events::state::Topic>, T>)
return e.content.topic;
return "";
}
};
struct EventBody
{
template<class C>
using body_t = decltype(C::body);
template<class T>
std::string operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<body_t, T>::value)
return e.content.body;
return "";
}
};
struct EventFormattedBody
{
template<class C>
using formatted_body_t = decltype(C::formatted_body);
template<class T>
std::string operator()(const mtx::events::RoomEvent<T> &e)
{
if constexpr (is_detected<formatted_body_t, T>::value)
return e.content.formatted_body;
return "";
}
};
struct EventFile
{
template<class Content>
using file_t = decltype(Content::file);
template<class T>
std::optional<mtx::crypto::EncryptedFile> operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<file_t, T>::value)
return e.content.file;
return std::nullopt;
}
};
struct EventUrl
{
template<class Content>
using url_t = decltype(Content::url);
template<class T>
std::string operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<url_t, T>::value) {
if (auto file = EventFile{}(e))
return file->url;
return e.content.url;
}
return "";
}
};
struct EventThumbnailUrl
{
template<class Content>
using thumbnail_url_t = decltype(Content::info.thumbnail_url);
template<class T>
std::string operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<thumbnail_url_t, T>::value) {
return e.content.info.thumbnail_url;
}
return "";
}
};
struct EventFilename
{
template<class T>
std::string operator()(const mtx::events::Event<T> &)
{
return "";
}
std::string operator()(const mtx::events::RoomEvent<mtx::events::msg::Audio> &e)
{
// body may be the original filename
return e.content.body;
}
std::string operator()(const mtx::events::RoomEvent<mtx::events::msg::Video> &e)
{
// body may be the original filename
return e.content.body;
}
std::string operator()(const mtx::events::RoomEvent<mtx::events::msg::Image> &e)
{
// body may be the original filename
return e.content.body;
}
std::string operator()(const mtx::events::RoomEvent<mtx::events::msg::File> &e)
{
// body may be the original filename
if (!e.content.filename.empty())
return e.content.filename;
return e.content.body;
}
};
struct EventMimeType
{
template<class Content>
using mimetype_t = decltype(Content::info.mimetype);
template<class T>
std::string operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<mimetype_t, T>::value) {
return e.content.info.mimetype;
}
return "";
}
};
struct EventFilesize
{
template<class Content>
using filesize_t = decltype(Content::info.size);
template<class T>
int64_t operator()(const mtx::events::RoomEvent<T> &e)
{
if constexpr (is_detected<filesize_t, T>::value) {
return e.content.info.size;
}
return 0;
}
};
struct EventInReplyTo
{
template<class Content>
using related_ev_id_t = decltype(Content::relates_to.in_reply_to.event_id);
template<class T>
std::string operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<related_ev_id_t, T>::value) {
return e.content.relates_to.in_reply_to.event_id;
}
return "";
}
};
struct EventMediaHeight
{
template<class Content>
using h_t = decltype(Content::info.h);
template<class T>
uint64_t operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<h_t, T>::value) {
return e.content.info.h;
}
return -1;
}
};
struct EventMediaWidth
{
template<class Content>
using w_t = decltype(Content::info.w);
template<class T>
uint64_t operator()(const mtx::events::Event<T> &e)
{
if constexpr (is_detected<w_t, T>::value) {
return e.content.info.w;
}
return -1;
}
};
template<class T>
double
eventPropHeight(const mtx::events::RoomEvent<T> &e)
{
auto w = eventWidth(e);
if (w == 0)
w = 1;
double prop = eventHeight(e) / (double)w;
return prop > 0 ? prop : 1.;
}
}
std::string
mtx::accessors::event_id(const mtx::events::collections::TimelineEvents &event)
{
return std::visit([](const auto e) { return e.event_id; }, event);
}
std::string
mtx::accessors::room_id(const mtx::events::collections::TimelineEvents &event)
{
return std::visit([](const auto e) { return e.room_id; }, event);
}
std::string
mtx::accessors::sender(const mtx::events::collections::TimelineEvents &event)
{
return std::visit([](const auto e) { return e.sender; }, event);
}
QDateTime
mtx::accessors::origin_server_ts(const mtx::events::collections::TimelineEvents &event)
{
return QDateTime::fromMSecsSinceEpoch(
std::visit([](const auto e) { return e.origin_server_ts; }, event));
}
std::string
mtx::accessors::filename(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventFilename{}, event);
}
mtx::events::MessageType
mtx::accessors::msg_type(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventMsgType{}, event);
}
std::string
mtx::accessors::room_name(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventRoomName{}, event);
}
std::string
mtx::accessors::room_topic(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventRoomTopic{}, event);
}
std::string
mtx::accessors::body(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventBody{}, event);
}
std::string
mtx::accessors::formatted_body(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventFormattedBody{}, event);
}
QString
mtx::accessors::formattedBodyWithFallback(const mtx::events::collections::TimelineEvents &event)
{
auto formatted = formatted_body(event);
if (!formatted.empty())
return QString::fromStdString(formatted);
else
return QString::fromStdString(body(event)).toHtmlEscaped().replace("\n", "<br>");
}
std::optional<mtx::crypto::EncryptedFile>
mtx::accessors::file(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventFile{}, event);
}
std::string
mtx::accessors::url(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventUrl{}, event);
}
std::string
mtx::accessors::thumbnail_url(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventThumbnailUrl{}, event);
}
std::string
mtx::accessors::mimetype(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventMimeType{}, event);
}
std::string
mtx::accessors::in_reply_to_event(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventInReplyTo{}, event);
}
int64_t
mtx::accessors::filesize(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventFilesize{}, event);
}
uint64_t
mtx::accessors::media_height(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventMediaHeight{}, event);
}
uint64_t
mtx::accessors::media_width(const mtx::events::collections::TimelineEvents &event)
{
return std::visit(EventMediaWidth{}, event);
}

62
src/EventAccessors.h Normal file
View File

@ -0,0 +1,62 @@
#pragma once
#include <string>
#include <QDateTime>
#include <QString>
#include <mtx/events/collections.hpp>
namespace mtx::accessors {
std::string
event_id(const mtx::events::collections::TimelineEvents &event);
std::string
room_id(const mtx::events::collections::TimelineEvents &event);
std::string
sender(const mtx::events::collections::TimelineEvents &event);
QDateTime
origin_server_ts(const mtx::events::collections::TimelineEvents &event);
std::string
filename(const mtx::events::collections::TimelineEvents &event);
mtx::events::MessageType
msg_type(const mtx::events::collections::TimelineEvents &event);
std::string
room_name(const mtx::events::collections::TimelineEvents &event);
std::string
room_topic(const mtx::events::collections::TimelineEvents &event);
std::string
body(const mtx::events::collections::TimelineEvents &event);
std::string
formatted_body(const mtx::events::collections::TimelineEvents &event);
QString
formattedBodyWithFallback(const mtx::events::collections::TimelineEvents &event);
std::optional<mtx::crypto::EncryptedFile>
file(const mtx::events::collections::TimelineEvents &event);
std::string
url(const mtx::events::collections::TimelineEvents &event);
std::string
thumbnail_url(const mtx::events::collections::TimelineEvents &event);
std::string
mimetype(const mtx::events::collections::TimelineEvents &event);
std::string
in_reply_to_event(const mtx::events::collections::TimelineEvents &event);
int64_t
filesize(const mtx::events::collections::TimelineEvents &event);
uint64_t
media_height(const mtx::events::collections::TimelineEvents &event);
uint64_t
media_width(const mtx::events::collections::TimelineEvents &event);
}

View File

@ -9,6 +9,7 @@
#include <QStandardPaths>
#include "ChatPage.h"
#include "EventAccessors.h"
#include "Logging.h"
#include "MainWindow.h"
#include "MatrixClient.h"
@ -21,364 +22,100 @@
Q_DECLARE_METATYPE(QModelIndex)
namespace {
template<class T>
QString
eventId(const mtx::events::RoomEvent<T> &event)
struct RoomEventType
{
return QString::fromStdString(event.event_id);
}
template<class T>
QString
roomId(const mtx::events::Event<T> &event)
{
return QString::fromStdString(event.room_id);
}
template<class T>
QString
senderId(const mtx::events::RoomEvent<T> &event)
{
return QString::fromStdString(event.sender);
}
template<class T>
QDateTime
eventTimestamp(const mtx::events::RoomEvent<T> &event)
{
return QDateTime::fromMSecsSinceEpoch(event.origin_server_ts);
}
template<class T>
std::string
eventMsgType(const mtx::events::Event<T> &)
{
return "";
}
template<class T>
auto
eventMsgType(const mtx::events::RoomEvent<T> &e) -> decltype(e.content.msgtype)
{
return e.content.msgtype;
}
template<class T>
QString
eventRoomName(const T &)
{
return "";
}
QString
eventRoomName(const mtx::events::StateEvent<mtx::events::state::Name> &e)
{
return QString::fromStdString(e.content.name);
}
template<class T>
QString
eventRoomTopic(const T &)
{
return "";
}
QString
eventRoomTopic(const mtx::events::StateEvent<mtx::events::state::Topic> &e)
{
return QString::fromStdString(e.content.topic);
}
template<class T>
QString
eventBody(const mtx::events::Event<T> &)
{
return QString("");
}
template<class T>
auto
eventBody(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.body), std::string>::value, QString>
{
return QString::fromStdString(e.content.body);
}
template<class T>
QString
eventFormattedBody(const mtx::events::Event<T> &)
{
return QString("");
}
template<class T>
auto
eventFormattedBody(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.formatted_body), std::string>::value, QString>
{
auto temp = e.content.formatted_body;
if (!temp.empty()) {
return QString::fromStdString(temp);
} else {
return QString::fromStdString(e.content.body).toHtmlEscaped().replace("\n", "<br>");
template<class T>
qml_mtx_events::EventType operator()(const mtx::events::Event<T> &e)
{
using mtx::events::EventType;
switch (e.type) {
case EventType::RoomKeyRequest:
return qml_mtx_events::EventType::KeyRequest;
case EventType::RoomAliases:
return qml_mtx_events::EventType::Aliases;
case EventType::RoomAvatar:
return qml_mtx_events::EventType::Avatar;
case EventType::RoomCanonicalAlias:
return qml_mtx_events::EventType::CanonicalAlias;
case EventType::RoomCreate:
return qml_mtx_events::EventType::Create;
case EventType::RoomEncrypted:
return qml_mtx_events::EventType::Encrypted;
case EventType::RoomEncryption:
return qml_mtx_events::EventType::Encryption;
case EventType::RoomGuestAccess:
return qml_mtx_events::EventType::GuestAccess;
case EventType::RoomHistoryVisibility:
return qml_mtx_events::EventType::HistoryVisibility;
case EventType::RoomJoinRules:
return qml_mtx_events::EventType::JoinRules;
case EventType::RoomMember:
return qml_mtx_events::EventType::Member;
case EventType::RoomMessage:
return qml_mtx_events::EventType::UnknownMessage;
case EventType::RoomName:
return qml_mtx_events::EventType::Name;
case EventType::RoomPowerLevels:
return qml_mtx_events::EventType::PowerLevels;
case EventType::RoomTopic:
return qml_mtx_events::EventType::Topic;
case EventType::RoomTombstone:
return qml_mtx_events::EventType::Tombstone;
case EventType::RoomRedaction:
return qml_mtx_events::EventType::Redaction;
case EventType::RoomPinnedEvents:
return qml_mtx_events::EventType::PinnedEvents;
case EventType::Sticker:
return qml_mtx_events::EventType::Sticker;
case EventType::Tag:
return qml_mtx_events::EventType::Tag;
case EventType::Unsupported:
default:
return qml_mtx_events::EventType::Unsupported;
}
}
}
template<class T>
std::optional<mtx::crypto::EncryptedFile>
eventEncryptionInfo(const mtx::events::Event<T> &)
{
return std::nullopt;
}
template<class T>
auto
eventEncryptionInfo(const mtx::events::RoomEvent<T> &e) -> std::enable_if_t<
std::is_same<decltype(e.content.file), std::optional<mtx::crypto::EncryptedFile>>::value,
std::optional<mtx::crypto::EncryptedFile>>
{
return e.content.file;
}
template<class T>
QString
eventUrl(const mtx::events::Event<T> &)
{
return "";
}
QString
eventUrl(const mtx::events::StateEvent<mtx::events::state::Avatar> &e)
{
return QString::fromStdString(e.content.url);
}
template<class T>
auto
eventUrl(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.url), std::string>::value, QString>
{
if (e.content.file)
return QString::fromStdString(e.content.file->url);
return QString::fromStdString(e.content.url);
}
template<class T>
QString
eventThumbnailUrl(const mtx::events::Event<T> &)
{
return "";
}
template<class T>
auto
eventThumbnailUrl(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.info.thumbnail_url), std::string>::value,
QString>
{
return QString::fromStdString(e.content.info.thumbnail_url);
}
template<class T>
QString
eventFilename(const mtx::events::Event<T> &)
{
return "";
}
QString
eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Audio> &e)
{
// body may be the original filename
return QString::fromStdString(e.content.body);
}
QString
eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Video> &e)
{
// body may be the original filename
return QString::fromStdString(e.content.body);
}
QString
eventFilename(const mtx::events::RoomEvent<mtx::events::msg::Image> &e)
{
// body may be the original filename
return QString::fromStdString(e.content.body);
}
QString
eventFilename(const mtx::events::RoomEvent<mtx::events::msg::File> &e)
{
// body may be the original filename
if (!e.content.filename.empty())
return QString::fromStdString(e.content.filename);
return QString::fromStdString(e.content.body);
}
template<class T>
auto
eventFilesize(const mtx::events::RoomEvent<T> &e) -> decltype(e.content.info.size)
{
return e.content.info.size;
}
template<class T>
int64_t
eventFilesize(const mtx::events::Event<T> &)
{
return 0;
}
template<class T>
QString
eventMimeType(const mtx::events::Event<T> &)
{
return QString();
}
template<class T>
auto
eventMimeType(const mtx::events::RoomEvent<T> &e)
-> std::enable_if_t<std::is_same<decltype(e.content.info.mimetype), std::string>::value, QString>
{
return QString::fromStdString(e.content.info.mimetype);
}
template<class T>
QString
eventRelatesTo(const mtx::events::Event<T> &)
{
return QString();
}
template<class T>
auto
eventRelatesTo(const mtx::events::RoomEvent<T> &e) -> std::enable_if_t<
std::is_same<decltype(e.content.relates_to.in_reply_to.event_id), std::string>::value,
QString>
{
return QString::fromStdString(e.content.relates_to.in_reply_to.event_id);
}
template<class T>
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<T> &e)
{
using mtx::events::EventType;
switch (e.type) {
case EventType::RoomKeyRequest:
return qml_mtx_events::EventType::KeyRequest;
case EventType::RoomAliases:
return qml_mtx_events::EventType::Aliases;
case EventType::RoomAvatar:
return qml_mtx_events::EventType::Avatar;
case EventType::RoomCanonicalAlias:
return qml_mtx_events::EventType::CanonicalAlias;
case EventType::RoomCreate:
return qml_mtx_events::EventType::Create;
case EventType::RoomEncrypted:
return qml_mtx_events::EventType::Encrypted;
case EventType::RoomEncryption:
return qml_mtx_events::EventType::Encryption;
case EventType::RoomGuestAccess:
return qml_mtx_events::EventType::GuestAccess;
case EventType::RoomHistoryVisibility:
return qml_mtx_events::EventType::HistoryVisibility;
case EventType::RoomJoinRules:
return qml_mtx_events::EventType::JoinRules;
case EventType::RoomMember:
return qml_mtx_events::EventType::Member;
case EventType::RoomMessage:
return qml_mtx_events::EventType::UnknownMessage;
case EventType::RoomName:
return qml_mtx_events::EventType::Name;
case EventType::RoomPowerLevels:
return qml_mtx_events::EventType::PowerLevels;
case EventType::RoomTopic:
return qml_mtx_events::EventType::Topic;
case EventType::RoomTombstone:
return qml_mtx_events::EventType::Tombstone;
case EventType::RoomRedaction:
return qml_mtx_events::EventType::Redaction;
case EventType::RoomPinnedEvents:
return qml_mtx_events::EventType::PinnedEvents;
case EventType::Sticker:
return qml_mtx_events::EventType::Sticker;
case EventType::Tag:
return qml_mtx_events::EventType::Tag;
case EventType::Unsupported:
default:
return qml_mtx_events::EventType::Unsupported;
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Audio> &)
{
return qml_mtx_events::EventType::AudioMessage;
}
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Audio> &)
{
return qml_mtx_events::EventType::AudioMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Emote> &)
{
return qml_mtx_events::EventType::EmoteMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::File> &)
{
return qml_mtx_events::EventType::FileMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Image> &)
{
return qml_mtx_events::EventType::ImageMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Notice> &)
{
return qml_mtx_events::EventType::NoticeMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Text> &)
{
return qml_mtx_events::EventType::TextMessage;
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Video> &)
{
return qml_mtx_events::EventType::VideoMessage;
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Emote> &)
{
return qml_mtx_events::EventType::EmoteMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::File> &)
{
return qml_mtx_events::EventType::FileMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Image> &)
{
return qml_mtx_events::EventType::ImageMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Notice> &)
{
return qml_mtx_events::EventType::NoticeMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Text> &)
{
return qml_mtx_events::EventType::TextMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Video> &)
{
return qml_mtx_events::EventType::VideoMessage;
}
qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Redacted> &)
{
return qml_mtx_events::EventType::Redacted;
}
// ::EventType::Type operator()(const Event<mtx::events::msg::Location> &e) { return
// ::EventType::LocationMessage; }
};
}
qml_mtx_events::EventType
toRoomEventType(const mtx::events::Event<mtx::events::msg::Redacted> &)
toRoomEventType(const mtx::events::collections::TimelineEvents &event)
{
return qml_mtx_events::EventType::Redacted;
}
// ::EventType::Type toRoomEventType(const Event<mtx::events::msg::Location> &e) { return
// ::EventType::LocationMessage; }
template<class T>
uint64_t
eventHeight(const mtx::events::Event<T> &)
{
return -1;
}
template<class T>
auto
eventHeight(const mtx::events::RoomEvent<T> &e) -> decltype(e.content.info.h)
{
return e.content.info.h;
}
template<class T>
uint64_t
eventWidth(const mtx::events::Event<T> &)
{
return -1;
}
template<class T>
auto
eventWidth(const mtx::events::RoomEvent<T> &e) -> decltype(e.content.info.w)
{
return e.content.info.w;
}
template<class T>
double
eventPropHeight(const mtx::events::RoomEvent<T> &e)
{
auto w = eventWidth(e);
if (w == 0)
w = 1;
double prop = eventHeight(e) / (double)w;
return prop > 0 ? prop : 1.;
}
return std::visit(RoomEventType{}, event);
}
TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObject *parent)
@ -477,6 +214,8 @@ TimelineModel::rowCount(const QModelIndex &parent) const
QVariant
TimelineModel::data(const QModelIndex &index, int role) const
{
using namespace mtx::accessors;
namespace acc = mtx::accessors;
if (index.row() < 0 && index.row() >= (int)eventOrder.size())
return QVariant();
@ -491,86 +230,71 @@ TimelineModel::data(const QModelIndex &index, int role) const
switch (role) {
case Section: {
QDateTime date =
std::visit([](const auto &e) -> QDateTime { return eventTimestamp(e); }, event);
QDateTime date = origin_server_ts(event);
date.setTime(QTime());
QString userId =
std::visit([](const auto &e) -> QString { return senderId(e); }, event);
std::string userId = acc::sender(event);
for (int r = index.row() - 1; r > 0; r--) {
auto tempEv = events.value(eventOrder[r]);
QDateTime prevDate = std::visit(
[](const auto &e) -> QDateTime { return eventTimestamp(e); }, tempEv);
QDateTime prevDate = origin_server_ts(tempEv);
prevDate.setTime(QTime());
if (prevDate != date)
return QString("%2 %1").arg(date.toMSecsSinceEpoch()).arg(userId);
return QString("%2 %1")
.arg(date.toMSecsSinceEpoch())
.arg(QString::fromStdString(userId));
QString prevUserId =
std::visit([](const auto &e) -> QString { return senderId(e); }, tempEv);
std::string prevUserId = acc::sender(tempEv);
if (userId != prevUserId)
break;
}
return QString("%1").arg(userId);
return QString("%1").arg(QString::fromStdString(userId));
}
case UserId:
return QVariant(
std::visit([](const auto &e) -> QString { return senderId(e); }, event));
return QVariant(QString::fromStdString(acc::sender(event)));
case UserName:
return QVariant(displayName(
std::visit([](const auto &e) -> QString { return senderId(e); }, event)));
return QVariant(displayName(QString::fromStdString(acc::sender(event))));
case Timestamp:
return QVariant(
std::visit([](const auto &e) -> QDateTime { return eventTimestamp(e); }, event));
return QVariant(origin_server_ts(event));
case Type:
return QVariant(std::visit(
[](const auto &e) -> qml_mtx_events::EventType { return toRoomEventType(e); },
event));
return QVariant(toRoomEventType(event));
case Body:
return QVariant(utils::replaceEmoji(
std::visit([](const auto &e) -> QString { return eventBody(e); }, event)));
return QVariant(utils::replaceEmoji(QString::fromStdString(body(event))));
case FormattedBody:
return QVariant(
utils::replaceEmoji(
utils::linkifyMessage(std::visit(
[](const auto &e) -> QString { return eventFormattedBody(e); }, event)))
utils::replaceEmoji(utils::linkifyMessage(formattedBodyWithFallback(event)))
.remove("<mx-reply>")
.remove("</mx-reply>"));
case Url:
return QVariant(
std::visit([](const auto &e) -> QString { return eventUrl(e); }, event));
return QVariant(QString::fromStdString(url(event)));
case ThumbnailUrl:
return QVariant(
std::visit([](const auto &e) -> QString { return eventThumbnailUrl(e); }, event));
return QVariant(QString::fromStdString(thumbnail_url(event)));
case Filename:
return QVariant(
std::visit([](const auto &e) -> QString { return eventFilename(e); }, event));
return QVariant(QString::fromStdString(filename(event)));
case Filesize:
return QVariant(std::visit(
[](const auto &e) -> QString {
return utils::humanReadableFileSize(eventFilesize(e));
},
event));
return QVariant(utils::humanReadableFileSize(filesize(event)));
case MimeType:
return QVariant(
std::visit([](const auto &e) -> QString { return eventMimeType(e); }, event));
return QVariant(QString::fromStdString(mimetype(event)));
case Height:
return QVariant(
std::visit([](const auto &e) -> qulonglong { return eventHeight(e); }, event));
return QVariant(qulonglong{media_height(event)});
case Width:
return QVariant(
std::visit([](const auto &e) -> qulonglong { return eventWidth(e); }, event));
case ProportionalHeight:
return QVariant(
std::visit([](const auto &e) -> double { return eventPropHeight(e); }, event));
return QVariant(qulonglong{media_width(event)});
case ProportionalHeight: {
auto w = media_width(event);
if (w == 0)
w = 1;
double prop = media_height(event) / (double)w;
return QVariant(prop > 0 ? prop : 1.);
}
case Id:
return id;
case State:
// only show read receipts for messages not from us
if (std::visit([](const auto &e) -> QString { return senderId(e); }, event)
.toStdString() != http::client()->user_id().to_string())
if (acc::sender(event) != http::client()->user_id().to_string())
return qml_mtx_events::Empty;
else if (failed.contains(id))
return qml_mtx_events::Failed;
@ -581,21 +305,15 @@ TimelineModel::data(const QModelIndex &index, int role) const
else
return qml_mtx_events::Received;
case IsEncrypted: {
auto tempEvent = events[id];
return std::holds_alternative<
mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(tempEvent);
}
case ReplyTo: {
QString evId =
std::visit([](const auto &e) -> QString { return eventRelatesTo(e); }, event);
return QVariant(evId);
mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(events[id]);
}
case ReplyTo:
return QVariant(QString::fromStdString(in_reply_to_event(event)));
case RoomName:
return QVariant(
std::visit([](const auto &e) -> QString { return eventRoomName(e); }, event));
return QVariant(QString::fromStdString(room_name(event)));
case RoomTopic:
return QVariant(
std::visit([](const auto &e) -> QString { return eventRoomTopic(e); }, event));
return QVariant(QString::fromStdString(room_topic(event)));
default:
return QVariant();
}
@ -667,7 +385,7 @@ TimelineModel::internalAddEvents(
{
std::vector<QString> ids;
for (auto e : timeline) {
QString id = std::visit([](const auto &e) -> QString { return eventId(e); }, e);
QString id = QString::fromStdString(mtx::accessors::event_id(e));
if (this->events.contains(id)) {
this->events.insert(id, e);
@ -708,11 +426,7 @@ TimelineModel::internalAddEvents(
std::get_if<mtx::events::EncryptedEvent<mtx::events::msg::Encrypted>>(&e)) {
e = decryptEvent(*event).event;
}
auto encInfo = std::visit(
[](const auto &ev) -> std::optional<mtx::crypto::EncryptedFile> {
return eventEncryptionInfo(ev);
},
e);
auto encInfo = mtx::accessors::file(e);
if (encInfo)
emit newEncryptedImage(encInfo.value());
@ -950,25 +664,18 @@ TimelineModel::replyAction(QString id)
event = decryptEvent(*e).event;
}
RelatedInfo related = std::visit(
[](const auto &ev) -> RelatedInfo {
RelatedInfo related_ = {};
related_.quoted_user = QString::fromStdString(ev.sender);
related_.related_event = ev.event_id;
return related_;
},
event);
related.type = mtx::events::getMessageType(
std::visit([](const auto &e) -> std::string { return eventMsgType(e); }, event));
related.quoted_body =
std::visit([](const auto &e) -> QString { return eventFormattedBody(e); }, event);
RelatedInfo related = {};
related.quoted_user = QString::fromStdString(mtx::accessors::sender(event));
related.related_event = mtx::accessors::event_id(event);
related.type = mtx::accessors::msg_type(event);
related.quoted_body = mtx::accessors::formattedBodyWithFallback(event);
related.quoted_body.remove(QRegularExpression(
"<mx-reply>.*</mx-reply>", QRegularExpression::DotMatchesEverythingOption));
nhlog::ui()->debug("after replacement: {}", related.quoted_body.toStdString());
related.room = room_id_;
if (related.quoted_body.isEmpty())
return;
// if (related.quoted_body.isEmpty())
// return;
ChatPage::instance()->messageReply(related);
}
@ -1412,8 +1119,7 @@ TimelineModel::addPendingMessage(mtx::events::collections::TimelineEvents event)
internalAddEvents({event});
QString txn_id_qstr =
std::visit([](const auto &e) -> QString { return eventId(e); }, event);
QString txn_id_qstr = QString::fromStdString(mtx::accessors::event_id(event));
beginInsertRows(QModelIndex(),
static_cast<int>(this->eventOrder.size()),
static_cast<int>(this->eventOrder.size()));
@ -1436,18 +1142,13 @@ TimelineModel::saveMedia(QString eventId) const
event = decryptEvent(*e).event;
}
QString mxcUrl = std::visit([](const auto &e) -> QString { return eventUrl(e); }, event);
QString originalFilename =
std::visit([](const auto &e) -> QString { return eventFilename(e); }, event);
QString mimeType =
std::visit([](const auto &e) -> QString { return eventMimeType(e); }, event);
QString mxcUrl = QString::fromStdString(mtx::accessors::url(event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(event));
QString mimeType = QString::fromStdString(mtx::accessors::mimetype(event));
using EncF = std::optional<mtx::crypto::EncryptedFile>;
EncF encryptionInfo =
std::visit([](const auto &e) -> EncF { return eventEncryptionInfo(e); }, event);
auto encryptionInfo = mtx::accessors::file(event);
qml_mtx_events::EventType eventType = std::visit(
[](const auto &e) -> qml_mtx_events::EventType { return toRoomEventType(e); }, event);
qml_mtx_events::EventType eventType = toRoomEventType(event);
QString dialogTitle;
if (eventType == qml_mtx_events::EventType::ImageMessage) {
@ -1513,13 +1214,11 @@ TimelineModel::cacheMedia(QString eventId)
event = decryptEvent(*e).event;
}
QString mxcUrl = std::visit([](const auto &e) -> QString { return eventUrl(e); }, event);
QString mimeType =
std::visit([](const auto &e) -> QString { return eventMimeType(e); }, event);
QString mxcUrl = QString::fromStdString(mtx::accessors::url(event));
QString originalFilename = QString::fromStdString(mtx::accessors::filename(event));
QString mimeType = QString::fromStdString(mtx::accessors::mimetype(event));
using EncF = std::optional<mtx::crypto::EncryptedFile>;
EncF encryptionInfo =
std::visit([](const auto &e) -> EncF { return eventEncryptionInfo(e); }, event);
auto encryptionInfo = mtx::accessors::file(event);
// If the message is a link to a non mxcUrl, don't download it
if (!mxcUrl.startsWith("mxc://")) {