diff --git a/CMakeLists.txt b/CMakeLists.txt
index f4706a2e883bb2a744c46ef212802cc3887577fa..4c7a9ccdc3410e36f35a3afaac3ce7469766b991 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -332,6 +332,7 @@ set(SRC_FILES
 	src/timeline/RoomlistModel.cpp
 
 	# UI components
+	src/ui/HiddenEvents.cpp
 	src/ui/MxcAnimatedImage.cpp
 	src/ui/MxcMediaProxy.cpp
 	src/ui/NhekoCursorShape.cpp
@@ -403,7 +404,7 @@ if(USE_BUNDLED_MTXCLIENT)
 	FetchContent_Declare(
 		MatrixClient
 		GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
-		GIT_TAG        8c03d9ac58274695a71d0eb32519ebce29bc536e
+		GIT_TAG        31a703c9febdfcaaf4e8a74abd424b6fc462e573
 		)
 	set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
 	set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
@@ -527,6 +528,7 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/timeline/RoomlistModel.h
 
 	# UI components
+	src/ui/HiddenEvents.h
 	src/ui/MxcAnimatedImage.h
 	src/ui/MxcMediaProxy.h
 	src/ui/NhekoCursorShape.h
diff --git a/io.github.NhekoReborn.Nheko.yaml b/io.github.NhekoReborn.Nheko.yaml
index dec139873e8c27118c806fcb7df6273ba29c1cf8..04298bcb9945ff07e18f1fe941e879ea37e851cc 100644
--- a/io.github.NhekoReborn.Nheko.yaml
+++ b/io.github.NhekoReborn.Nheko.yaml
@@ -191,7 +191,7 @@ modules:
     buildsystem: cmake-ninja
     name: mtxclient
     sources:
-      - commit: 8c03d9ac58274695a71d0eb32519ebce29bc536e
+      - commit: 31a703c9febdfcaaf4e8a74abd424b6fc462e573
         #tag: v0.6.1
         type: git
         url: https://github.com/Nheko-Reborn/mtxclient.git
diff --git a/resources/qml/dialogs/HiddenEventsDialog.qml b/resources/qml/dialogs/HiddenEventsDialog.qml
new file mode 100644
index 0000000000000000000000000000000000000000..cc6f17a53af69e44f0a0c37c013a42e5e4505c0c
--- /dev/null
+++ b/resources/qml/dialogs/HiddenEventsDialog.qml
@@ -0,0 +1,127 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import ".."
+import QtQuick 2.12
+import QtQuick.Controls 2.5
+import QtQuick.Layouts 1.3
+import im.nheko 1.0
+
+ApplicationWindow {
+    id: hiddenEventsDialog
+
+    property string roomid: ""
+    property string roomName: ""
+    property var onAccepted: undefined
+
+    modality: Qt.NonModal
+    flags: Qt.Dialog | Qt.WindowTitleHint
+    minimumWidth: 250
+    minimumHeight: 220
+
+    HiddenEvents {
+        id: hiddenEvents
+
+        roomid: hiddenEventsDialog.roomid
+    }
+
+    title: {
+        if (roomid) {
+            return qsTr("Hidden events for %1").arg(roomName);
+        }
+        else {
+            return qsTr("Hidden events");
+        }
+    }
+
+    Shortcut {
+        sequence: StandardKey.Cancel
+        onActivated: dbb.rejected()
+    }
+
+    ColumnLayout {
+        spacing: Nheko.paddingMedium
+        anchors.margins: Nheko.paddingMedium
+        anchors.fill: parent
+
+        MatrixText {
+            id: promptLabel
+            text: {
+                if (roomid) {
+                    return qsTr("These events will be be <b>shown</b> in %1:").arg(roomName);
+                }
+                else {
+                    return qsTr("These events will be be <b>shown</b> in all rooms:");
+                }
+            }
+            font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.2)
+            Layout.fillWidth: true
+            Layout.fillHeight: false
+        }
+
+        GridLayout {
+            columns: 2
+            rowSpacing: Nheko.paddingMedium
+            Layout.fillWidth: true
+            Layout.fillHeight: true
+
+            MatrixText {
+                text: qsTr("User events")
+                ToolTip.text: qsTr("Joins, leaves, avatar and name changes, bans, …")
+                ToolTip.visible: hh1.hovered
+                Layout.fillWidth: true
+
+                HoverHandler {
+                    id: hh1
+                }
+            }
+
+            ToggleButton {
+                Layout.alignment: Qt.AlignRight
+                checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.Member)
+                onToggled: hiddenEvents.toggle(MtxEvent.Member)
+            }
+
+            MatrixText {
+                text: qsTr("Power level changes")
+                ToolTip.text: qsTr("Sent when a moderator is added/removed or the permissions of a room are changed.")
+                ToolTip.visible: hh2.hovered
+                Layout.fillWidth: true
+
+                HoverHandler {
+                    id: hh2
+                }
+            }
+
+            ToggleButton {
+                Layout.alignment: Qt.AlignRight
+                checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.PowerLevels)
+                onToggled: hiddenEvents.toggle(MtxEvent.PowerLevels)
+            }
+
+            MatrixText {
+                text: qsTr("Stickers")
+                Layout.fillWidth: true
+            }
+
+            ToggleButton {
+                Layout.alignment: Qt.AlignRight
+                checked: !hiddenEvents.hiddenEvents.includes(MtxEvent.Sticker)
+                onToggled: hiddenEvents.toggle(MtxEvent.Sticker)
+            }
+        }
+    }
+
+    footer: DialogButtonBox {
+        id: dbb
+
+        standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
+        onAccepted: {
+            hiddenEvents.save();
+            hiddenEventsDialog.close();
+        }
+        onRejected: hiddenEventsDialog.close();
+    }
+
+}
diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml
index fad7b4c7586061fc45881e5b15292dc254541f6e..442010fddf2caecbc0f006fe2426779aff3eb400 100644
--- a/resources/qml/dialogs/RoomSettings.qml
+++ b/resources/qml/dialogs/RoomSettings.qml
@@ -254,6 +254,23 @@ ApplicationWindow {
                 Layout.alignment: Qt.AlignRight
             }
 
+            MatrixText {
+                text: qsTr("Hidden events")
+            }
+
+            HiddenEventsDialog {
+                id: hiddenEventsDialog
+                roomid: roomSettings.roomId
+                roomName: roomSettings.roomName
+            }
+
+            Button {
+                text: qsTr("Configure")
+                ToolTip.text: qsTr("Select events to hide in this room")
+                onClicked: hiddenEventsDialog.show()
+                Layout.alignment: Qt.AlignRight
+            }
+
             Item {
                 // for adding extra space between sections
                 Layout.fillWidth: true
@@ -302,5 +319,4 @@ ApplicationWindow {
         }
 
     }
-
 }
diff --git a/resources/res.qrc b/resources/res.qrc
index 2fba5f4cc0c5caa20d8533b5241c4c1703eec0ff..c865915094064484f236ab16953e5f110b12de60 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -152,6 +152,7 @@
         <file>qml/dialogs/RoomMembers.qml</file>
         <file>qml/dialogs/RoomSettings.qml</file>
         <file>qml/dialogs/UserProfile.qml</file>
+        <file>qml/dialogs/HiddenEventsDialog.qml</file>
         <file>qml/emoji/EmojiPicker.qml</file>
         <file>qml/emoji/StickerPicker.qml</file>
         <file>qml/ui/NhekoSlider.qml</file>
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 9f3ada58a487d6ffff058e01d28b6e5f4c2fc425..6bad336a34e80fb0f7d4ec827c4476d3fb618ef3 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -173,24 +173,31 @@ Cache::isHiddenEvent(lmdb::txn &txn,
     }
 
     mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
-    hiddenEvents.hidden_event_types = {
-      EventType::Reaction, EventType::CallCandidates, EventType::Unsupported};
-
-    if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, ""))
-        hiddenEvents =
-          std::move(std::get<mtx::events::AccountDataEvent<
-                      mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp)
-                      .content);
-    if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id))
-        hiddenEvents =
-          std::move(std::get<mtx::events::AccountDataEvent<
-                      mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp)
-                      .content);
+    hiddenEvents.hidden_event_types = std::vector{
+      EventType::Reaction,
+      EventType::CallCandidates,
+      EventType::Unsupported,
+    };
+
+    if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, "")) {
+        auto h = std::get<
+          mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
+          *temp);
+        if (h.content.hidden_event_types)
+            hiddenEvents = std::move(h.content);
+    }
+    if (auto temp = getAccountData(txn, mtx::events::EventType::NhekoHiddenEvents, room_id)) {
+        auto h = std::get<
+          mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
+          *temp);
+        if (h.content.hidden_event_types)
+            hiddenEvents = std::move(h.content);
+    }
 
     return std::visit(
       [hiddenEvents](const auto &ev) {
-          return std::any_of(hiddenEvents.hidden_event_types.begin(),
-                             hiddenEvents.hidden_event_types.end(),
+          return std::any_of(hiddenEvents.hidden_event_types->begin(),
+                             hiddenEvents.hidden_event_types->end(),
                              [ev](EventType type) { return type == ev.type; });
       },
       e);
@@ -1515,6 +1522,16 @@ Cache::saveState(const mtx::responses::Sync &res)
         for (const auto &ev : res.account_data.events)
             std::visit(
               [&txn, &accountDataDb](const auto &event) {
+                  if constexpr (std::is_same_v<
+                                  std::remove_cv_t<std::remove_reference_t<decltype(event)>>,
+                                  AccountDataEvent<
+                                    mtx::events::account_data::nheko_extensions::HiddenEvents>>) {
+                      if (!event.content.hidden_event_types) {
+                          accountDataDb.del(txn, "im.nheko.hidden_events");
+                          return;
+                      }
+                  }
+
                   auto j = json(event);
                   accountDataDb.put(txn, j["type"].get<std::string>(), j.dump());
               },
@@ -1589,6 +1606,15 @@ Cache::saveState(const mtx::responses::Sync &res)
             for (const auto &evt : room.second.account_data.events) {
                 std::visit(
                   [&txn, &accountDataDb](const auto &event) {
+                      if constexpr (std::is_same_v<
+                                      std::remove_cv_t<std::remove_reference_t<decltype(event)>>,
+                                      AccountDataEvent<mtx::events::account_data::nheko_extensions::
+                                                         HiddenEvents>>) {
+                          if (!event.content.hidden_event_types) {
+                              accountDataDb.del(txn, "im.nheko.hidden_events");
+                              return;
+                          }
+                      }
                       auto j = json(event);
                       accountDataDb.put(txn, j["type"].get<std::string>(), j.dump());
                   },
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 83504d866a4bc3e11c58a022a8f14e3893a73af7..01a058910eac8a1907ca29dc9c2deb2c315950f9 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -44,6 +44,7 @@
 #include "encryption/SelfVerificationStatus.h"
 #include "timeline/DelegateChooser.h"
 #include "timeline/TimelineViewManager.h"
+#include "ui/HiddenEvents.h"
 #include "ui/MxcAnimatedImage.h"
 #include "ui/MxcMediaProxy.h"
 #include "ui/NhekoCursorShape.h"
@@ -168,6 +169,7 @@ MainWindow::registerQmlTypes()
     qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
     qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
     qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
+    qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
     qmlRegisterUncreatableType<DeviceVerificationFlow>(
       "im.nheko",
       1,
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index c7aa0fa281e9c4abdf8ad073bb7c4094fbb967f7..662bbb38c57ea78ab807ec5ba8a93a0fa7b4b134 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -50,59 +50,7 @@ struct RoomEventType
     template<class T>
     qml_mtx_events::EventType operator()(const mtx::events::Event<T> &e)
     {
-        using mtx::events::EventType;
-        switch (e.type) {
-        case EventType::RoomKeyRequest:
-            return qml_mtx_events::EventType::KeyRequest;
-        case EventType::Reaction:
-            return qml_mtx_events::EventType::Reaction;
-        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::RoomCreate;
-        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::RoomGuestAccess;
-        case EventType::RoomHistoryVisibility:
-            return qml_mtx_events::EventType::RoomHistoryVisibility;
-        case EventType::RoomJoinRules:
-            return qml_mtx_events::EventType::RoomJoinRules;
-        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::SpaceParent:
-            return qml_mtx_events::EventType::SpaceParent;
-        case EventType::SpaceChild:
-            return qml_mtx_events::EventType::SpaceChild;
-        case EventType::Unsupported:
-            return qml_mtx_events::EventType::Unsupported;
-        default:
-            return qml_mtx_events::EventType::UnknownMessage;
-        }
+        return qml_mtx_events::toRoomEventType(e.type);
     }
     qml_mtx_events::EventType operator()(const mtx::events::Event<mtx::events::msg::Audio> &)
     {
@@ -198,6 +146,64 @@ struct RoomEventType
 };
 }
 
+qml_mtx_events::EventType
+qml_mtx_events::toRoomEventType(mtx::events::EventType e)
+{
+    using mtx::events::EventType;
+    switch (e) {
+    case EventType::RoomKeyRequest:
+        return qml_mtx_events::EventType::KeyRequest;
+    case EventType::Reaction:
+        return qml_mtx_events::EventType::Reaction;
+    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::RoomCreate;
+    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::RoomGuestAccess;
+    case EventType::RoomHistoryVisibility:
+        return qml_mtx_events::EventType::RoomHistoryVisibility;
+    case EventType::RoomJoinRules:
+        return qml_mtx_events::EventType::RoomJoinRules;
+    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::SpaceParent:
+        return qml_mtx_events::EventType::SpaceParent;
+    case EventType::SpaceChild:
+        return qml_mtx_events::EventType::SpaceChild;
+    case EventType::Unsupported:
+        return qml_mtx_events::EventType::Unsupported;
+    default:
+        return qml_mtx_events::EventType::UnknownMessage;
+    }
+}
+
 qml_mtx_events::EventType
 toRoomEventType(const mtx::events::collections::TimelineEvents &event)
 {
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index f6cc1e6bcf6e1ed329b86b0e58bb217ca5f0b0c0..6cdff285de4b66248edfbe4f4098852b35e7d982 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -125,6 +125,8 @@ enum EventType
 };
 Q_ENUM_NS(EventType)
 mtx::events::EventType fromRoomEventType(qml_mtx_events::EventType);
+qml_mtx_events::EventType
+toRoomEventType(mtx::events::EventType e);
 
 enum EventState
 {
diff --git a/src/ui/HiddenEvents.cpp b/src/ui/HiddenEvents.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a8da812ebaf3887ac445e49bcc709a8029292de0
--- /dev/null
+++ b/src/ui/HiddenEvents.cpp
@@ -0,0 +1,93 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "HiddenEvents.h"
+
+#include "Cache_p.h"
+#include "MainWindow.h"
+#include "MatrixClient.h"
+
+void
+HiddenEvents::load()
+{
+    using namespace mtx::events;
+    mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
+    hiddenEvents.hidden_event_types = std::vector{
+      EventType::Reaction,
+      EventType::CallCandidates,
+      EventType::Unsupported,
+    };
+
+    if (auto temp =
+          cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents, "")) {
+        auto h = std::get<
+          mtx::events::AccountDataEvent<mtx::events::account_data::nheko_extensions::HiddenEvents>>(
+          *temp);
+        if (h.content.hidden_event_types)
+            hiddenEvents = std::move(h.content);
+    }
+
+    if (!roomid_.isEmpty()) {
+        if (auto temp = cache::client()->getAccountData(mtx::events::EventType::NhekoHiddenEvents,
+                                                        roomid_.toStdString())) {
+            auto h = std::get<mtx::events::AccountDataEvent<
+              mtx::events::account_data::nheko_extensions::HiddenEvents>>(*temp);
+            if (h.content.hidden_event_types)
+                hiddenEvents = std::move(h.content);
+        }
+    }
+
+    hiddenEvents_.clear();
+    hiddenEvents_ = std::move(hiddenEvents.hidden_event_types.value());
+    emit hiddenEventsChanged();
+}
+
+Q_INVOKABLE void
+HiddenEvents::toggle(int type)
+{
+    auto t = qml_mtx_events::fromRoomEventType(static_cast<qml_mtx_events::EventType>(type));
+    if (auto it = std::find(begin(hiddenEvents_), end(hiddenEvents_), t); it != end(hiddenEvents_))
+        hiddenEvents_.erase(it);
+    else
+        hiddenEvents_.push_back(t);
+    emit hiddenEventsChanged();
+}
+
+QVariantList
+HiddenEvents::hiddenEvents() const
+{
+    QVariantList l;
+    for (const auto &e : hiddenEvents_) {
+        l.push_back(qml_mtx_events::toRoomEventType(e));
+    }
+
+    return l;
+}
+
+void
+HiddenEvents::save()
+{
+    mtx::events::account_data::nheko_extensions::HiddenEvents hiddenEvents;
+    hiddenEvents.hidden_event_types = hiddenEvents_;
+
+    if (roomid_.isEmpty())
+        http::client()->put_account_data(hiddenEvents, [](mtx::http::RequestErr e) {
+            if (e) {
+                nhlog::net()->error("Failed to set hidden events: {}", *e);
+                MainWindow::instance()->showNotification(
+                  tr("Failed to set hidden events: %1")
+                    .arg(QString::fromStdString(e->matrix_error.error)));
+            }
+        });
+    else
+        http::client()->put_room_account_data(
+          roomid_.toStdString(), hiddenEvents, [](mtx::http::RequestErr e) {
+              if (e) {
+                  nhlog::net()->error("Failed to set hidden events: {}", *e);
+                  MainWindow::instance()->showNotification(
+                    tr("Failed to set hidden events: %1")
+                      .arg(QString::fromStdString(e->matrix_error.error)));
+              }
+          });
+}
diff --git a/src/ui/HiddenEvents.h b/src/ui/HiddenEvents.h
new file mode 100644
index 0000000000000000000000000000000000000000..928b14ba3c5d07a8a076d9ba4c767a3639eafe39
--- /dev/null
+++ b/src/ui/HiddenEvents.h
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2022 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <QObject>
+#include <QString>
+#include <QVariantList>
+
+#include "timeline/TimelineModel.h"
+
+class HiddenEvents : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged REQUIRED)
+    Q_PROPERTY(QVariantList hiddenEvents READ hiddenEvents NOTIFY hiddenEventsChanged)
+public:
+    explicit HiddenEvents(QObject *p = nullptr)
+      : QObject(p)
+    {}
+
+    Q_INVOKABLE void toggle(int type);
+    Q_INVOKABLE void save();
+
+    [[nodiscard]] QString roomid() const { return roomid_; }
+    void setRoomid(const QString &r)
+    {
+        roomid_ = r;
+        emit roomidChanged();
+
+        load();
+    }
+
+    [[nodiscard]] QVariantList hiddenEvents() const;
+
+signals:
+    void roomidChanged();
+    void hiddenEventsChanged();
+
+private:
+    QString roomid_;
+    std::vector<mtx::events::EventType> hiddenEvents_;
+
+    void load();
+};
diff --git a/src/ui/RoomSettings.cpp b/src/ui/RoomSettings.cpp
index 5407edee307f10c9a6a31b1ccb19c7ae84bdf1fa..43a11b7f92d38047f05ddf9b40019da62e27225b 100644
--- a/src/ui/RoomSettings.cpp
+++ b/src/ui/RoomSettings.cpp
@@ -12,10 +12,13 @@
 #include <QMimeDatabase>
 #include <QStandardPaths>
 #include <QVBoxLayout>
+#include <mtx/events/event_type.hpp>
 #include <mtx/responses/common.hpp>
 #include <mtx/responses/media.hpp>
+#include <mtxclient/http/client.hpp>
 
 #include "Cache.h"
+#include "Cache_p.h"
 #include "Config.h"
 #include "Logging.h"
 #include "MatrixClient.h"
diff --git a/src/ui/RoomSettings.h b/src/ui/RoomSettings.h
index 75b7bae067beba75c88defe120c51ef96ea2ee05..f79aa3f7618e6ba34d3c785bcd15d4fa6450eaa0 100644
--- a/src/ui/RoomSettings.h
+++ b/src/ui/RoomSettings.h
@@ -8,8 +8,10 @@
 #include <QLabel>
 #include <QObject>
 #include <QPushButton>
+#include <QSet>
 #include <QString>
 
+#include <mtx/events/event_type.hpp>
 #include <mtx/events/guest_access.hpp>
 
 #include "CacheStructs.h"