diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ChatPage.cpp | 50 | ||||
-rw-r--r-- | src/ChatPage.h | 1 | ||||
-rw-r--r-- | src/UserSettingsPage.cpp | 6 | ||||
-rw-r--r-- | src/UserSettingsPage.h | 2 | ||||
-rw-r--r-- | src/timeline/TimelineModel.h | 2 | ||||
-rw-r--r-- | src/timeline/TimelineViewManager.cpp | 40 | ||||
-rw-r--r-- | src/timeline/TimelineViewManager.h | 11 | ||||
-rw-r--r-- | src/ui/UserProfile.cpp | 64 | ||||
-rw-r--r-- | src/ui/UserProfile.h | 6 |
9 files changed, 172 insertions, 10 deletions
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 25af8974..db5cbbe8 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -6,6 +6,9 @@ #include <QInputDialog> #include <QMessageBox> +#include <algorithm> +#include <unordered_set> + #include <mtx/responses.hpp> #include "AvatarProvider.h" @@ -775,6 +778,23 @@ ChatPage::handleSyncResponse(const mtx::responses::Sync &res, const std::string // Ensure that we have enough one-time keys available. ensureOneTimeKeyCount(res.device_one_time_keys_count, res.device_unused_fallback_key_types); + std::optional<mtx::events::account_data::IgnoredUsers> oldIgnoredUsers; + if (auto ignoreEv = std::ranges::find_if( + res.account_data.events, + [](const mtx::events::collections::RoomAccountDataEvents &e) { + return std::holds_alternative< + mtx::events::AccountDataEvent<mtx::events::account_data::IgnoredUsers>>(e); + }); + ignoreEv != res.account_data.events.end()) { + if (auto oldEv = cache::client()->getAccountData(mtx::events::EventType::IgnoredUsers)) + oldIgnoredUsers = + std::get<mtx::events::AccountDataEvent<mtx::events::account_data::IgnoredUsers>>( + *oldEv) + .content; + else + oldIgnoredUsers = mtx::events::account_data::IgnoredUsers{}; + } + // TODO: fine grained error handling try { cache::client()->saveState(res); @@ -783,6 +803,36 @@ ChatPage::handleSyncResponse(const mtx::responses::Sync &res, const std::string auto updates = cache::getRoomInfo(cache::client()->roomsWithStateUpdates(res)); emit syncUI(std::move(res)); + + // if the ignored users changed, clear timeline of all affected rooms. + if (oldIgnoredUsers) { + if (auto newEv = + cache::client()->getAccountData(mtx::events::EventType::IgnoredUsers)) { + std::vector<mtx::events::account_data::IgnoredUser> changedUsers{}; + std::ranges::set_symmetric_difference( + oldIgnoredUsers->users, + std::get<mtx::events::AccountDataEvent<mtx::events::account_data::IgnoredUsers>>( + *newEv) + .content.users, + std::back_inserter(changedUsers), + {}, + &mtx::events::account_data::IgnoredUser::id, + &mtx::events::account_data::IgnoredUser::id); + + std::unordered_set<std::string> roomsToReload; + for (const auto &user : changedUsers) { + auto commonRooms = cache::client()->getCommonRooms(user.id); + for (const auto &room : commonRooms) + roomsToReload.insert(room.first); + } + + for (const auto &room : roomsToReload) { + if (auto model = + view_manager_->rooms()->getRoomById(QString::fromStdString(room))) + model->clearTimeline(); + } + } + } } catch (const lmdb::map_full_error &e) { nhlog::db()->error("lmdb is full: {}", e.what()); cache::deleteOldData(); diff --git a/src/ChatPage.h b/src/ChatPage.h index 685b719b..1e1da049 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -16,6 +16,7 @@ #include <mtx/events/presence.hpp> #include <mtx/secret_storage.hpp> +#include <QDateTime> #include <QMap> #include <QPoint> #include <QSharedPointer> diff --git a/src/UserSettingsPage.cpp b/src/UserSettingsPage.cpp index c9c878d0..3bc2f161 100644 --- a/src/UserSettingsPage.cpp +++ b/src/UserSettingsPage.cpp @@ -1042,6 +1042,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const return tr("Read receipts"); case HiddenTimelineEvents: return tr("Hidden events"); + case IgnoredUsers: + return tr("Ignored users"); case DesktopNotifications: return tr("Desktop notifications"); case AlertOnNotification: @@ -1485,6 +1487,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const return tr("Regularly redact expired events as specified in the event expiration " "configuration. Since this is currently not executed server side, you need " "to have one client running this regularly."); + case IgnoredUsers: + return tr("Manage your ignored users."); } } else if (role == Type) { switch (index.row()) { @@ -1571,6 +1575,8 @@ UserSettingsModel::data(const QModelIndex &index, int role) const return KeyStatus; case HiddenTimelineEvents: return ConfigureHiddenEvents; + case IgnoredUsers: + return ManageIgnoredUsers; } } else if (role == ValueLowerBound) { switch (index.row()) { diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h index 2bae068a..2cf8e5ab 100644 --- a/src/UserSettingsPage.h +++ b/src/UserSettingsPage.h @@ -508,6 +508,7 @@ class UserSettingsModel : public QAbstractListModel MessageVisibilitySection, ExpireEvents, HiddenTimelineEvents, + IgnoredUsers, NotificationsSection, DesktopNotifications, @@ -566,6 +567,7 @@ public: SessionKeyImportExport, XSignKeysRequestDownload, ConfigureHiddenEvents, + ManageIgnoredUsers, }; Q_ENUM(Types); diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index a3933478..b9a48327 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -18,8 +18,6 @@ #include "CacheStructs.h" #include "EventStore.h" #include "InputBar.h" -#include "InviteesModel.h" -#include "MemberList.h" #include "Permissions.h" #include "ReadReceiptsModel.h" #include "ui/RoomSummary.h" diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index b8bd679b..e2616c14 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -12,6 +12,7 @@ #include <QString> #include "Cache.h" +#include "Cache_p.h" #include "ChatPage.h" #include "CombinedImagePackModel.h" #include "CommandCompleter.h" @@ -210,6 +211,7 @@ TimelineViewManager::sync(const mtx::responses::Sync &sync_) this->rooms_->sync(sync_); this->communities_->sync(sync_); this->presenceEmitter->sync(sync_.presence); + this->processIgnoredUsers(sync_.account_data); if (isInitialSync_) { this->isInitialSync_ = false; @@ -560,3 +562,41 @@ TimelineViewManager::fixImageRendering(QQuickTextDocument *t, QQuickItem *i) QObject::connect(t->textDocument(), SIGNAL(imagesLoaded()), i, SLOT(updateWholeDocument())); } } + +using IgnoredUsers = mtx::events::EphemeralEvent<mtx::events::account_data::IgnoredUsers>; + +static QVector<QString> +convertIgnoredToQt(const IgnoredUsers &ev) +{ + QVector<QString> users; + for (const mtx::events::account_data::IgnoredUser &user : ev.content.users) { + users.push_back(QString::fromStdString(user.id)); + } + + return users; +} + +QVector<QString> +TimelineViewManager::getIgnoredUsers() +{ + const auto cache = cache::client()->getAccountData(mtx::events::EventType::IgnoredUsers); + if (!cache) { + return {}; + } + + return convertIgnoredToQt(std::get<IgnoredUsers>(*cache)); +} + +void +TimelineViewManager::processIgnoredUsers(const mtx::responses::AccountData &data) +{ + for (const mtx::events::collections::RoomAccountDataEvents::variant &ev : data.events) { + if (!std::holds_alternative<IgnoredUsers>(ev)) { + continue; + } + const auto &ignoredEv = std::get<IgnoredUsers>(ev); + + emit this->ignoredUsersChanged(convertIgnoredToQt(ignoredEv)); + break; + } +} \ No newline at end of file diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index f3bd04a2..b4e176cd 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -11,7 +11,8 @@ #include <mtx/common.hpp> #include <mtx/responses/messages.hpp> -#include "ReadReceiptsModel.h" +#include "InviteesModel.h" +#include "MemberList.h" #include "timeline/CommunitiesModel.h" #include "timeline/PresenceEmitter.h" #include "timeline/RoomlistModel.h" @@ -39,6 +40,7 @@ class TimelineViewManager final : public QObject Q_PROPERTY( bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged) + Q_PROPERTY(QVector<QString> ignoredUsers READ getIgnoredUsers NOTIFY ignoredUsersChanged) public: TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr); @@ -62,6 +64,10 @@ public: return instance_; } + static TimelineViewManager *instance() { return TimelineViewManager::instance_; } + + QVector<QString> getIgnoredUsers(); + void sync(const mtx::responses::Sync &sync_); VerificationManager *verificationManager() { return verificationManager_; } @@ -113,6 +119,7 @@ signals: QString url, double originalWidth, double proportionalHeight); + void ignoredUsersChanged(const QVector<QString> &ignoredUsers); public slots: void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids); @@ -154,4 +161,6 @@ private: QHash<QPair<QString, quint64>, QColor> userColors; inline static TimelineViewManager *instance_ = nullptr; + + void processIgnoredUsers(const mtx::responses::AccountData &data); }; diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 80def409..338f3658 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -11,11 +11,11 @@ #include "Cache_p.h" #include "ChatPage.h" #include "Logging.h" +#include "MainWindow.h" +#include "MatrixClient.h" #include "UserProfile.h" #include "Utils.h" -#include "encryption/DeviceVerificationFlow.h" #include "encryption/VerificationManager.h" -#include "mtx/responses/crypto.hpp" #include "timeline/TimelineModel.h" #include "timeline/TimelineViewManager.h" #include "ui/UIA.h" @@ -64,6 +64,19 @@ UserProfile::UserProfile(const QString &roomid, new RoomInfoModel(cache::client()->getCommonRooms(userid.toStdString()), this); else sharedRooms_ = new RoomInfoModel({}, this); + + connect(ChatPage::instance(), &ChatPage::syncUI, this, [this](const mtx::responses::Sync &res) { + if (auto ignoreEv = std::ranges::find_if( + res.account_data.events, + [](const mtx::events::collections::RoomAccountDataEvents &e) { + return std::holds_alternative< + mtx::events::AccountDataEvent<mtx::events::account_data::IgnoredUsers>>(e); + }); + ignoreEv != res.account_data.events.end()) { + // doesn't matter much if it was actually us + emit ignoredChanged(); + } + }); } QHash<int, QByteArray> @@ -224,6 +237,49 @@ UserProfile::refreshDevices() fetchDeviceList(this->userid_); } +bool +UserProfile::ignored() const +{ + auto old = TimelineViewManager::instance()->getIgnoredUsers(); + return old.contains(userid_); +} + +void +UserProfile::setIgnored(bool ignore) +{ + auto old = TimelineViewManager::instance()->getIgnoredUsers(); + if (ignore) { + if (old.contains(userid_)) { + emit ignoredChanged(); + return; + } + old.append(userid_); + } else { + if (!old.contains(userid_)) { + emit ignoredChanged(); + return; + } + old.removeAll(userid_); + } + + std::vector<mtx::events::account_data::IgnoredUser> content; + for (const QString &item : std::as_const(old)) { + content.push_back({item.toStdString()}); + } + + mtx::events::account_data::IgnoredUsers payload{.users{content}}; + + auto userid = userid_; + + http::client()->put_account_data(payload, [userid](mtx::http::RequestErr e) { + if (e) { + MainWindow::instance()->showNotification( + tr("Failed to ignore \"%1\": %2") + .arg(userid, QString::fromStdString(e->matrix_error.error))); + } + }); +} + void UserProfile::fetchDeviceList(const QString &userID) { @@ -345,10 +401,6 @@ UserProfile::banUser() ChatPage::instance()->banUser(roomid_, this->userid_, QLatin1String("")); } -// void ignoreUser(){ - -// } - void UserProfile::kickUser() { diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index d8e06aa1..bc5b6a35 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -157,6 +157,7 @@ class UserProfile final : public QObject Q_PROPERTY(int userVerified READ getUserStatus NOTIFY userStatusChanged) Q_PROPERTY(bool isLoading READ isLoading NOTIFY loadingChanged) Q_PROPERTY(bool userVerificationEnabled READ userVerificationEnabled NOTIFY userStatusChanged) + Q_PROPERTY(bool ignored READ ignored WRITE setIgnored NOTIFY ignoredChanged) Q_PROPERTY(bool isSelf READ isSelf CONSTANT) Q_PROPERTY(TimelineModel *room READ room CONSTANT) public: @@ -184,7 +185,6 @@ public: Q_INVOKABLE void refreshDevices(); Q_INVOKABLE void banUser(); Q_INVOKABLE void signOutDevice(const QString &deviceID); - // Q_INVOKABLE void ignoreUser(); Q_INVOKABLE void kickUser(); Q_INVOKABLE void startChat(); Q_INVOKABLE void startChat(bool encryptionEnabled); @@ -193,6 +193,9 @@ public: Q_INVOKABLE void changeAvatar(); Q_INVOKABLE void openGlobalProfile(); + void setIgnored(bool ignored); + bool ignored() const; + signals: void userStatusChanged(); void loadingChanged(); @@ -201,6 +204,7 @@ signals: void displayError(const QString &errorMessage); void globalUsernameRetrieved(const QString &globalUser); void devicesChanged(); + void ignoredChanged(); // internal void verificationStatiChanged(); |