diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c68d614..7871bb6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/EventAccessors.cpp b/src/EventAccessors.cpp new file mode 100644 index 00000000..6264af58 --- /dev/null +++ b/src/EventAccessors.cpp @@ -0,0 +1,363 @@ +#include "EventAccessors.h" + +#include + +namespace { +struct nonesuch +{ + ~nonesuch() = delete; + nonesuch(nonesuch const &) = delete; + void operator=(nonesuch const &) = delete; +}; + +namespace detail { +template class Op, class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +} // namespace detail + +template class Op, class... Args> +using is_detected = typename detail::detector::value_t; + +struct EventMsgType +{ + template + using msgtype_t = decltype(E::msgtype); + template + mtx::events::MessageType operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) + return mtx::events::getMessageType(e.content.msgtype); + return mtx::events::MessageType::Unknown; + } +}; + +struct EventRoomName +{ + template + std::string operator()(const T &e) + { + if constexpr (std::is_same_v, T>) + return e.content.name; + return ""; + } +}; + +struct EventRoomTopic +{ + template + std::string operator()(const T &e) + { + if constexpr (std::is_same_v, T>) + return e.content.topic; + return ""; + } +}; + +struct EventBody +{ + template + using body_t = decltype(C::body); + template + std::string operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) + return e.content.body; + return ""; + } +}; + +struct EventFormattedBody +{ + template + using formatted_body_t = decltype(C::formatted_body); + template + std::string operator()(const mtx::events::RoomEvent &e) + { + if constexpr (is_detected::value) + return e.content.formatted_body; + return ""; + } +}; + +struct EventFile +{ + template + using file_t = decltype(Content::file); + template + std::optional operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) + return e.content.file; + return std::nullopt; + } +}; + +struct EventUrl +{ + template + using url_t = decltype(Content::url); + template + std::string operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + if (auto file = EventFile{}(e)) + return file->url; + return e.content.url; + } + return ""; + } +}; + +struct EventThumbnailUrl +{ + template + using thumbnail_url_t = decltype(Content::info.thumbnail_url); + template + std::string operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + return e.content.info.thumbnail_url; + } + return ""; + } +}; + +struct EventFilename +{ + template + std::string operator()(const mtx::events::Event &) + { + return ""; + } + std::string operator()(const mtx::events::RoomEvent &e) + { + // body may be the original filename + return e.content.body; + } + std::string operator()(const mtx::events::RoomEvent &e) + { + // body may be the original filename + return e.content.body; + } + std::string operator()(const mtx::events::RoomEvent &e) + { + // body may be the original filename + return e.content.body; + } + std::string operator()(const mtx::events::RoomEvent &e) + { + // body may be the original filename + if (!e.content.filename.empty()) + return e.content.filename; + return e.content.body; + } +}; + +struct EventMimeType +{ + template + using mimetype_t = decltype(Content::info.mimetype); + template + std::string operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + return e.content.info.mimetype; + } + return ""; + } +}; + +struct EventFilesize +{ + template + using filesize_t = decltype(Content::info.size); + template + int64_t operator()(const mtx::events::RoomEvent &e) + { + if constexpr (is_detected::value) { + return e.content.info.size; + } + return 0; + } +}; + +struct EventInReplyTo +{ + template + using related_ev_id_t = decltype(Content::relates_to.in_reply_to.event_id); + template + std::string operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + return e.content.relates_to.in_reply_to.event_id; + } + return ""; + } +}; + +struct EventMediaHeight +{ + template + using h_t = decltype(Content::info.h); + template + uint64_t operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + return e.content.info.h; + } + return -1; + } +}; + +struct EventMediaWidth +{ + template + using w_t = decltype(Content::info.w); + template + uint64_t operator()(const mtx::events::Event &e) + { + if constexpr (is_detected::value) { + return e.content.info.w; + } + return -1; + } +}; + +template +double +eventPropHeight(const mtx::events::RoomEvent &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", "
"); +} + +std::optional +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); +} diff --git a/src/EventAccessors.h b/src/EventAccessors.h new file mode 100644 index 00000000..5c03861d --- /dev/null +++ b/src/EventAccessors.h @@ -0,0 +1,62 @@ +#pragma once + +#include + +#include +#include + +#include + +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 +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); +} diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index ce238d94..593a21df 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -9,6 +9,7 @@ #include #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 -QString -eventId(const mtx::events::RoomEvent &event) +struct RoomEventType { - return QString::fromStdString(event.event_id); -} -template -QString -roomId(const mtx::events::Event &event) -{ - return QString::fromStdString(event.room_id); -} -template -QString -senderId(const mtx::events::RoomEvent &event) -{ - return QString::fromStdString(event.sender); -} - -template -QDateTime -eventTimestamp(const mtx::events::RoomEvent &event) -{ - return QDateTime::fromMSecsSinceEpoch(event.origin_server_ts); -} - -template -std::string -eventMsgType(const mtx::events::Event &) -{ - return ""; -} -template -auto -eventMsgType(const mtx::events::RoomEvent &e) -> decltype(e.content.msgtype) -{ - return e.content.msgtype; -} - -template -QString -eventRoomName(const T &) -{ - return ""; -} -QString -eventRoomName(const mtx::events::StateEvent &e) -{ - return QString::fromStdString(e.content.name); -} - -template -QString -eventRoomTopic(const T &) -{ - return ""; -} -QString -eventRoomTopic(const mtx::events::StateEvent &e) -{ - return QString::fromStdString(e.content.topic); -} - -template -QString -eventBody(const mtx::events::Event &) -{ - return QString(""); -} -template -auto -eventBody(const mtx::events::RoomEvent &e) - -> std::enable_if_t::value, QString> -{ - return QString::fromStdString(e.content.body); -} - -template -QString -eventFormattedBody(const mtx::events::Event &) -{ - return QString(""); -} -template -auto -eventFormattedBody(const mtx::events::RoomEvent &e) - -> std::enable_if_t::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", "
"); + template + qml_mtx_events::EventType operator()(const mtx::events::Event &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 -std::optional -eventEncryptionInfo(const mtx::events::Event &) -{ - return std::nullopt; -} - -template -auto -eventEncryptionInfo(const mtx::events::RoomEvent &e) -> std::enable_if_t< - std::is_same>::value, - std::optional> -{ - return e.content.file; -} - -template -QString -eventUrl(const mtx::events::Event &) -{ - return ""; -} - -QString -eventUrl(const mtx::events::StateEvent &e) -{ - return QString::fromStdString(e.content.url); -} - -template -auto -eventUrl(const mtx::events::RoomEvent &e) - -> std::enable_if_t::value, QString> -{ - if (e.content.file) - return QString::fromStdString(e.content.file->url); - return QString::fromStdString(e.content.url); -} - -template -QString -eventThumbnailUrl(const mtx::events::Event &) -{ - return ""; -} -template -auto -eventThumbnailUrl(const mtx::events::RoomEvent &e) - -> std::enable_if_t::value, - QString> -{ - return QString::fromStdString(e.content.info.thumbnail_url); -} - -template -QString -eventFilename(const mtx::events::Event &) -{ - return ""; -} -QString -eventFilename(const mtx::events::RoomEvent &e) -{ - // body may be the original filename - return QString::fromStdString(e.content.body); -} -QString -eventFilename(const mtx::events::RoomEvent &e) -{ - // body may be the original filename - return QString::fromStdString(e.content.body); -} -QString -eventFilename(const mtx::events::RoomEvent &e) -{ - // body may be the original filename - return QString::fromStdString(e.content.body); -} -QString -eventFilename(const mtx::events::RoomEvent &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 -auto -eventFilesize(const mtx::events::RoomEvent &e) -> decltype(e.content.info.size) -{ - return e.content.info.size; -} - -template -int64_t -eventFilesize(const mtx::events::Event &) -{ - return 0; -} - -template -QString -eventMimeType(const mtx::events::Event &) -{ - return QString(); -} -template -auto -eventMimeType(const mtx::events::RoomEvent &e) - -> std::enable_if_t::value, QString> -{ - return QString::fromStdString(e.content.info.mimetype); -} - -template -QString -eventRelatesTo(const mtx::events::Event &) -{ - return QString(); -} -template -auto -eventRelatesTo(const mtx::events::RoomEvent &e) -> std::enable_if_t< - std::is_same::value, - QString> -{ - return QString::fromStdString(e.content.relates_to.in_reply_to.event_id); -} - -template -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &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 &) + { + return qml_mtx_events::EventType::AudioMessage; } -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::AudioMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::EmoteMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::FileMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::ImageMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::NoticeMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::TextMessage; -} -qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) -{ - return qml_mtx_events::EventType::VideoMessage; + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::EmoteMessage; + } + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::FileMessage; + } + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::ImageMessage; + } + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::NoticeMessage; + } + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::TextMessage; + } + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::VideoMessage; + } + + qml_mtx_events::EventType operator()(const mtx::events::Event &) + { + return qml_mtx_events::EventType::Redacted; + } + // ::EventType::Type operator()(const Event &e) { return + // ::EventType::LocationMessage; } +}; } qml_mtx_events::EventType -toRoomEventType(const mtx::events::Event &) +toRoomEventType(const mtx::events::collections::TimelineEvents &event) { - return qml_mtx_events::EventType::Redacted; -} -// ::EventType::Type toRoomEventType(const Event &e) { return -// ::EventType::LocationMessage; } - -template -uint64_t -eventHeight(const mtx::events::Event &) -{ - return -1; -} -template -auto -eventHeight(const mtx::events::RoomEvent &e) -> decltype(e.content.info.h) -{ - return e.content.info.h; -} -template -uint64_t -eventWidth(const mtx::events::Event &) -{ - return -1; -} -template -auto -eventWidth(const mtx::events::RoomEvent &e) -> decltype(e.content.info.w) -{ - return e.content.info.w; -} - -template -double -eventPropHeight(const mtx::events::RoomEvent &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("") .remove("")); 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>(tempEvent); - } - case ReplyTo: { - QString evId = - std::visit([](const auto &e) -> QString { return eventRelatesTo(e); }, event); - return QVariant(evId); + mtx::events::EncryptedEvent>(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 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>(&e)) { e = decryptEvent(*event).event; } - auto encInfo = std::visit( - [](const auto &ev) -> std::optional { - 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( ".*", 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(this->eventOrder.size()), static_cast(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; - 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; - 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://")) {