Port state events and images

This commit is contained in:
Nicolas Werner 2023-07-08 19:22:50 +02:00
parent 76b40f452b
commit eab8731f5b
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
7 changed files with 232 additions and 102 deletions

View File

@ -191,13 +191,19 @@ Item {
roleValues: [ roleValues: [
MtxEvent.TextMessage, MtxEvent.TextMessage,
MtxEvent.NoticeMessage, MtxEvent.NoticeMessage,
MtxEvent.ElementEffectMessage,
MtxEvent.UnknownMessage,
] ]
TextMessage { TextMessage {
id: textMes
keepFullText: true keepFullText: true
required property string userId required property string userId
required property string userName required property string userName
required property string formattedBody
required property int type
color: type == MtxEvent.NoticeMessage ? palette.buttonText : palette.text
font.italic: type == MtxEvent.NoticeMessage
formatted: formattedBody
Layout.fillWidth: true Layout.fillWidth: true
//Layout.maximumWidth: implicitWidth //Layout.maximumWidth: implicitWidth
@ -205,6 +211,80 @@ Item {
} }
} }
EventDelegateChoice {
roleValues: [
MtxEvent.EmoteMessage,
]
TextMessage {
keepFullText: true
required property string userId
required property string userName
required property string formattedBody
formatted: TimelineManager.escapeEmoji(userName) + " " + formattedBody
color: TimelineManager.userColor(userId, palette.base)
font.italic: true
Layout.fillWidth: true
//Layout.maximumWidth: implicitWidth
}
}
EventDelegateChoice {
roleValues: [
MtxEvent.CanonicalAlias,
MtxEvent.ServerAcl,
MtxEvent.Name,
MtxEvent.Topic,
MtxEvent.Avatar,
MtxEvent.PinnedEvents,
MtxEvent.ImagePackInRoom,
MtxEvent.SpaceParent,
MtxEvent.RoomCreate,
MtxEvent.PowerLevels,
MtxEvent.PolicyRuleUser,
MtxEvent.PolicyRuleRoom,
MtxEvent.PolicyRuleServer,
MtxEvent.RoomJoinRules,
MtxEvent.RoomHistoryVisibility,
MtxEvent.RoomGuestAccess,
]
TextMessage {
keepFullText: true
required property string userId
required property string userName
required property string formattedStateEvent
isOnlyEmoji: false
text: formattedStateEvent
formatted: ''
body: ''
color: palette.buttonText
font.italic: true
Layout.fillWidth: true
//Layout.maximumWidth: implicitWidth
}
}
EventDelegateChoice {
roleValues: [
MtxEvent.ImageMessage,
MtxEvent.Sticker,
]
ImageMessage {
Layout.fillWidth: true
containerHeight: timelineView.height
Layout.maximumWidth: tempWidth
}
}
EventDelegateChoice { EventDelegateChoice {
roleValues: [ roleValues: [
] ]

View File

@ -2,10 +2,11 @@
// //
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick 2.15 import QtQuick
import QtQuick.Window 2.15 import QtQuick.Window
import QtQuick.Controls 2.3 import QtQuick.Controls
import im.nheko 1.0 import QtQuick.Layouts
import im.nheko
AbstractButton { AbstractButton {
required property int type required property int type
@ -17,13 +18,13 @@ AbstractButton {
required property string filename required property string filename
required property bool isReply required property bool isReply
required property string eventId required property string eventId
required property int containerHeight
property double divisor: isReply ? 5 : 3 property double divisor: isReply ? 5 : 3
property int tempWidth: originalWidth < 1? 400: originalWidth property int tempWidth: originalWidth < 1? 400: originalWidth
implicitWidth: Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1)) Layout.preferredWidth: Math.round(tempWidth*Math.min((containerHeight/divisor)/(tempWidth*proportionalHeight), 1))
width: Math.min(parent?.width ?? 2000,implicitWidth) Layout.preferredHeight: width*proportionalHeight
height: width*proportionalHeight
hoverEnabled: true hoverEnabled: true
state: (img.status != Image.Ready || timeline.privacyScreen.active) ? "BlurhashVisible" : "ImageVisible" state: (img.status != Image.Ready || timeline.privacyScreen.active) ? "BlurhashVisible" : "ImageVisible"

View File

@ -175,6 +175,7 @@ Item {
isReply: d.isReply isReply: d.isReply
eventId: d.eventId eventId: d.eventId
metadataWidth: d.metadataWidth metadataWidth: d.metadataWidth
containerHeight: timelineView.height
} }
} }
@ -193,6 +194,7 @@ Item {
isReply: d.isReply isReply: d.isReply
eventId: d.eventId eventId: d.eventId
metadataWidth: d.metadataWidth metadataWidth: d.metadataWidth
containerHeight: timelineView.height
} }
} }

View File

@ -12,7 +12,7 @@ MatrixText {
required property bool isOnlyEmoji required property bool isOnlyEmoji
required property bool isReply required property bool isReply
required property bool keepFullText required property bool keepFullText
required property string formattedBody required property string formatted
property string copyText: selectedText ? getText(selectionStart, selectionEnd) : body property string copyText: selectedText ? getText(selectionStart, selectionEnd) : body
property int metadataWidth: 100 property int metadataWidth: 100
@ -40,7 +40,7 @@ MatrixText {
background-color: " + palette.text + "; background-color: " + palette.text + ";
}" : "") + // TODO(Nico): Figure out how to support mobile }" : "") + // TODO(Nico): Figure out how to support mobile
"</style> "</style>
" + formattedBody.replace(/<del>/g, "<s>").replace(/<\/del>/g, "</s>").replace(/<strike>/g, "<s>").replace(/<\/strike>/g, "</s>") " + formatted.replace(/<del>/g, "<s>").replace(/<\/del>/g, "</s>").replace(/<strike>/g, "<s>").replace(/<\/strike>/g, "</s>")
Layout.maximumHeight: !keepFullText ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : implicitHeight Layout.maximumHeight: !keepFullText ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : implicitHeight
clip: !keepFullText clip: !keepFullText
selectByMouse: !Settings.mobileMode && !isReply selectByMouse: !Settings.mobileMode && !isReply

View File

@ -843,8 +843,8 @@ EventStore::get(const std::string &id,
nhlog::net()->error( nhlog::net()->error(
"Failed to retrieve event with id {}, which was " "Failed to retrieve event with id {}, which was "
"requested to show the replyTo for event {}", "requested to show the replyTo for event {}",
relatedTo, id,
id); relatedTo);
return; return;
} }
emit eventFetched(id, relatedTo, timeline); emit eventFetched(id, relatedTo, timeline);

View File

@ -532,6 +532,7 @@ TimelineModel::roleNames() const
{IsOnlyEmoji, "isOnlyEmoji"}, {IsOnlyEmoji, "isOnlyEmoji"},
{Body, "body"}, {Body, "body"},
{FormattedBody, "formattedBody"}, {FormattedBody, "formattedBody"},
{FormattedStateEvent, "formattedStateEvent"},
{IsSender, "isSender"}, {IsSender, "isSender"},
{UserId, "userId"}, {UserId, "userId"},
{UserName, "userName"}, {UserName, "userName"},
@ -694,6 +695,76 @@ TimelineModel::data(const mtx::events::collections::TimelineEvents &event, int r
return QVariant(utils::replaceEmoji(utils::linkifyMessage(formattedBody_))); return QVariant(utils::replaceEmoji(utils::linkifyMessage(formattedBody_)));
} }
case FormattedStateEvent: {
if (mtx::accessors::is_state_event(event)) {
return std::visit(
[this](const auto &e) {
constexpr auto t = mtx::events::state_content_to_type<decltype(e.content)>;
if constexpr (t == mtx::events::EventType::RoomServerAcl)
return tr("%1 changed which servers are allowed in this room.")
.arg(displayName(QString::fromStdString(e.sender)));
else if constexpr (t == mtx::events::EventType::RoomName) {
if (e.content.name.empty())
return tr("%1 removed the room name.")
.arg(displayName(QString::fromStdString(e.sender)));
else
return tr("%1 changed the room name to: %2")
.arg(displayName(QString::fromStdString(e.sender)))
.arg(QString::fromStdString(e.content.name).toHtmlEscaped());
} else if constexpr (t == mtx::events::EventType::RoomTopic) {
if (e.content.topic.empty())
return tr("%1 removed the topic.")
.arg(displayName(QString::fromStdString(e.sender)));
else
return tr("%1 changed the topic to: %2")
.arg(displayName(QString::fromStdString(e.sender)))
.arg(QString::fromStdString(e.content.topic).toHtmlEscaped());
} else if constexpr (t == mtx::events::EventType::RoomAvatar) {
if (e.content.url.starts_with("mxc://"))
return tr("%1 changed the room avatar to: %2")
.arg(displayName(QString::fromStdString(e.sender)))
.arg(QStringLiteral("<img height=\"32\" src=\"%1\">")
.arg(QUrl::toPercentEncoding(
QString::fromStdString(e.content.url))));
else
return tr("%1 removed the room avatar.")
.arg(displayName(QString::fromStdString(e.sender)));
} else if constexpr (t == mtx::events::EventType::RoomPinnedEvents)
return tr("%1 changed the pinned messages.")
.arg(displayName(QString::fromStdString(e.sender)));
else if constexpr (t == mtx::events::EventType::ImagePackInRoom)
formatImagePackEvent(e);
else if constexpr (t == mtx::events::EventType::RoomCanonicalAlias)
return tr("%1 changed the addresses for this room.")
.arg(displayName(QString::fromStdString(e.sender)));
else if constexpr (t == mtx::events::EventType::SpaceParent)
return tr("%1 changed the parent communities for this room.")
.arg(displayName(QString::fromStdString(e.sender)));
else if constexpr (t == mtx::events::EventType::RoomCreate)
return tr("%1 created and configured room: %2")
.arg(displayName(QString::fromStdString(e.sender)))
.arg(room_id_);
else if constexpr (t == mtx::events::EventType::RoomPowerLevels)
return formatPowerLevelEvent(e);
else if constexpr (t == mtx::events::EventType::PolicyRuleRoom)
return formatPolicyRule(QString::fromStdString(e.event_id));
else if constexpr (t == mtx::events::EventType::PolicyRuleUser)
return formatPolicyRule(QString::fromStdString(e.event_id));
else if constexpr (t == mtx::events::EventType::PolicyRuleServer)
return formatPolicyRule(QString::fromStdString(e.event_id));
else if constexpr (t == mtx::events::EventType::RoomHistoryVisibility)
return formatHistoryVisibilityEvent(e);
else if constexpr (t == mtx::events::EventType::RoomGuestAccess)
return formatGuestAccessEvent(e);
return tr("%1 changed unknown state event %2.")
.arg(displayName(QString::fromStdString(e.sender)))
.arg(QString::fromStdString(to_string(e.type)));
},
event);
}
return QString();
}
case Url: case Url:
return QVariant(QString::fromStdString(url(event))); return QVariant(QString::fromStdString(url(event)));
case ThumbnailUrl: case ThumbnailUrl:
@ -2308,20 +2379,13 @@ TimelineModel::formatJoinRuleEvent(const QString &id)
} }
QString QString
TimelineModel::formatGuestAccessEvent(const QString &id) TimelineModel::formatGuestAccessEvent(
const mtx::events::StateEvent<mtx::events::state::GuestAccess> &event) const
{ {
auto e = events.get(id.toStdString(), ""); QString user = QString::fromStdString(event.sender);
if (!e)
return {};
auto event = std::get_if<mtx::events::StateEvent<mtx::events::state::GuestAccess>>(e);
if (!event)
return {};
QString user = QString::fromStdString(event->sender);
QString name = utils::replaceEmoji(displayName(user)); QString name = utils::replaceEmoji(displayName(user));
switch (event->content.guest_access) { switch (event.content.guest_access) {
case mtx::events::state::AccessState::CanJoin: case mtx::events::state::AccessState::CanJoin:
return tr("%1 made the room open to guests.").arg(name); return tr("%1 made the room open to guests.").arg(name);
case mtx::events::state::AccessState::Forbidden: case mtx::events::state::AccessState::Forbidden:
@ -2332,21 +2396,13 @@ TimelineModel::formatGuestAccessEvent(const QString &id)
} }
QString QString
TimelineModel::formatHistoryVisibilityEvent(const QString &id) TimelineModel::formatHistoryVisibilityEvent(
const mtx::events::StateEvent<mtx::events::state::HistoryVisibility> &event) const
{ {
auto e = events.get(id.toStdString(), ""); QString user = QString::fromStdString(event.sender);
if (!e)
return {};
auto event = std::get_if<mtx::events::StateEvent<mtx::events::state::HistoryVisibility>>(e);
if (!event)
return {};
QString user = QString::fromStdString(event->sender);
QString name = utils::replaceEmoji(displayName(user)); QString name = utils::replaceEmoji(displayName(user));
switch (event->content.history_visibility) { switch (event.content.history_visibility) {
case mtx::events::state::Visibility::WorldReadable: case mtx::events::state::Visibility::WorldReadable:
return tr("%1 made the room history world readable. Events may be now read by " return tr("%1 made the room history world readable. Events may be now read by "
"non-joined people.") "non-joined people.")
@ -2364,32 +2420,25 @@ TimelineModel::formatHistoryVisibilityEvent(const QString &id)
} }
QString QString
TimelineModel::formatPowerLevelEvent(const QString &id) TimelineModel::formatPowerLevelEvent(
const mtx::events::StateEvent<mtx::events::state::PowerLevels> &event) const
{ {
auto e = events.get(id.toStdString(), "");
if (!e)
return {};
auto event = std::get_if<mtx::events::StateEvent<mtx::events::state::PowerLevels>>(e);
if (!event)
return QString();
mtx::events::StateEvent<mtx::events::state::PowerLevels> const *prevEvent = nullptr; mtx::events::StateEvent<mtx::events::state::PowerLevels> const *prevEvent = nullptr;
if (!event->unsigned_data.replaces_state.empty()) { if (!event.unsigned_data.replaces_state.empty()) {
auto tempPrevEvent = events.get(event->unsigned_data.replaces_state, event->event_id); auto tempPrevEvent = events.get(event.unsigned_data.replaces_state, event.event_id);
if (tempPrevEvent) { if (tempPrevEvent) {
prevEvent = prevEvent =
std::get_if<mtx::events::StateEvent<mtx::events::state::PowerLevels>>(tempPrevEvent); std::get_if<mtx::events::StateEvent<mtx::events::state::PowerLevels>>(tempPrevEvent);
} }
} }
QString user = QString::fromStdString(event->sender); QString user = QString::fromStdString(event.sender);
QString sender_name = utils::replaceEmoji(displayName(user)); QString sender_name = utils::replaceEmoji(displayName(user));
// Get the rooms levels for redactions and powerlevel changes to determine "Administrator" and // Get the rooms levels for redactions and powerlevel changes to determine "Administrator" and
// "Moderator" powerlevels. // "Moderator" powerlevels.
auto administrator_power_level = event->content.state_level("m.room.power_levels"); auto administrator_power_level = event.content.state_level("m.room.power_levels");
auto moderator_power_level = event->content.redact; auto moderator_power_level = event.content.redact;
auto default_powerlevel = event->content.users_default; auto default_powerlevel = event.content.users_default;
if (!prevEvent) if (!prevEvent)
return tr("%1 has changed the room's permissions.").arg(sender_name); return tr("%1 has changed the room's permissions.").arg(sender_name);
@ -2399,7 +2448,7 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
auto numberOfAffected = 0; auto numberOfAffected = 0;
// We do only compare to people with explicit PL. Usually others are not going to be // We do only compare to people with explicit PL. Usually others are not going to be
// affected either way and this is cheaper to iterate over. // affected either way and this is cheaper to iterate over.
for (auto const &[mxid, currentPowerlevel] : event->content.users) { for (auto const &[mxid, currentPowerlevel] : event.content.users) {
if (currentPowerlevel == newPowerlevelSetting && if (currentPowerlevel == newPowerlevelSetting &&
prevEvent->content.user_level(mxid) < newPowerlevelSetting) { prevEvent->content.user_level(mxid) < newPowerlevelSetting) {
numberOfAffected++; numberOfAffected++;
@ -2413,16 +2462,16 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
QStringList resultingMessage{}; QStringList resultingMessage{};
// These affect only a few people. Therefor we can print who is affected. // These affect only a few people. Therefor we can print who is affected.
if (event->content.kick != prevEvent->content.kick) { if (event.content.kick != prevEvent->content.kick) {
auto default_message = tr("%1 has changed the room's kick powerlevel from %2 to %3.") auto default_message = tr("%1 has changed the room's kick powerlevel from %2 to %3.")
.arg(sender_name) .arg(sender_name)
.arg(prevEvent->content.kick) .arg(prevEvent->content.kick)
.arg(event->content.kick); .arg(event.content.kick);
// We only calculate affected users if we change to a level above the default users PL // We only calculate affected users if we change to a level above the default users PL
// to not accidentally have a DoS vector // to not accidentally have a DoS vector
if (event->content.kick > default_powerlevel) { if (event.content.kick > default_powerlevel) {
auto [affected, number_of_affected] = calc_affected(event->content.kick); auto [affected, number_of_affected] = calc_affected(event.content.kick);
if (number_of_affected != 0) { if (number_of_affected != 0) {
auto true_affected_rest = number_of_affected - affected.size(); auto true_affected_rest = number_of_affected - affected.size();
@ -2444,16 +2493,16 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
} }
} }
if (event->content.redact != prevEvent->content.redact) { if (event.content.redact != prevEvent->content.redact) {
auto default_message = tr("%1 has changed the room's redact powerlevel from %2 to %3.") auto default_message = tr("%1 has changed the room's redact powerlevel from %2 to %3.")
.arg(sender_name) .arg(sender_name)
.arg(prevEvent->content.redact) .arg(prevEvent->content.redact)
.arg(event->content.redact); .arg(event.content.redact);
// We only calculate affected users if we change to a level above the default users PL // We only calculate affected users if we change to a level above the default users PL
// to not accidentally have a DoS vector // to not accidentally have a DoS vector
if (event->content.redact > default_powerlevel) { if (event.content.redact > default_powerlevel) {
auto [affected, number_of_affected] = calc_affected(event->content.redact); auto [affected, number_of_affected] = calc_affected(event.content.redact);
if (number_of_affected != 0) { if (number_of_affected != 0) {
auto true_affected_rest = number_of_affected - affected.size(); auto true_affected_rest = number_of_affected - affected.size();
@ -2476,16 +2525,16 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
} }
} }
if (event->content.ban != prevEvent->content.ban) { if (event.content.ban != prevEvent->content.ban) {
auto default_message = tr("%1 has changed the room's ban powerlevel from %2 to %3.") auto default_message = tr("%1 has changed the room's ban powerlevel from %2 to %3.")
.arg(sender_name) .arg(sender_name)
.arg(prevEvent->content.ban) .arg(prevEvent->content.ban)
.arg(event->content.ban); .arg(event.content.ban);
// We only calculate affected users if we change to a level above the default users PL // We only calculate affected users if we change to a level above the default users PL
// to not accidentally have a DoS vector // to not accidentally have a DoS vector
if (event->content.ban > default_powerlevel) { if (event.content.ban > default_powerlevel) {
auto [affected, number_of_affected] = calc_affected(event->content.ban); auto [affected, number_of_affected] = calc_affected(event.content.ban);
if (number_of_affected != 0) { if (number_of_affected != 0) {
auto true_affected_rest = number_of_affected - affected.size(); auto true_affected_rest = number_of_affected - affected.size();
@ -2507,17 +2556,17 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
} }
} }
if (event->content.state_default != prevEvent->content.state_default) { if (event.content.state_default != prevEvent->content.state_default) {
auto default_message = auto default_message =
tr("%1 has changed the room's state_default powerlevel from %2 to %3.") tr("%1 has changed the room's state_default powerlevel from %2 to %3.")
.arg(sender_name) .arg(sender_name)
.arg(prevEvent->content.state_default) .arg(prevEvent->content.state_default)
.arg(event->content.state_default); .arg(event.content.state_default);
// We only calculate affected users if we change to a level above the default users PL // We only calculate affected users if we change to a level above the default users PL
// to not accidentally have a DoS vector // to not accidentally have a DoS vector
if (event->content.state_default > default_powerlevel) { if (event.content.state_default > default_powerlevel) {
auto [affected, number_of_affected] = calc_affected(event->content.kick); auto [affected, number_of_affected] = calc_affected(event.content.kick);
if (number_of_affected != 0) { if (number_of_affected != 0) {
auto true_affected_rest = number_of_affected - affected.size(); auto true_affected_rest = number_of_affected - affected.size();
@ -2541,42 +2590,42 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
// These affect potentially the whole room. We there for do not calculate who gets affected // These affect potentially the whole room. We there for do not calculate who gets affected
// by this to prevent huge lists of people. // by this to prevent huge lists of people.
if (event->content.invite != prevEvent->content.invite) { if (event.content.invite != prevEvent->content.invite) {
resultingMessage.append(tr("%1 has changed the room's invite powerlevel from %2 to %3.") resultingMessage.append(tr("%1 has changed the room's invite powerlevel from %2 to %3.")
.arg(sender_name, .arg(sender_name,
QString::number(prevEvent->content.invite), QString::number(prevEvent->content.invite),
QString::number(event->content.invite))); QString::number(event.content.invite)));
} }
if (event->content.events_default != prevEvent->content.events_default) { if (event.content.events_default != prevEvent->content.events_default) {
if ((event->content.events_default > default_powerlevel) && if ((event.content.events_default > default_powerlevel) &&
prevEvent->content.events_default <= default_powerlevel) { prevEvent->content.events_default <= default_powerlevel) {
resultingMessage.append( resultingMessage.append(
tr("%1 has changed the room's events_default powerlevel from %2 to %3. New " tr("%1 has changed the room's events_default powerlevel from %2 to %3. New "
"users can now not send any events.") "users can now not send any events.")
.arg(sender_name, .arg(sender_name,
QString::number(prevEvent->content.events_default), QString::number(prevEvent->content.events_default),
QString::number(event->content.events_default))); QString::number(event.content.events_default)));
} else if ((event->content.events_default < prevEvent->content.events_default) && } else if ((event.content.events_default < prevEvent->content.events_default) &&
(event->content.events_default < default_powerlevel) && (event.content.events_default < default_powerlevel) &&
(prevEvent->content.events_default > default_powerlevel)) { (prevEvent->content.events_default > default_powerlevel)) {
resultingMessage.append( resultingMessage.append(
tr("%1 has changed the room's events_default powerlevel from %2 to %3. New " tr("%1 has changed the room's events_default powerlevel from %2 to %3. New "
"users can now send events that are not otherwise restricted.") "users can now send events that are not otherwise restricted.")
.arg(sender_name, .arg(sender_name,
QString::number(prevEvent->content.events_default), QString::number(prevEvent->content.events_default),
QString::number(event->content.events_default))); QString::number(event.content.events_default)));
} else { } else {
resultingMessage.append( resultingMessage.append(
tr("%1 has changed the room's events_default powerlevel from %2 to %3.") tr("%1 has changed the room's events_default powerlevel from %2 to %3.")
.arg(sender_name, .arg(sender_name,
QString::number(prevEvent->content.events_default), QString::number(prevEvent->content.events_default),
QString::number(event->content.events_default))); QString::number(event.content.events_default)));
} }
} }
// Compare if a Powerlevel of a user changed // Compare if a Powerlevel of a user changed
for (auto const &[mxid, powerlevel] : event->content.users) { for (auto const &[mxid, powerlevel] : event.content.users) {
auto nameOfChangedUser = utils::replaceEmoji(displayName(QString::fromStdString(mxid))); auto nameOfChangedUser = utils::replaceEmoji(displayName(QString::fromStdString(mxid)));
if (prevEvent->content.user_level(mxid) != powerlevel) { if (prevEvent->content.user_level(mxid) != powerlevel) {
if (powerlevel >= administrator_power_level) { if (powerlevel >= administrator_power_level) {
@ -2601,7 +2650,7 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
} }
// Handle added/removed/changed event type // Handle added/removed/changed event type
for (auto const &[event_type, powerlevel] : event->content.events) { for (auto const &[event_type, powerlevel] : event.content.events) {
auto prev_not_present = auto prev_not_present =
prevEvent->content.events.find(event_type) == prevEvent->content.events.end(); prevEvent->content.events.find(event_type) == prevEvent->content.events.end();
@ -2640,26 +2689,19 @@ TimelineModel::formatPowerLevelEvent(const QString &id)
} }
QString QString
TimelineModel::formatImagePackEvent(const QString &id) TimelineModel::formatImagePackEvent(
const mtx::events::StateEvent<mtx::events::msc2545::ImagePack> &event) const
{ {
auto e = events.get(id.toStdString(), "");
if (!e)
return {};
auto event = std::get_if<mtx::events::StateEvent<mtx::events::msc2545::ImagePack>>(e);
if (!event)
return {};
mtx::events::StateEvent<mtx::events::msc2545::ImagePack> const *prevEvent = nullptr; mtx::events::StateEvent<mtx::events::msc2545::ImagePack> const *prevEvent = nullptr;
if (!event->unsigned_data.replaces_state.empty()) { if (!event.unsigned_data.replaces_state.empty()) {
auto tempPrevEvent = events.get(event->unsigned_data.replaces_state, event->event_id); auto tempPrevEvent = events.get(event.unsigned_data.replaces_state, event.event_id);
if (tempPrevEvent) { if (tempPrevEvent) {
prevEvent = prevEvent =
std::get_if<mtx::events::StateEvent<mtx::events::msc2545::ImagePack>>(tempPrevEvent); std::get_if<mtx::events::StateEvent<mtx::events::msc2545::ImagePack>>(tempPrevEvent);
} }
} }
const auto &newImages = event->content.images; const auto &newImages = event.content.images;
const auto oldImages = prevEvent ? prevEvent->content.images : decltype(newImages){}; const auto oldImages = prevEvent ? prevEvent->content.images : decltype(newImages){};
auto ascent = QFontMetrics(UserSettings::instance()->font()).ascent(); auto ascent = QFontMetrics(UserSettings::instance()->font()).ascent();
@ -2682,12 +2724,12 @@ TimelineModel::formatImagePackEvent(const QString &id)
auto added = calcChange(newImages, oldImages); auto added = calcChange(newImages, oldImages);
auto removed = calcChange(oldImages, newImages); auto removed = calcChange(oldImages, newImages);
auto sender = utils::replaceEmoji(displayName(QString::fromStdString(event->sender))); auto sender = utils::replaceEmoji(displayName(QString::fromStdString(event.sender)));
const auto packId = [&event]() -> QString { const auto packId = [&event]() -> QString {
if (event->content.pack && !event->content.pack->display_name.empty()) { if (event.content.pack && !event.content.pack->display_name.empty()) {
return event->content.pack->display_name.c_str(); return event.content.pack->display_name.c_str();
} else if (!event->state_key.empty()) { } else if (!event.state_key.empty()) {
return event->state_key.c_str(); return event.state_key.c_str();
} }
return tr("(empty)"); return tr("(empty)");
}(); }();
@ -2712,7 +2754,7 @@ TimelineModel::formatImagePackEvent(const QString &id)
} }
QString QString
TimelineModel::formatPolicyRule(const QString &id) TimelineModel::formatPolicyRule(const QString &id) const
{ {
auto idStr = id.toStdString(); auto idStr = id.toStdString();
auto e = events.get(idStr, ""); auto e = events.get(idStr, "");

View File

@ -238,6 +238,7 @@ public:
IsOnlyEmoji, IsOnlyEmoji,
Body, Body,
FormattedBody, FormattedBody,
FormattedStateEvent,
IsSender, IsSender,
UserId, UserId,
UserName, UserName,
@ -310,11 +311,15 @@ public:
Q_INVOKABLE void joinReplacementRoom(const QString &id); Q_INVOKABLE void joinReplacementRoom(const QString &id);
Q_INVOKABLE QString formatMemberEvent(const QString &id); Q_INVOKABLE QString formatMemberEvent(const QString &id);
Q_INVOKABLE QString formatJoinRuleEvent(const QString &id); Q_INVOKABLE QString formatJoinRuleEvent(const QString &id);
Q_INVOKABLE QString formatHistoryVisibilityEvent(const QString &id); QString formatHistoryVisibilityEvent(
Q_INVOKABLE QString formatGuestAccessEvent(const QString &id); const mtx::events::StateEvent<mtx::events::state::HistoryVisibility> &event) const;
Q_INVOKABLE QString formatPowerLevelEvent(const QString &id); QString
Q_INVOKABLE QString formatImagePackEvent(const QString &id); formatGuestAccessEvent(const mtx::events::StateEvent<mtx::events::state::GuestAccess> &) const;
Q_INVOKABLE QString formatPolicyRule(const QString &id); QString formatPowerLevelEvent(
const mtx::events::StateEvent<mtx::events::state::PowerLevels> &event) const;
QString formatImagePackEvent(
const mtx::events::StateEvent<mtx::events::msc2545::ImagePack> &event) const;
Q_INVOKABLE QString formatPolicyRule(const QString &id) const;
Q_INVOKABLE QVariantMap formatRedactedEvent(const QString &id); Q_INVOKABLE QVariantMap formatRedactedEvent(const QString &id);
Q_INVOKABLE void viewRawMessage(const QString &id); Q_INVOKABLE void viewRawMessage(const QString &id);