Refactor NeoChatRoom a bit

This commit is contained in:
Tobias Fella
2026-02-13 23:32:12 +01:00
committed by Joshua Goins
parent 4e616d53b2
commit b88e27d6d5

View File

@@ -62,14 +62,18 @@
#include <ranges> #include <ranges>
using namespace Quotient; using namespace Quotient;
using namespace std::ranges::views;
std::function<bool(const Quotient::RoomEvent *)> NeoChatRoom::m_hiddenFilter = [](const Quotient::RoomEvent *) -> bool { std::function<bool(const Quotient::RoomEvent *)> NeoChatRoom::m_hiddenFilter = [](const Quotient::RoomEvent *) -> bool {
return false; return false;
}; };
NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinState) NeoChatRoom::NeoChatRoom(Connection *c, QString roomId, JoinState joinState)
: Room(connection, std::move(roomId), joinState) : Room(c, std::move(roomId), joinState)
{ {
const auto connection = static_cast<NeoChatConnection *>(c);
Q_ASSERT(connection);
m_mainCache = new ChatBarCache(this); m_mainCache = new ChatBarCache(this);
m_editCache = new ChatBarCache(this); m_editCache = new ChatBarCache(this);
m_threadCache = new ChatBarCache(this); m_threadCache = new ChatBarCache(this);
@@ -79,24 +83,21 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
setFileUploadingProgress(0); setFileUploadingProgress(0);
setHasFileUploading(false); setHasFileUploading(false);
}); });
connect(this, &Room::fileTransferCompleted, this, [this](QString eventId) { connect(this, &Room::fileTransferCompleted, this, [this](const QString &eventId) {
const auto evtIt = findInTimeline(eventId); if (const auto evtIt = findInTimeline(eventId); evtIt != messageEvents().rend()) {
if (evtIt != messageEvents().rend()) {
const auto m_event = evtIt->viewAs<RoomEvent>();
QString mxcUrl; QString mxcUrl;
if (auto event = eventCast<const Quotient::RoomMessageEvent>(m_event)) { if (auto roomMessageEvent = evtIt->viewAs<const Quotient::RoomMessageEvent>();
if (event->has<EventContent::FileContentBase>()) { roomMessageEvent && roomMessageEvent->has<EventContent::FileContentBase>()) {
mxcUrl = event->get<EventContent::FileContentBase>()->url().toString(); mxcUrl = roomMessageEvent->get<EventContent::FileContentBase>()->url().toString();
} } else if (auto event = evtIt->viewAs<const Quotient::StickerEvent>()) {
} else if (auto event = eventCast<const Quotient::StickerEvent>(m_event)) {
mxcUrl = event->image().url().toString(); mxcUrl = event->image().url().toString();
} }
if (mxcUrl.isEmpty()) { if (mxcUrl.isEmpty()) {
return; return;
} }
auto localPath = this->fileTransferInfo(eventId).localPath.toLocalFile(); KSharedConfig::openStateConfig(u"neochatdownloads"_s)
auto config = KSharedConfig::openStateConfig(u"neochatdownloads"_s)->group(u"downloads"_s); ->group(u"downloads"_s)
config.writePathEntry(mxcUrl.mid(6), localPath); .writePathEntry(mxcUrl.mid(6), fileTransferInfo(eventId).localPath.toLocalFile());
} }
}); });
@@ -104,21 +105,16 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
connect(this, &Room::aboutToAddHistoricalMessages, this, &NeoChatRoom::cleanupExtraEventRange); connect(this, &Room::aboutToAddHistoricalMessages, this, &NeoChatRoom::cleanupExtraEventRange);
connect(this, &Room::aboutToAddNewMessages, this, &NeoChatRoom::cleanupExtraEventRange); connect(this, &Room::aboutToAddNewMessages, this, &NeoChatRoom::cleanupExtraEventRange);
const auto &roomLastMessageProvider = RoomLastMessageProvider::self(); if (RoomLastMessageProvider::self().hasKey(id())) {
if (auto eventJson = QJsonDocument::fromJson(RoomLastMessageProvider::self().read(id())).object(); !eventJson.isEmpty()) {
if (roomLastMessageProvider.hasKey(id())) { if (auto event = loadEvent<RoomEvent>(eventJson)) {
auto eventJson = QJsonDocument::fromJson(roomLastMessageProvider.read(id())).object();
if (!eventJson.isEmpty()) {
auto event = loadEvent<RoomEvent>(eventJson);
if (event != nullptr) {
m_cachedEvent = std::move(event); m_cachedEvent = std::move(event);
} }
} }
} }
connect(this, &Room::addedMessages, this, &NeoChatRoom::cacheLastEvent); connect(this, &Room::addedMessages, this, &NeoChatRoom::cacheLastEvent);
connect(this, &Quotient::Room::eventsHistoryJobChanged, this, &NeoChatRoom::lastActiveTimeChanged); connect(this, &Room::eventsHistoryJobChanged, this, &NeoChatRoom::lastActiveTimeChanged);
connect(this, &Room::joinStateChanged, this, [this](JoinState oldState, JoinState newState) { connect(this, &Room::joinStateChanged, this, [this](JoinState oldState, JoinState newState) {
if (oldState == JoinState::Invite && newState != JoinState::Invite) { if (oldState == JoinState::Invite && newState != JoinState::Invite) {
@@ -170,9 +166,7 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
} }
}); });
const auto neochatconnection = static_cast<NeoChatConnection *>(connection); connect(connection, &NeoChatConnection::globalUrlPreviewEnabledChanged, this, &NeoChatRoom::urlPreviewEnabledChanged);
Q_ASSERT(neochatconnection);
connect(neochatconnection, &NeoChatConnection::globalUrlPreviewEnabledChanged, this, &NeoChatRoom::urlPreviewEnabledChanged);
connect(this, &Room::fullyReadMarkerMoved, this, &NeoChatRoom::invalidateLastUnreadHighlightId); connect(this, &Room::fullyReadMarkerMoved, this, &NeoChatRoom::invalidateLastUnreadHighlightId);
// This may look weird, but this is actually for performance. // This may look weird, but this is actually for performance.
@@ -256,19 +250,17 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body, std::optiona
if (url.isEmpty()) { if (url.isEmpty()) {
co_return; co_return;
} }
auto mime = QMimeDatabase().mimeTypeForUrl(url);
url.setScheme("file"_L1); url.setScheme("file"_L1);
QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString()); QFileInfo fileInfo(url.isLocalFile() ? url.toLocalFile() : url.toString());
EventContent::FileContentBase *content;
const auto mime = QMimeDatabase().mimeTypeForUrl(url);
EventContent::FileContentBase *content = nullptr;
if (mime.name().startsWith("image/"_L1)) { if (mime.name().startsWith("image/"_L1)) {
QImage image(url.toLocalFile()); content = new EventContent::ImageContent(url, fileInfo.size(), mime, QImage(url.toLocalFile()).size(), fileInfo.fileName());
content = new EventContent::ImageContent(url, fileInfo.size(), mime, image.size(), fileInfo.fileName());
} else if (mime.name().startsWith("audio/"_L1)) { } else if (mime.name().startsWith("audio/"_L1)) {
content = new EventContent::AudioContent(url, fileInfo.size(), mime, fileInfo.fileName()); content = new EventContent::AudioContent(url, fileInfo.size(), mime, fileInfo.fileName());
} else if (mime.name().startsWith("video/"_L1)) { } else if (mime.name().startsWith("video/"_L1)) {
QVideoSink sink; QVideoSink sink;
QMediaPlayer player; QMediaPlayer player;
player.setSource(url); player.setSource(url);
player.setVideoSink(&sink); player.setVideoSink(&sink);
@@ -305,7 +297,7 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body, std::optiona
content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName()); content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName());
} }
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, std::unique_ptr<EventContent::FileContentBase>(content), relatesTo); const auto txnId = postFile(body.isEmpty() ? url.fileName() : body, std::unique_ptr<EventContent::FileContentBase>(content), relatesTo);
setHasFileUploading(true); setHasFileUploading(true);
connect(this, &Room::fileTransferCompleted, [this, txnId](const QString &id, FileSourceInfo) { connect(this, &Room::fileTransferCompleted, [this, txnId](const QString &id, FileSourceInfo) {
if (id == txnId) { if (id == txnId) {
@@ -329,8 +321,7 @@ QCoro::Task<void> NeoChatRoom::doUploadFile(QUrl url, QString body, std::optiona
connect(this, &Room::fileTransferProgress, job, &FileTransferPseudoJob::fileTransferProgress); connect(this, &Room::fileTransferProgress, job, &FileTransferPseudoJob::fileTransferProgress);
connect(this, &Room::fileTransferCompleted, job, &FileTransferPseudoJob::fileTransferCompleted); connect(this, &Room::fileTransferCompleted, job, &FileTransferPseudoJob::fileTransferCompleted);
connect(this, &Room::fileTransferFailed, job, [this, job, txnId] { connect(this, &Room::fileTransferFailed, job, [this, job, txnId] {
auto info = fileTransferInfo(txnId); if (fileTransferInfo(txnId).status == FileTransferInfo::Cancelled) {
if (info.status == FileTransferInfo::Cancelled) {
job->fileTransferCanceled(txnId); job->fileTransferCanceled(txnId);
} else { } else {
job->fileTransferFailed(txnId); job->fileTransferFailed(txnId);
@@ -376,10 +367,8 @@ const RoomEvent *NeoChatRoom::lastEvent(std::function<bool(const RoomEvent *)> f
for (auto timelineItem = messageEvents().rbegin(); timelineItem < messageEvents().rend(); timelineItem++) { for (auto timelineItem = messageEvents().rbegin(); timelineItem < messageEvents().rend(); timelineItem++) {
const RoomEvent *event = timelineItem->get(); const RoomEvent *event = timelineItem->get();
if (filter) { if (filter && filter(event)) {
if (filter(event)) { continue;
continue;
}
} }
if (is<RedactionEvent>(*event) || is<ReactionEvent>(*event)) { if (is<RedactionEvent>(*event) || is<ReactionEvent>(*event)) {
@@ -420,7 +409,7 @@ const RoomEvent *NeoChatRoom::lastEvent(std::function<bool(const RoomEvent *)> f
} }
} }
if (m_cachedEvent != nullptr) { if (m_cachedEvent) {
return std::to_address(m_cachedEvent); return std::to_address(m_cachedEvent);
} }
@@ -429,18 +418,9 @@ const RoomEvent *NeoChatRoom::lastEvent(std::function<bool(const RoomEvent *)> f
void NeoChatRoom::cacheLastEvent() void NeoChatRoom::cacheLastEvent()
{ {
auto event = lastEvent(m_hiddenFilter); if (auto event = lastEvent(m_hiddenFilter)) {
if (event != nullptr) { RoomLastMessageProvider::self().write(id(), QJsonDocument(event->fullJson()).toJson(QJsonDocument::Compact));
auto &roomLastMessageProvider = RoomLastMessageProvider::self(); m_cachedEvent = loadEvent<RoomEvent>(event->fullJson());
auto eventJson = QJsonDocument(event->fullJson()).toJson(QJsonDocument::Compact);
roomLastMessageProvider.write(id(), eventJson);
auto uniqueEvent = loadEvent<RoomEvent>(event->fullJson());
if (event != nullptr) {
m_cachedEvent = std::move(uniqueEvent);
}
} }
} }
@@ -448,8 +428,7 @@ bool NeoChatRoom::isEventSpoiler(const RoomEvent *e) const
{ {
if (const auto message = eventCast<const RoomMessageEvent>(e)) { if (const auto message = eventCast<const RoomMessageEvent>(e)) {
if (message->has<EventContent::TextContent>() && message->content() && message->mimeType().name() == "text/html"_L1) { if (message->has<EventContent::TextContent>() && message->content() && message->mimeType().name() == "text/html"_L1) {
const auto htmlBody = message->get<EventContent::TextContent>()->body; return message->get<EventContent::TextContent>()->body.contains("data-mx-spoiler"_L1);
return htmlBody.contains("data-mx-spoiler"_L1);
} }
} }
return false; return false;
@@ -466,10 +445,10 @@ void NeoChatRoom::checkForHighlights(const Quotient::TimelineItem &ti)
if (ti->senderId() == localMember.id()) { if (ti->senderId() == localMember.id()) {
return; return;
} }
if (auto *e = ti.viewAs<RoomMessageEvent>()) { if (const auto roomMessageEvent = ti.viewAs<RoomMessageEvent>()) {
const auto &text = e->plainBody(); const auto &text = roomMessageEvent->plainBody();
if (text.contains(localMember.id()) || text.contains(localMember.disambiguatedName())) { if (text.contains(localMember.id()) || text.contains(localMember.disambiguatedName())) {
highlights.insert(e); highlights.insert(roomMessageEvent);
} }
} }
} }
@@ -490,8 +469,8 @@ void NeoChatRoom::onAddHistoricalTimelineEvents(rev_iter_t from)
void NeoChatRoom::onRedaction(const RoomEvent &prevEvent, const RoomEvent & /*after*/) void NeoChatRoom::onRedaction(const RoomEvent &prevEvent, const RoomEvent & /*after*/)
{ {
if (const auto &e = eventCast<const ReactionEvent>(&prevEvent)) { if (const auto &reactionEvent = eventCast<const ReactionEvent>(&prevEvent)) {
if (auto relatedEventId = e->eventId(); !relatedEventId.isEmpty()) { if (auto relatedEventId = reactionEvent->eventId(); !relatedEventId.isEmpty()) {
Q_EMIT updatedEvent(relatedEventId); Q_EMIT updatedEvent(relatedEventId);
} }
} }
@@ -520,8 +499,7 @@ QUrl NeoChatRoom::avatarMediaUrl() const
} }
// Use the first (excluding self) user's avatar for direct chats // Use the first (excluding self) user's avatar for direct chats
const auto directChatMembers = this->directChatMembers(); for (const auto &member : directChatMembers()) {
for (const auto member : directChatMembers) {
if (member != localMember()) { if (member != localMember()) {
return member.avatarUrl(); return member.avatarUrl();
} }
@@ -548,32 +526,21 @@ void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction
return; return;
} }
const auto &evt = **eventIt; auto isOwnReactionOfType = [this, reaction](const auto &it) {
auto reactionEvent = eventCast<const ReactionEvent>(it);
return reactionEvent && reactionEvent->key() == reaction && reactionEvent->senderId() == localMember().id();
};
QStringList redactEventIds; // What if there are multiple reaction events? const auto &annotations = relatedEvents(**eventIt, EventRelation::AnnotationType);
auto redactEventIds = annotations | filter(isOwnReactionOfType) | transform(&RoomEvent::id);
const auto &annotations = relatedEvents(evt, EventRelation::AnnotationType); if (std::ranges::empty(redactEventIds)) {
if (!annotations.isEmpty()) { postReaction(eventId, reaction);
for (const auto &a : annotations) { return;
if (auto e = eventCast<const ReactionEvent>(a)) {
if (e->key() != reaction) {
continue;
}
if (e->senderId() == localMember().id()) {
redactEventIds.push_back(e->id());
break;
}
}
}
} }
if (!redactEventIds.isEmpty()) { for (const auto &redactEventId : redactEventIds) {
for (const auto &redactEventId : redactEventIds) { redactEvent(redactEventId);
redactEvent(redactEventId);
}
} else {
postReaction(eventId, reaction);
} }
} }