Add support for copying & deleting multiple messages at once
BUG: 496458
This commit is contained in:
committed by
Joshua Goins
parent
0f634ff795
commit
f5d726989f
@@ -59,6 +59,8 @@
|
||||
#include <KJobTrackerInterface>
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <ranges>
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
std::function<bool(const Quotient::RoomEvent *)> NeoChatRoom::m_hiddenFilter = [](const Quotient::RoomEvent *) -> bool {
|
||||
@@ -630,7 +632,14 @@ bool NeoChatRoom::isUserBanned(const QString &user) const
|
||||
|
||||
void NeoChatRoom::deleteMessagesByUser(const QString &user, const QString &reason)
|
||||
{
|
||||
doDeleteMessagesByUser(user, reason);
|
||||
QStringList events;
|
||||
for (const auto &event : messageEvents()) {
|
||||
if (event->senderId() == user && !event->isRedacted() && !event.viewAs<RedactionEvent>() && !event->isStateEvent()) {
|
||||
events += event->id();
|
||||
}
|
||||
}
|
||||
|
||||
doDeleteMessageIds(events, reason);
|
||||
}
|
||||
|
||||
QString NeoChatRoom::historyVisibility() const
|
||||
@@ -761,16 +770,10 @@ void NeoChatRoom::setUserPowerLevel(const QString &userID, const int &powerLevel
|
||||
}
|
||||
}
|
||||
|
||||
QCoro::Task<void> NeoChatRoom::doDeleteMessagesByUser(const QString &user, QString reason)
|
||||
QCoro::Task<void> NeoChatRoom::doDeleteMessageIds(const QStringList eventIds, QString reason)
|
||||
{
|
||||
QStringList events;
|
||||
for (const auto &event : messageEvents()) {
|
||||
if (event->senderId() == user && !event->isRedacted() && !event.viewAs<RedactionEvent>() && !event->isStateEvent()) {
|
||||
events += event->id();
|
||||
}
|
||||
}
|
||||
for (const auto &e : events) {
|
||||
auto job = connection()->callApi<RedactEventJob>(id(), QString::fromLatin1(QUrl::toPercentEncoding(e)), connection()->generateTxnId(), reason);
|
||||
for (const auto &eventId : eventIds) {
|
||||
auto job = connection()->callApi<RedactEventJob>(id(), eventId, connection()->generateTxnId(), reason);
|
||||
co_await qCoro(job.get(), &BaseJob::finished);
|
||||
if (job->error() != BaseJob::Success) {
|
||||
qWarning() << "Error: \"" << job->error() << "\" while deleting messages. Aborting";
|
||||
@@ -1963,4 +1966,96 @@ QList<QString> NeoChatRoom::sortedMemberIds() const
|
||||
return m_sortedMemberIds;
|
||||
}
|
||||
|
||||
int NeoChatRoom::selectedMessageCount() const
|
||||
{
|
||||
return m_selectedMessageIds.size();
|
||||
}
|
||||
|
||||
bool NeoChatRoom::canDeleteSelectedMessages() const
|
||||
{
|
||||
if (canSendState("redact"_L1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString localUserId = connection()->userId();
|
||||
return std::ranges::all_of(m_selectedMessageIds, [this, localUserId](const QString &eventId) {
|
||||
const auto eventIt = findInTimeline(eventId);
|
||||
if (eventIt == historyEdge()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RoomEvent *event = eventIt->event();
|
||||
return event && (event->senderId() == localUserId);
|
||||
});
|
||||
}
|
||||
|
||||
bool NeoChatRoom::isMessageSelected(const QString &eventId) const
|
||||
{
|
||||
return m_selectedMessageIds.contains(eventId);
|
||||
}
|
||||
|
||||
void NeoChatRoom::toggleMessageSelection(const QString &eventId)
|
||||
{
|
||||
if (!m_selectedMessageIds.remove(eventId)) {
|
||||
m_selectedMessageIds.insert(eventId);
|
||||
}
|
||||
|
||||
Q_EMIT selectionChanged();
|
||||
}
|
||||
|
||||
QString NeoChatRoom::getFormattedSelectedMessages() const
|
||||
{
|
||||
QVector<const RoomEvent *> events;
|
||||
events.reserve(m_selectedMessageIds.size());
|
||||
|
||||
std::ranges::copy(m_selectedMessageIds | std::views::transform([this](const QString &eventId) -> const RoomEvent * {
|
||||
const auto eventIt = findInTimeline(eventId);
|
||||
return eventIt != historyEdge() ? eventIt->event() : nullptr;
|
||||
}) | std::views::filter([](const RoomEvent *event) {
|
||||
return event != nullptr;
|
||||
}),
|
||||
std::back_inserter(events));
|
||||
|
||||
std::ranges::sort(events, {}, &RoomEvent::originTimestamp);
|
||||
|
||||
QString formattedContent;
|
||||
formattedContent.reserve(events.size() * 256); // estimate an average of 256 characters per message
|
||||
|
||||
for (const RoomEvent *event : events) {
|
||||
formattedContent += EventHandler::authorDisplayName(this, event);
|
||||
formattedContent += u" — "_s;
|
||||
formattedContent += EventHandler::dateTime(this, event).shortDateTime();
|
||||
formattedContent += u'\n';
|
||||
formattedContent += EventHandler::plainBody(this, event);
|
||||
formattedContent += u"\n\n"_s;
|
||||
}
|
||||
|
||||
return formattedContent.trimmed();
|
||||
}
|
||||
|
||||
void NeoChatRoom::deleteSelectedMessages(const QString &reason)
|
||||
{
|
||||
QStringList events;
|
||||
for (const auto &eventId : m_selectedMessageIds) {
|
||||
const auto eventIt = findInTimeline(eventId);
|
||||
if (eventIt == historyEdge()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const RoomEvent *event = eventIt->event();
|
||||
if (event && !event->isRedacted() && !is<RedactionEvent>(*event)) {
|
||||
events += eventId;
|
||||
}
|
||||
}
|
||||
|
||||
doDeleteMessageIds(events, reason);
|
||||
clearSelectedMessages();
|
||||
}
|
||||
|
||||
void NeoChatRoom::clearSelectedMessages()
|
||||
{
|
||||
m_selectedMessageIds.clear();
|
||||
Q_EMIT selectionChanged();
|
||||
}
|
||||
|
||||
#include "moc_neochatroom.cpp"
|
||||
|
||||
@@ -220,6 +220,16 @@ class NeoChatRoom : public Quotient::Room
|
||||
*/
|
||||
Q_PROPERTY(bool spaceHasUnreadMessages READ spaceHasUnreadMessages NOTIFY spaceHasUnreadMessagesChanged)
|
||||
|
||||
/**
|
||||
* @brief The number of selected messages in the room.
|
||||
*/
|
||||
Q_PROPERTY(int selectedMessageCount READ selectedMessageCount NOTIFY selectionChanged)
|
||||
|
||||
/**
|
||||
* @brief Whether the user can delete the selected messages.
|
||||
*/
|
||||
Q_PROPERTY(bool canDeleteSelectedMessages READ canDeleteSelectedMessages NOTIFY selectionChanged)
|
||||
|
||||
public:
|
||||
explicit NeoChatRoom(Quotient::Connection *connection, QString roomId, Quotient::JoinState joinState = {});
|
||||
|
||||
@@ -676,6 +686,41 @@ public:
|
||||
*/
|
||||
QList<QString> sortedMemberIds() const;
|
||||
|
||||
/**
|
||||
* @brief The number of selected messages in the room.
|
||||
*/
|
||||
int selectedMessageCount() const;
|
||||
|
||||
/**
|
||||
* @brief Whether the user can delete the selected messages.
|
||||
*/
|
||||
bool canDeleteSelectedMessages() const;
|
||||
|
||||
/**
|
||||
* @brief Whether the given message is selected.
|
||||
*/
|
||||
Q_INVOKABLE bool isMessageSelected(const QString &eventId) const;
|
||||
|
||||
/**
|
||||
* @brief Toggle the selection state of the given message.
|
||||
*/
|
||||
Q_INVOKABLE void toggleMessageSelection(const QString &eventId);
|
||||
|
||||
/**
|
||||
* @brief Get the content of the selected messages formatted as a single string.
|
||||
*/
|
||||
Q_INVOKABLE QString getFormattedSelectedMessages() const;
|
||||
|
||||
/**
|
||||
* @brief Delete the selected messages with an optional reason.
|
||||
*/
|
||||
Q_INVOKABLE void deleteSelectedMessages(const QString &reason = QString());
|
||||
|
||||
/**
|
||||
* @brief Clear the selection of messages.
|
||||
*/
|
||||
Q_INVOKABLE void clearSelectedMessages();
|
||||
|
||||
private:
|
||||
bool m_visible = false;
|
||||
|
||||
@@ -693,7 +738,7 @@ private:
|
||||
void onAddHistoricalTimelineEvents(rev_iter_t from) override;
|
||||
void onRedaction(const Quotient::RoomEvent &prevEvent, const Quotient::RoomEvent &after) override;
|
||||
|
||||
QCoro::Task<void> doDeleteMessagesByUser(const QString &user, QString reason);
|
||||
QCoro::Task<void> doDeleteMessageIds(const QStringList eventIds, QString reason);
|
||||
QCoro::Task<void> doUploadFile(QUrl url, QString body = QString(), std::optional<Quotient::EventRelation> relatesTo = std::nullopt);
|
||||
|
||||
std::unique_ptr<Quotient::RoomEvent> m_cachedEvent;
|
||||
@@ -713,6 +758,7 @@ private:
|
||||
|
||||
QString m_lastUnreadHighlightId;
|
||||
QList<QString> m_sortedMemberIds;
|
||||
QSet<QString> m_selectedMessageIds;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updatePushNotificationState(QString type);
|
||||
@@ -752,6 +798,7 @@ Q_SIGNALS:
|
||||
void pinnedMessageChanged();
|
||||
void highlightCycleStartedChanged();
|
||||
void spaceHasUnreadMessagesChanged();
|
||||
void selectionChanged();
|
||||
|
||||
/**
|
||||
* @brief Request a message be shown to the user of the given type.
|
||||
|
||||
Reference in New Issue
Block a user