diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8b43559f5fb8687cdd8d121b8de0a4973b13517c..5a5e3ba142dedca563706c3ac94a1d2f584f85fb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -311,8 +311,6 @@ set(SRC_FILES
 	src/ChatPage.cpp
 	src/Clipboard.cpp
 	src/ColorImageProvider.cpp
-	src/CommunitiesList.cpp
-	src/CommunitiesListItem.cpp
 	src/CompletionProxyModel.cpp
 	src/DeviceVerificationFlow.cpp
 	src/EventAccessors.cpp
@@ -324,22 +322,14 @@ set(SRC_FILES
 	src/MxcImageProvider.cpp
 	src/Olm.cpp
 	src/RegisterPage.cpp
-	src/RoomInfoListItem.cpp
-	src/RoomList.cpp
 	src/SSOHandler.cpp
-	src/SideBarActions.cpp
-	src/Splitter.cpp
 	src/TrayIcon.cpp
-	src/UserInfoWidget.cpp
 	src/UserSettingsPage.cpp
 	src/UsersModel.cpp
 	src/RoomsModel.cpp
 	src/Utils.cpp
 	src/WebRTCSession.cpp
 	src/WelcomePage.cpp
-	src/popups/PopupItem.cpp
-	src/popups/SuggestionsPopup.cpp
-	src/popups/UserMentions.cpp
 	src/main.cpp
 
 	third_party/blurhash/blurhash.cpp
@@ -535,8 +525,6 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/CallManager.h
 	src/ChatPage.h
 	src/Clipboard.h
-	src/CommunitiesList.h
-	src/CommunitiesListItem.h
 	src/CompletionProxyModel.h
 	src/DeviceVerificationFlow.h
 	src/InviteeItem.h
@@ -544,21 +532,13 @@ qt5_wrap_cpp(MOC_HEADERS
 	src/MainWindow.h
 	src/MxcImageProvider.h
 	src/RegisterPage.h
-	src/RoomInfoListItem.h
-	src/RoomList.h
 	src/SSOHandler.h
-	src/SideBarActions.h
-	src/Splitter.h
 	src/TrayIcon.h
-	src/UserInfoWidget.h
 	src/UserSettingsPage.h
 	src/UsersModel.h
 	src/RoomsModel.h
 	src/WebRTCSession.h
 	src/WelcomePage.h
-	src/popups/PopupItem.h
-	src/popups/SuggestionsPopup.h
-	src/popups/UserMentions.h
 	)
 
 #
diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml
index a8b6fa52bb49444af9cd46d4bc6459a54f02bf12..c23ab97d99e4d0b2ecbffe3ae7bd0f110fd058f3 100644
--- a/resources/qml/Root.qml
+++ b/resources/qml/Root.qml
@@ -72,6 +72,15 @@ Page {
         }
     }
 
+    Shortcut {
+        sequence: "Ctrl+Down"
+        onActivated: Rooms.nextRoom();
+    }
+    Shortcut {
+        sequence: "Ctrl+Up"
+        onActivated: Rooms.previousRoom();
+    }
+
     Component {
         id: deviceVerificationDialog
 
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index bee20d60f554dfd16b3f50e8982310b7fb271c05..4ad7bd1449e8dfb24c4ea0fdb882b04717c606a8 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -23,10 +23,6 @@
 #include "MainWindow.h"
 #include "MatrixClient.h"
 #include "Olm.h"
-#include "RoomList.h"
-#include "SideBarActions.h"
-#include "Splitter.h"
-#include "UserInfoWidget.h"
 #include "UserSettingsPage.h"
 #include "Utils.h"
 #include "ui/OverlayModal.h"
@@ -36,7 +32,6 @@
 #include "notifications/Manager.h"
 
 #include "dialogs/ReadReceipts.h"
-#include "popups/UserMentions.h"
 #include "timeline/TimelineViewManager.h"
 
 #include "blurhash.hpp"
@@ -76,62 +71,9 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         topLayout_->setSpacing(0);
         topLayout_->setMargin(0);
 
-        communitiesList_ = new CommunitiesList(this);
-        topLayout_->addWidget(communitiesList_);
-
-        splitter = new Splitter(this);
-        splitter->setHandleWidth(0);
-
-        topLayout_->addWidget(splitter);
-
-        // SideBar
-        sideBar_ = new QFrame(this);
-        sideBar_->setObjectName("sideBar");
-        sideBar_->setMinimumWidth(::splitter::calculateSidebarSizes(QFont{}).normal);
-        sideBarLayout_ = new QVBoxLayout(sideBar_);
-        sideBarLayout_->setSpacing(0);
-        sideBarLayout_->setMargin(0);
-
-        sideBarTopWidget_ = new QWidget(sideBar_);
-        sidebarActions_   = new SideBarActions(this);
-        connect(
-          sidebarActions_, &SideBarActions::showSettings, this, &ChatPage::showUserSettingsPage);
-        connect(sidebarActions_, &SideBarActions::joinRoom, this, &ChatPage::joinRoom);
-        connect(sidebarActions_, &SideBarActions::createRoom, this, &ChatPage::createRoom);
-
-        user_info_widget_ = new UserInfoWidget(sideBar_);
-        connect(user_info_widget_, &UserInfoWidget::openGlobalUserProfile, this, [this]() {
-                UserProfile *userProfile = new UserProfile("", utils::localUser(), view_manager_);
-                emit view_manager_->openProfile(userProfile);
-        });
-
-        user_mentions_popup_ = new popups::UserMentions();
-        room_list_           = new RoomList(userSettings, sideBar_);
-        connect(room_list_, &RoomList::joinRoom, this, &ChatPage::joinRoom);
-
-        sideBarLayout_->addWidget(user_info_widget_);
-        sideBarLayout_->addWidget(room_list_);
-        sideBarLayout_->addWidget(sidebarActions_);
-
-        sideBarTopWidgetLayout_ = new QVBoxLayout(sideBarTopWidget_);
-        sideBarTopWidgetLayout_->setSpacing(0);
-        sideBarTopWidgetLayout_->setMargin(0);
-
-        // Content
-        content_ = new QFrame(this);
-        content_->setObjectName("mainContent");
-        contentLayout_ = new QVBoxLayout(content_);
-        contentLayout_->setSpacing(0);
-        contentLayout_->setMargin(0);
-
         view_manager_ = new TimelineViewManager(callManager_, this);
 
-        contentLayout_->addWidget(view_manager_->getWidget());
-
-        // Splitter
-        splitter->addWidget(sideBar_);
-        splitter->addWidget(content_);
-        splitter->restoreSizes(parent->width());
+        topLayout_->addWidget(view_manager_->getWidget());
 
         connect(this,
                 &ChatPage::downloadedSecrets,
@@ -153,17 +95,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                 trySync();
         });
 
-        connect(
-          new QShortcut(QKeySequence("Ctrl+Down"), this), &QShortcut::activated, this, [this]() {
-                  if (isVisible())
-                          room_list_->nextRoom();
-          });
-        connect(
-          new QShortcut(QKeySequence("Ctrl+Up"), this), &QShortcut::activated, this, [this]() {
-                  if (isVisible())
-                          room_list_->previousRoom();
-          });
-
         connectivityTimer_.setInterval(CHECK_CONNECTIVITY_INTERVAL);
         connect(&connectivityTimer_, &QTimer::timeout, this, [=]() {
                 if (http::client()->access_token().empty()) {
@@ -185,10 +116,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
 
         connect(this, &ChatPage::loggedOut, this, &ChatPage::logout);
 
-        connect(
-          view_manager_, &TimelineViewManager::showRoomList, splitter, &Splitter::showFullRoomList);
         connect(view_manager_, &TimelineViewManager::inviteUsers, this, [this](QStringList users) {
-                const auto room_id = current_room_.toStdString();
+                const auto room_id = currentRoom().toStdString();
 
                 for (int ii = 0; ii < users.size(); ++ii) {
                         QTimer::singleShot(ii * 500, this, [this, room_id, ii, users]() {
@@ -211,29 +140,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                 }
         });
 
-        connect(room_list_, &RoomList::roomChanged, this, [this](QString room_id) {
-                this->current_room_ = room_id;
-        });
-        connect(room_list_, &RoomList::roomChanged, splitter, &Splitter::showChatView);
-
-        connect(room_list_, &RoomList::acceptInvite, this, [this](const QString &room_id) {
-                joinRoom(room_id);
-                room_list_->removeRoom(room_id, currentRoom() == room_id);
-        });
-
-        connect(room_list_, &RoomList::declineInvite, this, [this](const QString &room_id) {
-                leaveRoom(room_id);
-                room_list_->removeRoom(room_id, currentRoom() == room_id);
-        });
-
-        connect(view_manager_,
-                &TimelineViewManager::updateRoomsLastMessage,
-                room_list_,
-                &RoomList::updateRoomDescription);
-
-        connect(
-          this, &ChatPage::updateGroupsInfo, communitiesList_, &CommunitiesList::setCommunities);
-
         connect(this, &ChatPage::leftRoom, this, &ChatPage::removeRoom);
         connect(this, &ChatPage::newRoom, this, &ChatPage::changeRoom, Qt::QueuedConnection);
         connect(this, &ChatPage::notificationsRetrieved, this, &ChatPage::sendNotifications);
@@ -248,60 +154,23 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                         }
                 });
 
-        connect(communitiesList_,
-                &CommunitiesList::communityChanged,
-                this,
-                [this](const QString &groupId) {
-                        current_community_ = groupId;
-
-                        if (groupId == "world") {
-                                auto hidden = communitiesList_->hiddenTagsAndCommunities();
-                                std::set<QString> roomsToHide = communitiesList_->roomList(groupId);
-                                for (const auto &hiddenTag : hidden) {
-                                        auto temp = communitiesList_->roomList(hiddenTag);
-                                        roomsToHide.insert(temp.begin(), temp.end());
-                                }
-
-                                room_list_->removeFilter(roomsToHide);
-                        } else {
-                                auto hidden = communitiesList_->hiddenTagsAndCommunities();
-                                hidden.erase(current_community_);
-
-                                auto roomsToShow = communitiesList_->roomList(groupId);
-                                for (const auto &hiddenTag : hidden) {
-                                        for (const auto &r : communitiesList_->roomList(hiddenTag))
-                                                roomsToShow.erase(r);
-                                }
-
-                                room_list_->applyFilter(roomsToShow);
-                        }
-                });
-
         connect(&notificationsManager,
                 &NotificationsManager::notificationClicked,
                 this,
                 [this](const QString &roomid, const QString &eventid) {
                         Q_UNUSED(eventid)
-                        room_list_->highlightSelectedRoom(roomid);
+                        view_manager_->rooms()->setCurrentRoom(roomid);
                         activateWindow();
                 });
         connect(&notificationsManager,
                 &NotificationsManager::sendNotificationReply,
                 this,
                 [this](const QString &roomid, const QString &eventid, const QString &body) {
+                        view_manager_->rooms()->setCurrentRoom(roomid);
                         view_manager_->queueReply(roomid, eventid, body);
-                        room_list_->highlightSelectedRoom(roomid);
                         activateWindow();
                 });
 
-        setGroupViewState(userSettings_->groupView());
-
-        connect(userSettings_.data(),
-                &UserSettings::groupViewStateChanged,
-                this,
-                &ChatPage::setGroupViewState);
-
-        connect(this, &ChatPage::initializeRoomList, room_list_, &RoomList::initialize);
         connect(
           this,
           &ChatPage::initializeViews,
@@ -312,30 +181,13 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                 &ChatPage::initializeEmptyViews,
                 view_manager_,
                 &TimelineViewManager::initializeRoomlist);
-        connect(this,
-                &ChatPage::initializeMentions,
-                user_mentions_popup_,
-                &popups::UserMentions::initializeMentions);
         connect(
           this, &ChatPage::chatFocusChanged, view_manager_, &TimelineViewManager::chatFocusChanged);
         connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) {
-                try {
-                        room_list_->cleanupInvites(cache::invites());
-                } catch (const lmdb::error &e) {
-                        nhlog::db()->error("failed to retrieve invites: {}", e.what());
-                }
-
                 view_manager_->sync(rooms);
-                removeLeftRooms(rooms.leave);
 
                 bool hasNotifications = false;
                 for (const auto &room : rooms.join) {
-                        auto room_id = QString::fromStdString(room.first);
-                        updateRoomNotificationCount(
-                          room_id,
-                          room.second.unread_notifications.notification_count,
-                          room.second.unread_notifications.highlight_count);
-
                         if (room.second.unread_notifications.notification_count > 0)
                                 hasNotifications = true;
                 }
@@ -358,16 +210,6 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
                                   emit notificationsRetrieved(std::move(res));
                           });
         });
-        connect(this, &ChatPage::syncRoomlist, room_list_, &RoomList::sync);
-        connect(this, &ChatPage::syncTags, communitiesList_, &CommunitiesList::syncTags);
-
-        // Callbacks to update the user info (top left corner of the page).
-        connect(this, &ChatPage::setUserAvatar, user_info_widget_, &UserInfoWidget::setAvatar);
-        connect(this, &ChatPage::setUserDisplayName, this, [this](const QString &name) {
-                auto userid = utils::localUser();
-                user_info_widget_->setUserId(userid);
-                user_info_widget_->setDisplayName(name);
-        });
 
         connect(
           this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync, Qt::QueuedConnection);
@@ -420,8 +262,6 @@ ChatPage::dropToLoginPage(const QString &msg)
 void
 ChatPage::resetUI()
 {
-        room_list_->clear();
-        user_info_widget_->reset();
         view_manager_->clearAll();
 
         emit unreadMessages(0);
@@ -474,9 +314,6 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
                         view_manager_,
                         &TimelineViewManager::updateReadReceipts);
 
-                connect(
-                  cache::client(), &Cache::roomReadStatus, room_list_, &RoomList::updateReadStatus);
-
                 connect(cache::client(),
                         &Cache::removeNotification,
                         &notificationsManager,
@@ -553,9 +390,7 @@ ChatPage::loadStateFromCache()
                 olm::client()->load(cache::restoreOlmAccount(), STORAGE_SECRET_KEY);
 
                 emit initializeEmptyViews();
-                emit initializeRoomList(cache::roomInfo());
                 emit initializeMentions(cache::getTimelineMentions());
-                emit syncTags(cache::roomInfo().toStdMap());
 
                 cache::calculateRoomReadStatus();
 
@@ -593,38 +428,6 @@ ChatPage::removeRoom(const QString &room_id)
                 nhlog::db()->critical("failure while removing room: {}", e.what());
                 // TODO: Notify the user.
         }
-
-        room_list_->removeRoom(room_id, room_id == current_room_);
-}
-
-void
-ChatPage::removeLeftRooms(const std::map<std::string, mtx::responses::LeftRoom> &rooms)
-{
-        for (auto it = rooms.cbegin(); it != rooms.cend(); ++it) {
-                const auto room_id = QString::fromStdString(it->first);
-                room_list_->removeRoom(room_id, room_id == current_room_);
-        }
-}
-
-void
-ChatPage::setGroupViewState(bool isEnabled)
-{
-        if (!isEnabled) {
-                communitiesList_->communityChanged("world");
-                communitiesList_->hide();
-
-                return;
-        }
-
-        communitiesList_->show();
-}
-
-void
-ChatPage::updateRoomNotificationCount(const QString &room_id,
-                                      uint16_t notification_count,
-                                      uint16_t highlight_count)
-{
-        room_list_->updateUnreadMessageCount(room_id, notification_count, highlight_count);
 }
 
 void
@@ -672,18 +475,6 @@ ChatPage::sendNotifications(const mtx::responses::Notifications &res)
         }
 }
 
-void
-ChatPage::showNotificationsDialog(const QPoint &widgetPos)
-{
-        auto notifDialog = user_mentions_popup_;
-
-        notifDialog->setGeometry(
-          widgetPos.x() - (width() / 10), widgetPos.y() + 25, width() / 5, height() / 2);
-
-        notifDialog->raise();
-        notifDialog->showPopup();
-}
-
 void
 ChatPage::tryInitialSync()
 {
@@ -782,11 +573,9 @@ ChatPage::startInitialSync()
                           olm::handle_to_device_messages(res.to_device.events);
 
                           emit initializeViews(std::move(res.rooms));
-                          emit initializeRoomList(cache::roomInfo());
                           emit initializeMentions(cache::getTimelineMentions());
 
                           cache::calculateRoomReadStatus();
-                          emit syncTags(cache::roomInfo().toStdMap());
                   } catch (const lmdb::error &e) {
                           nhlog::db()->error("failed to save state after initial sync: {}",
                                              e.what());
@@ -823,12 +612,8 @@ ChatPage::handleSyncResponse(const mtx::responses::Sync &res, const std::string
 
                 auto updates = cache::getRoomInfo(cache::client()->roomsWithStateUpdates(res));
 
-                emit syncRoomlist(updates);
-
                 emit syncUI(res.rooms);
 
-                emit syncTags(cache::getRoomInfo(cache::client()->roomsWithTagUpdates(res)));
-
                 // if we process a lot of syncs (1 every 200ms), this means we clean the
                 // db every 100s
                 static int syncCounter = 0;
@@ -932,7 +717,7 @@ ChatPage::joinRoomVia(const std::string &room_id,
                           emit showNotification(tr("Failed to remove invite: %1").arg(e.what()));
                   }
 
-                  room_list_->highlightSelectedRoom(QString::fromStdString(room_id));
+                  view_manager_->rooms()->setCurrentRoom(QString::fromStdString(room_id));
           });
 }
 
@@ -981,18 +766,17 @@ void
 ChatPage::changeRoom(const QString &room_id)
 {
         view_manager_->rooms()->setCurrentRoom(room_id);
-        room_list_->highlightSelectedRoom(room_id);
 }
 
 void
 ChatPage::inviteUser(QString userid, QString reason)
 {
-        auto room = current_room_;
+        auto room = currentRoom();
 
         if (QMessageBox::question(this,
                                   tr("Confirm invite"),
                                   tr("Do you really want to invite %1 (%2)?")
-                                    .arg(cache::displayName(current_room_, userid))
+                                    .arg(cache::displayName(room, userid))
                                     .arg(userid)) != QMessageBox::Yes)
                 return;
 
@@ -1014,12 +798,12 @@ ChatPage::inviteUser(QString userid, QString reason)
 void
 ChatPage::kickUser(QString userid, QString reason)
 {
-        auto room = current_room_;
+        auto room = currentRoom();
 
         if (QMessageBox::question(this,
                                   tr("Confirm kick"),
                                   tr("Do you really want to kick %1 (%2)?")
-                                    .arg(cache::displayName(current_room_, userid))
+                                    .arg(cache::displayName(room, userid))
                                     .arg(userid)) != QMessageBox::Yes)
                 return;
 
@@ -1041,12 +825,12 @@ ChatPage::kickUser(QString userid, QString reason)
 void
 ChatPage::banUser(QString userid, QString reason)
 {
-        auto room = current_room_;
+        auto room = currentRoom();
 
         if (QMessageBox::question(this,
                                   tr("Confirm ban"),
                                   tr("Do you really want to ban %1 (%2)?")
-                                    .arg(cache::displayName(current_room_, userid))
+                                    .arg(cache::displayName(room, userid))
                                     .arg(userid)) != QMessageBox::Yes)
                 return;
 
@@ -1068,12 +852,12 @@ ChatPage::banUser(QString userid, QString reason)
 void
 ChatPage::unbanUser(QString userid, QString reason)
 {
-        auto room = current_room_;
+        auto room = currentRoom();
 
         if (QMessageBox::question(this,
                                   tr("Confirm unban"),
                                   tr("Do you really want to unban %1 (%2)?")
-                                    .arg(cache::displayName(current_room_, userid))
+                                    .arg(cache::displayName(room, userid))
                                     .arg(userid)) != QMessageBox::Yes)
                 return;
 
@@ -1175,51 +959,6 @@ ChatPage::getProfileInfo()
 
                   emit setUserAvatar(QString::fromStdString(res.avatar_url));
           });
-
-        http::client()->joined_groups(
-          [this](const mtx::responses::JoinedGroups &res, mtx::http::RequestErr err) {
-                  if (err) {
-                          nhlog::net()->critical("failed to retrieve joined groups: {} {}",
-                                                 static_cast<int>(err->status_code),
-                                                 err->matrix_error.error);
-                          emit updateGroupsInfo({});
-                          return;
-                  }
-
-                  emit updateGroupsInfo(res);
-          });
-}
-
-void
-ChatPage::hideSideBars()
-{
-        // Don't hide side bar, if we are currently only showing the side bar!
-        if (view_manager_->getWidget()->isVisible()) {
-                communitiesList_->hide();
-                sideBar_->hide();
-        }
-        view_manager_->enableBackButton();
-}
-
-void
-ChatPage::showSideBars()
-{
-        if (userSettings_->groupView())
-                communitiesList_->show();
-
-        sideBar_->show();
-        view_manager_->disableBackButton();
-        content_->show();
-}
-
-uint64_t
-ChatPage::timelineWidth()
-{
-        int sidebarWidth = sideBar_->minimumSize().width();
-        sidebarWidth += communitiesList_->minimumSize().width();
-        nhlog::ui()->info("timelineWidth: {}", size().width() - sidebarWidth);
-
-        return size().width() - sidebarWidth;
 }
 
 void
@@ -1305,7 +1044,8 @@ ChatPage::startChat(QString userid)
                         if (std::find(room_members.begin(),
                                       room_members.end(),
                                       (userid).toStdString()) != room_members.end()) {
-                                room_list_->highlightSelectedRoom(QString::fromStdString(room_id));
+                                view_manager_->rooms()->setCurrentRoom(
+                                  QString::fromStdString(room_id));
                                 return;
                         }
                 }
@@ -1406,7 +1146,7 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
 
                 for (auto roomid : joined_rooms) {
                         if (roomid == targetRoomId) {
-                                room_list_->highlightSelectedRoom(mxid1);
+                                view_manager_->rooms()->setCurrentRoom(mxid1);
                                 if (!mxid2.isEmpty())
                                         view_manager_->showEvent(mxid1, mxid2);
                                 return;
@@ -1424,7 +1164,7 @@ ChatPage::handleMatrixUri(const QByteArray &uri)
                         auto aliases = cache::client()->getRoomAliases(roomid);
                         if (aliases) {
                                 if (aliases->alias == targetRoomAlias) {
-                                        room_list_->highlightSelectedRoom(
+                                        view_manager_->rooms()->setCurrentRoom(
                                           QString::fromStdString(roomid));
                                         if (!mxid2.isEmpty())
                                                 view_manager_->showEvent(
@@ -1446,8 +1186,17 @@ ChatPage::handleMatrixUri(const QUrl &uri)
         handleMatrixUri(uri.toString(QUrl::ComponentFormattingOption::FullyEncoded).toUtf8());
 }
 
-void
-ChatPage::highlightRoom(const QString &room_id)
+bool
+ChatPage::isRoomActive(const QString &room_id)
+{
+        return isActiveWindow() && currentRoom() == room_id;
+}
+
+QString
+ChatPage::currentRoom() const
 {
-        room_list_->highlightSelectedRoom(room_id);
+        if (view_manager_->rooms()->currentRoom())
+                return view_manager_->rooms()->currentRoom()->roomId();
+        else
+                return "";
 }
diff --git a/src/ChatPage.h b/src/ChatPage.h
index eb60047d4cb1cc5f5400a4ca8341effecd3d6a7c..751e70747f71ff8d90780e9523ef428c52d52b6d 100644
--- a/src/ChatPage.h
+++ b/src/ChatPage.h
@@ -27,15 +27,10 @@
 
 #include "CacheCryptoStructs.h"
 #include "CacheStructs.h"
-#include "CommunitiesList.h"
 #include "notifications/Manager.h"
 
 class OverlayModal;
-class RoomList;
-class SideBarActions;
-class Splitter;
 class TimelineViewManager;
-class UserInfoWidget;
 class UserSettings;
 class NotificationsManager;
 class TimelineModel;
@@ -53,11 +48,6 @@ struct Notifications;
 struct Sync;
 struct Timeline;
 struct Rooms;
-struct LeftRoom;
-}
-
-namespace popups {
-class UserMentions;
 }
 
 using SecretsToDecrypt = std::map<std::string, mtx::secret_storage::AesHmacSha2EncryptedData>;
@@ -71,7 +61,6 @@ public:
 
         // Initialize all the components of the UI.
         void bootstrap(QString userid, QString homeserver, QString token);
-        QString currentRoom() const { return current_room_; }
 
         static ChatPage *instance() { return instance_; }
 
@@ -80,14 +69,6 @@ public:
         TimelineViewManager *timelineManager() { return view_manager_; }
         void deleteConfigs();
 
-        CommunitiesList *communitiesList() { return communitiesList_; }
-
-        //! Calculate the width of the message timeline.
-        uint64_t timelineWidth();
-        //! Hide the room & group list (if it was visible).
-        void hideSideBars();
-        //! Show the room/group list (if it was visible).
-        void showSideBars();
         void initiateLogout();
 
         QString status() const;
@@ -95,6 +76,9 @@ public:
 
         mtx::presence::PresenceState currentPresence() const;
 
+        // TODO(Nico): Get rid of this!
+        QString currentRoom() const;
+
 public slots:
         void handleMatrixUri(const QByteArray &uri);
         void handleMatrixUri(const QUrl &uri);
@@ -102,7 +86,6 @@ public slots:
         void startChat(QString userid);
         void leaveRoom(const QString &room_id);
         void createRoom(const mtx::requests::CreateRoom &req);
-        void highlightRoom(const QString &room_id);
         void joinRoom(const QString &room);
         void joinRoomVia(const std::string &room_id,
                          const std::vector<std::string> &via,
@@ -145,13 +128,10 @@ signals:
         void leftRoom(const QString &room_id);
         void newRoom(const QString &room_id);
 
-        void initializeRoomList(QMap<QString, RoomInfo>);
         void initializeViews(const mtx::responses::Rooms &rooms);
         void initializeEmptyViews();
         void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
         void syncUI(const mtx::responses::Rooms &rooms);
-        void syncRoomlist(const std::map<QString, RoomInfo> &updates);
-        void syncTags(const std::map<QString, RoomInfo> &updates);
         void dropToLoginPageCb(const QString &msg);
 
         void notifyMessage(const QString &roomid,
@@ -161,7 +141,6 @@ signals:
                            const QString &message,
                            const QImage &icon);
 
-        void updateGroupsInfo(const mtx::responses::JoinedGroups &groups);
         void retrievedPresence(const QString &statusMsg, mtx::presence::PresenceState state);
         void themeChanged();
         void decryptSidebarChanged();
@@ -207,65 +186,31 @@ private:
         void getProfileInfo();
 
         //! Check if the given room is currently open.
-        bool isRoomActive(const QString &room_id)
-        {
-                return isActiveWindow() && currentRoom() == room_id;
-        }
+        bool isRoomActive(const QString &room_id);
 
         using UserID      = QString;
         using Membership  = mtx::events::StateEvent<mtx::events::state::Member>;
         using Memberships = std::map<std::string, Membership>;
 
-        using LeftRooms = std::map<std::string, mtx::responses::LeftRoom>;
-        void removeLeftRooms(const LeftRooms &rooms);
-
         void loadStateFromCache();
         void resetUI();
-        //! Decides whether or not to hide the group's sidebar.
-        void setGroupViewState(bool isEnabled);
 
         template<class Collection>
         Memberships getMemberships(const std::vector<Collection> &events) const;
 
-        //! Update the room with the new notification count.
-        void updateRoomNotificationCount(const QString &room_id,
-                                         uint16_t notification_count,
-                                         uint16_t highlight_count);
         //! Send desktop notification for the received messages.
         void sendNotifications(const mtx::responses::Notifications &);
 
-        void showNotificationsDialog(const QPoint &point);
-
         template<typename T>
         void connectCallMessage();
 
         QHBoxLayout *topLayout_;
-        Splitter *splitter;
-
-        QWidget *sideBar_;
-        QVBoxLayout *sideBarLayout_;
-        QWidget *sideBarTopWidget_;
-        QVBoxLayout *sideBarTopWidgetLayout_;
-
-        QFrame *content_;
-        QVBoxLayout *contentLayout_;
-
-        CommunitiesList *communitiesList_;
-        RoomList *room_list_;
 
         TimelineViewManager *view_manager_;
-        SideBarActions *sidebarActions_;
 
         QTimer connectivityTimer_;
         std::atomic_bool isConnected_;
 
-        QString current_room_;
-        QString current_community_;
-
-        UserInfoWidget *user_info_widget_;
-
-        popups::UserMentions *user_mentions_popup_;
-
         // Global user settings.
         QSharedPointer<UserSettings> userSettings_;
 
diff --git a/src/CommunitiesList.cpp b/src/CommunitiesList.cpp
deleted file mode 100644
index 7cc5d10e2cd1d3f7f663081987a3207992f9bbe1..0000000000000000000000000000000000000000
--- a/src/CommunitiesList.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "CommunitiesList.h"
-#include "Cache.h"
-#include "Logging.h"
-#include "MatrixClient.h"
-#include "MxcImageProvider.h"
-#include "Splitter.h"
-#include "UserSettingsPage.h"
-
-#include <mtx/responses/groups.hpp>
-#include <nlohmann/json.hpp>
-
-#include <QLabel>
-
-CommunitiesList::CommunitiesList(QWidget *parent)
-  : QWidget(parent)
-{
-        QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
-        sizePolicy.setHorizontalStretch(0);
-        sizePolicy.setVerticalStretch(1);
-        setSizePolicy(sizePolicy);
-
-        topLayout_ = new QVBoxLayout(this);
-        topLayout_->setSpacing(0);
-        topLayout_->setMargin(0);
-
-        const auto sideBarSizes = splitter::calculateSidebarSizes(QFont{});
-        setFixedWidth(sideBarSizes.groups);
-
-        scrollArea_ = new QScrollArea(this);
-        scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-        scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-        scrollArea_->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-        scrollArea_->setWidgetResizable(true);
-        scrollArea_->setAlignment(Qt::AlignLeading | Qt::AlignTop | Qt::AlignVCenter);
-
-        contentsLayout_ = new QVBoxLayout();
-        contentsLayout_->setSpacing(0);
-        contentsLayout_->setMargin(0);
-
-        addGlobalItem();
-        contentsLayout_->addStretch(1);
-
-        scrollArea_->setLayout(contentsLayout_);
-        topLayout_->addWidget(scrollArea_);
-
-        connect(
-          this, &CommunitiesList::avatarRetrieved, this, &CommunitiesList::updateCommunityAvatar);
-}
-
-void
-CommunitiesList::setCommunities(const mtx::responses::JoinedGroups &response)
-{
-        // remove all non-tag communities
-        auto it = communities_.begin();
-        while (it != communities_.end()) {
-                if (it->second->is_tag()) {
-                        ++it;
-                } else {
-                        it = communities_.erase(it);
-                }
-        }
-
-        addGlobalItem();
-
-        for (const auto &group : response.groups)
-                addCommunity(group);
-
-        communities_["world"]->setPressedState(true);
-        selectedCommunity_ = "world";
-        emit communityChanged("world");
-        sortEntries();
-}
-
-void
-CommunitiesList::syncTags(const std::map<QString, RoomInfo> &info)
-{
-        for (const auto &room : info)
-                setTagsForRoom(room.first, room.second.tags);
-        emit communityChanged(selectedCommunity_);
-        sortEntries();
-}
-
-void
-CommunitiesList::setTagsForRoom(const QString &room_id, const std::vector<std::string> &tags)
-{
-        // create missing tag if any
-        for (const auto &tag : tags) {
-                // filter out tags we should ignore according to the spec
-                // https://matrix.org/docs/spec/client_server/r0.4.0.html#id154
-                // nheko currently does not make use of internal tags
-                // so we ignore any tag containig a `.` (which would indicate a tag
-                // in the form `tld.domain.*`) except for `m.*` and `u.*`.
-                if (tag.find(".") != ::std::string::npos && tag.compare(0, 2, "m.") &&
-                    tag.compare(0, 2, "u."))
-                        continue;
-                QString name = QString("tag:") + QString::fromStdString(tag);
-                if (!communityExists(name)) {
-                        addCommunity(std::string("tag:") + tag);
-                }
-        }
-        // update membership of the room for all tags
-        auto it = communities_.begin();
-        while (it != communities_.end()) {
-                // Skip if the community is not a tag
-                if (!it->second->is_tag()) {
-                        ++it;
-                        continue;
-                }
-                // insert or remove the room from the tag as appropriate
-                std::string current_tag =
-                  it->first.right(static_cast<int>(it->first.size() - strlen("tag:")))
-                    .toStdString();
-                if (std::find(tags.begin(), tags.end(), current_tag) != tags.end()) {
-                        // the room has this tag
-                        it->second->addRoom(room_id);
-                } else {
-                        // the room does not have this tag
-                        it->second->delRoom(room_id);
-                }
-                // Check if the tag is now empty, if yes delete it
-                if (it->second->rooms().empty()) {
-                        it = communities_.erase(it);
-                } else {
-                        ++it;
-                }
-        }
-}
-
-void
-CommunitiesList::addCommunity(const std::string &group_id)
-{
-        auto hiddenTags = UserSettings::instance()->hiddenTags();
-
-        const auto id = QString::fromStdString(group_id);
-
-        CommunitiesListItem *list_item = new CommunitiesListItem(id, scrollArea_);
-
-        if (hiddenTags.contains(id))
-                list_item->setDisabled(true);
-
-        communities_.emplace(id, QSharedPointer<CommunitiesListItem>(list_item));
-        contentsLayout_->insertWidget(contentsLayout_->count() - 1, list_item);
-
-        connect(list_item,
-                &CommunitiesListItem::clicked,
-                this,
-                &CommunitiesList::highlightSelectedCommunity);
-        connect(list_item, &CommunitiesListItem::isDisabledChanged, this, [this]() {
-                for (const auto &community : communities_) {
-                        if (community.second->isPressed()) {
-                                emit highlightSelectedCommunity(community.first);
-                                break;
-                        }
-                }
-
-                auto hiddenTags = hiddenTagsAndCommunities();
-                // Qt < 5.14 compat
-                QStringList hiddenTags_;
-                for (auto &&t : hiddenTags)
-                        hiddenTags_.push_back(t);
-                UserSettings::instance()->setHiddenTags(hiddenTags_);
-        });
-
-        if (group_id.empty() || group_id.front() != '+')
-                return;
-
-        nhlog::ui()->debug("Add community: {}", group_id);
-
-        connect(this,
-                &CommunitiesList::groupProfileRetrieved,
-                this,
-                [this](const QString &id, const mtx::responses::GroupProfile &profile) {
-                        if (communities_.find(id) == communities_.end())
-                                return;
-
-                        communities_.at(id)->setName(QString::fromStdString(profile.name));
-
-                        if (!profile.avatar_url.empty())
-                                fetchCommunityAvatar(id,
-                                                     QString::fromStdString(profile.avatar_url));
-                });
-        connect(this,
-                &CommunitiesList::groupRoomsRetrieved,
-                this,
-                [this](const QString &id, const std::set<QString> &rooms) {
-                        nhlog::ui()->info(
-                          "Fetched rooms for {}: {}", id.toStdString(), rooms.size());
-                        if (communities_.find(id) == communities_.end())
-                                return;
-
-                        communities_.at(id)->setRooms(rooms);
-                });
-
-        http::client()->group_profile(
-          group_id, [id, this](const mtx::responses::GroupProfile &res, mtx::http::RequestErr err) {
-                  if (err) {
-                          return;
-                  }
-
-                  emit groupProfileRetrieved(id, res);
-          });
-
-        http::client()->group_rooms(
-          group_id, [id, this](const nlohmann::json &res, mtx::http::RequestErr err) {
-                  if (err) {
-                          return;
-                  }
-
-                  std::set<QString> room_ids;
-                  for (const auto &room : res.at("chunk"))
-                          room_ids.emplace(QString::fromStdString(room.at("room_id")));
-
-                  emit groupRoomsRetrieved(id, room_ids);
-          });
-}
-
-void
-CommunitiesList::updateCommunityAvatar(const QString &community_id, const QPixmap &img)
-{
-        if (!communityExists(community_id)) {
-                nhlog::ui()->warn("Avatar update on nonexistent community {}",
-                                  community_id.toStdString());
-                return;
-        }
-
-        communities_.at(community_id)->setAvatar(img.toImage());
-}
-
-void
-CommunitiesList::highlightSelectedCommunity(const QString &community_id)
-{
-        if (!communityExists(community_id)) {
-                nhlog::ui()->debug("CommunitiesList: clicked unknown community");
-                return;
-        }
-
-        selectedCommunity_ = community_id;
-        emit communityChanged(community_id);
-
-        for (const auto &community : communities_) {
-                if (community.first != community_id) {
-                        community.second->setPressedState(false);
-                } else {
-                        community.second->setPressedState(true);
-                        scrollArea_->ensureWidgetVisible(community.second.data());
-                }
-        }
-}
-
-void
-CommunitiesList::fetchCommunityAvatar(const QString &id, const QString &avatarUrl)
-{
-        MxcImageProvider::download(
-          QString(avatarUrl).remove(QStringLiteral("mxc://")),
-          QSize(96, 96),
-          [this, id](QString, QSize, QImage img, QString) {
-                  if (img.isNull()) {
-                          nhlog::net()->warn("failed to download avatar: {})", id.toStdString());
-                          return;
-                  }
-
-                  emit avatarRetrieved(id, QPixmap::fromImage(img));
-          });
-}
-
-std::set<QString>
-CommunitiesList::roomList(const QString &id) const
-{
-        if (communityExists(id))
-                return communities_.at(id)->rooms();
-
-        return {};
-}
-
-std::vector<std::string>
-CommunitiesList::currentTags() const
-{
-        std::vector<std::string> tags;
-        for (auto &entry : communities_) {
-                CommunitiesListItem *item = entry.second.data();
-                if (item->is_tag())
-                        tags.push_back(entry.first.mid(4).toStdString());
-        }
-        return tags;
-}
-
-std::set<QString>
-CommunitiesList::hiddenTagsAndCommunities() const
-{
-        std::set<QString> hiddenTags;
-        for (auto &entry : communities_) {
-                if (entry.second->isDisabled())
-                        hiddenTags.insert(entry.first);
-        }
-
-        return hiddenTags;
-}
-
-void
-CommunitiesList::sortEntries()
-{
-        std::vector<CommunitiesListItem *> header;
-        std::vector<CommunitiesListItem *> communities;
-        std::vector<CommunitiesListItem *> tags;
-        std::vector<CommunitiesListItem *> footer;
-        // remove all the contents and sort them in the 4 vectors
-        for (auto &entry : communities_) {
-                CommunitiesListItem *item = entry.second.data();
-                contentsLayout_->removeWidget(item);
-                // world is handled separately
-                if (entry.first == "world")
-                        continue;
-                // sort the rest
-                if (item->is_tag())
-                        if (entry.first == "tag:m.favourite")
-                                header.push_back(item);
-                        else if (entry.first == "tag:m.lowpriority")
-                                footer.push_back(item);
-                        else
-                                tags.push_back(item);
-                else
-                        communities.push_back(item);
-        }
-
-        // now there remains only the stretch in the layout, remove it
-        QLayoutItem *stretch = contentsLayout_->itemAt(0);
-        contentsLayout_->removeItem(stretch);
-
-        contentsLayout_->addWidget(communities_["world"].data());
-
-        auto insert_widgets = [this](auto &vec) {
-                for (auto item : vec)
-                        contentsLayout_->addWidget(item);
-        };
-        insert_widgets(header);
-        insert_widgets(communities);
-        insert_widgets(tags);
-        insert_widgets(footer);
-
-        contentsLayout_->addItem(stretch);
-}
diff --git a/src/CommunitiesList.h b/src/CommunitiesList.h
deleted file mode 100644
index 12b275b073c8c68ed442df9da32f051711654a9d..0000000000000000000000000000000000000000
--- a/src/CommunitiesList.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QScrollArea>
-#include <QSharedPointer>
-#include <QVBoxLayout>
-
-#include "CacheStructs.h"
-#include "CommunitiesListItem.h"
-
-namespace mtx::responses {
-struct GroupProfile;
-struct JoinedGroups;
-}
-
-class CommunitiesList : public QWidget
-{
-        Q_OBJECT
-
-public:
-        CommunitiesList(QWidget *parent = nullptr);
-
-        void clear() { communities_.clear(); }
-
-        void addCommunity(const std::string &id);
-        void removeCommunity(const QString &id) { communities_.erase(id); };
-        std::set<QString> roomList(const QString &id) const;
-
-        void syncTags(const std::map<QString, RoomInfo> &info);
-        void setTagsForRoom(const QString &id, const std::vector<std::string> &tags);
-        std::vector<std::string> currentTags() const;
-        std::set<QString> hiddenTagsAndCommunities() const;
-
-signals:
-        void communityChanged(const QString &id);
-        void avatarRetrieved(const QString &id, const QPixmap &img);
-        void groupProfileRetrieved(const QString &group_id, const mtx::responses::GroupProfile &);
-        void groupRoomsRetrieved(const QString &group_id, const std::set<QString> &res);
-
-public slots:
-        void updateCommunityAvatar(const QString &id, const QPixmap &img);
-        void highlightSelectedCommunity(const QString &id);
-        void setCommunities(const mtx::responses::JoinedGroups &groups);
-
-private:
-        void fetchCommunityAvatar(const QString &id, const QString &avatarUrl);
-        void addGlobalItem() { addCommunity("world"); }
-        void sortEntries();
-
-        //! Check whether or not a community id is currently managed.
-        bool communityExists(const QString &id) const
-        {
-                return communities_.find(id) != communities_.end();
-        }
-
-        QString selectedCommunity_;
-        QVBoxLayout *topLayout_;
-        QVBoxLayout *contentsLayout_;
-        QScrollArea *scrollArea_;
-
-        std::map<QString, QSharedPointer<CommunitiesListItem>> communities_;
-};
diff --git a/src/CommunitiesListItem.cpp b/src/CommunitiesListItem.cpp
deleted file mode 100644
index a2f2777df5ce49573b2fcab0525e729d1158c297..0000000000000000000000000000000000000000
--- a/src/CommunitiesListItem.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "CommunitiesListItem.h"
-
-#include <QMenu>
-#include <QMouseEvent>
-
-#include "Utils.h"
-#include "ui/Painter.h"
-#include "ui/Ripple.h"
-#include "ui/RippleOverlay.h"
-
-CommunitiesListItem::CommunitiesListItem(QString group_id, QWidget *parent)
-  : QWidget(parent)
-  , groupId_(group_id)
-{
-        setMouseTracking(true);
-        setAttribute(Qt::WA_Hover);
-
-        QPainterPath path;
-        path.addRect(0, 0, parent->width(), height());
-        rippleOverlay_ = new RippleOverlay(this);
-        rippleOverlay_->setClipPath(path);
-        rippleOverlay_->setClipping(true);
-
-        menu_ = new QMenu(this);
-        hideRoomsWithTagAction_ =
-          new QAction(tr("Hide rooms with this tag or from this community"), this);
-        hideRoomsWithTagAction_->setCheckable(true);
-        menu_->addAction(hideRoomsWithTagAction_);
-        connect(menu_, &QMenu::aboutToShow, this, [this]() {
-                hideRoomsWithTagAction_->setChecked(isDisabled_);
-        });
-
-        connect(hideRoomsWithTagAction_, &QAction::triggered, this, [this](bool checked) {
-                this->setDisabled(checked);
-        });
-
-        updateTooltip();
-}
-
-void
-CommunitiesListItem::contextMenuEvent(QContextMenuEvent *event)
-{
-        menu_->popup(event->globalPos());
-}
-
-void
-CommunitiesListItem::setName(QString name)
-{
-        name_ = name;
-        updateTooltip();
-}
-
-void
-CommunitiesListItem::setPressedState(bool state)
-{
-        if (isPressed_ != state) {
-                isPressed_ = state;
-                update();
-        }
-}
-
-void
-CommunitiesListItem::setDisabled(bool state)
-{
-        if (isDisabled_ != state) {
-                isDisabled_ = state;
-                update();
-                emit isDisabledChanged();
-        }
-}
-
-void
-CommunitiesListItem::mousePressEvent(QMouseEvent *event)
-{
-        if (event->buttons() == Qt::RightButton) {
-                QWidget::mousePressEvent(event);
-                return;
-        }
-
-        emit clicked(groupId_);
-
-        setPressedState(true);
-
-        QPoint pos           = event->pos();
-        qreal radiusEndValue = static_cast<qreal>(width()) / 3;
-
-        auto ripple = new Ripple(pos);
-        ripple->setRadiusEndValue(radiusEndValue);
-        ripple->setOpacityStartValue(0.15);
-        ripple->setColor("white");
-        ripple->radiusAnimation()->setDuration(200);
-        ripple->opacityAnimation()->setDuration(400);
-        rippleOverlay_->addRipple(ripple);
-}
-
-void
-CommunitiesListItem::paintEvent(QPaintEvent *)
-{
-        Painter p(this);
-        PainterHighQualityEnabler hq(p);
-
-        if (isPressed_)
-                p.fillRect(rect(), highlightedBackgroundColor_);
-        else if (isDisabled_)
-                p.fillRect(rect(), disabledBackgroundColor_);
-        else if (underMouse())
-                p.fillRect(rect(), hoverBackgroundColor_);
-        else
-                p.fillRect(rect(), backgroundColor_);
-
-        if (avatar_.isNull()) {
-                QPixmap source;
-                if (groupId_ == "world")
-                        source = QPixmap(":/icons/icons/ui/world.png");
-                else if (groupId_ == "tag:m.favourite")
-                        source = QPixmap(":/icons/icons/ui/star.png");
-                else if (groupId_ == "tag:m.lowpriority")
-                        source = QPixmap(":/icons/icons/ui/lowprio.png");
-                else if (groupId_.startsWith("tag:"))
-                        source = QPixmap(":/icons/icons/ui/tag.png");
-
-                if (source.isNull()) {
-                        QFont font;
-                        font.setPointSizeF(font.pointSizeF() * 1.3);
-                        p.setFont(font);
-
-                        p.drawLetterAvatar(utils::firstChar(resolveName()),
-                                           avatarFgColor_,
-                                           avatarBgColor_,
-                                           width(),
-                                           height(),
-                                           IconSize);
-                } else {
-                        QPainter painter(&source);
-                        painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
-                        painter.fillRect(source.rect(), avatarFgColor_);
-                        painter.end();
-
-                        const int imageSz = 32;
-                        p.drawPixmap(
-                          QRect(
-                            (width() - imageSz) / 2, (height() - imageSz) / 2, imageSz, imageSz),
-                          source);
-                }
-        } else {
-                p.save();
-
-                p.drawAvatar(avatar_, width(), height(), IconSize);
-                p.restore();
-        }
-}
-
-void
-CommunitiesListItem::setAvatar(const QImage &img)
-{
-        avatar_ = utils::scaleImageToPixmap(img, IconSize);
-        update();
-}
-
-QString
-CommunitiesListItem::resolveName() const
-{
-        if (!name_.isEmpty())
-                return name_;
-        if (groupId_.startsWith("tag:"))
-                return groupId_.right(static_cast<int>(groupId_.size() - strlen("tag:")));
-        if (!groupId_.startsWith("+"))
-                return QString("Group"); // Group with no name or id.
-
-        // Extract the localpart of the group.
-        auto firstPart = groupId_.split(':').at(0);
-        return firstPart.right(firstPart.size() - 1);
-}
-
-void
-CommunitiesListItem::updateTooltip()
-{
-        if (groupId_ == "world")
-                setToolTip(tr("All rooms"));
-        else if (is_tag()) {
-                QStringRef tag =
-                  groupId_.rightRef(static_cast<int>(groupId_.size() - strlen("tag:")));
-                if (tag == "m.favourite")
-                        setToolTip(tr("Favourite rooms"));
-                else if (tag == "m.lowpriority")
-                        setToolTip(tr("Low priority rooms"));
-                else if (tag == "m.server_notice")
-                        setToolTip(tr("Server Notices", "Tag translation for m.server_notice"));
-                else if (tag.startsWith("u."))
-                        setToolTip(tag.right(tag.size() - 2) + tr(" (tag)"));
-                else
-                        setToolTip(tag + tr(" (tag)"));
-        } else {
-                QString name = resolveName();
-                setToolTip(name + tr(" (community)"));
-        }
-}
diff --git a/src/CommunitiesListItem.h b/src/CommunitiesListItem.h
deleted file mode 100644
index e74686115a3a4f83e9539e8e5c0b85f63aa6680b..0000000000000000000000000000000000000000
--- a/src/CommunitiesListItem.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QSharedPointer>
-#include <QWidget>
-
-#include <set>
-
-#include "Config.h"
-
-class RippleOverlay;
-class QMouseEvent;
-class QMenu;
-
-class CommunitiesListItem : public QWidget
-{
-        Q_OBJECT
-        Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
-                     setHighlightedBackgroundColor)
-        Q_PROPERTY(QColor disabledBackgroundColor READ disabledBackgroundColor WRITE
-                     setDisabledBackgroundColor)
-        Q_PROPERTY(
-          QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
-        Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
-
-        Q_PROPERTY(QColor avatarFgColor READ avatarFgColor WRITE setAvatarFgColor)
-        Q_PROPERTY(QColor avatarBgColor READ avatarBgColor WRITE setAvatarBgColor)
-
-public:
-        CommunitiesListItem(QString group_id, QWidget *parent = nullptr);
-
-        void setName(QString name);
-        bool isPressed() const { return isPressed_; }
-        bool isDisabled() const { return isDisabled_; }
-        void setAvatar(const QImage &img);
-
-        void setRooms(std::set<QString> room_ids) { room_ids_ = std::move(room_ids); }
-        void addRoom(const QString &id) { room_ids_.insert(id); }
-        void delRoom(const QString &id) { room_ids_.erase(id); }
-        std::set<QString> rooms() const { return room_ids_; }
-
-        bool is_tag() const { return groupId_.startsWith("tag:"); }
-
-        QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
-        QColor disabledBackgroundColor() const { return disabledBackgroundColor_; }
-        QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
-        QColor backgroundColor() const { return backgroundColor_; }
-
-        QColor avatarFgColor() const { return avatarFgColor_; }
-        QColor avatarBgColor() const { return avatarBgColor_; }
-
-        void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
-        void setDisabledBackgroundColor(QColor &color) { disabledBackgroundColor_ = color; }
-        void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
-        void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
-
-        void setAvatarFgColor(QColor &color) { avatarFgColor_ = color; }
-        void setAvatarBgColor(QColor &color) { avatarBgColor_ = color; }
-
-        QSize sizeHint() const override
-        {
-                return QSize(IconSize + IconSize / 3, IconSize + IconSize / 3);
-        }
-
-signals:
-        void clicked(const QString &group_id);
-        void isDisabledChanged();
-
-public slots:
-        void setPressedState(bool state);
-        void setDisabled(bool state);
-
-protected:
-        void mousePressEvent(QMouseEvent *event) override;
-        void paintEvent(QPaintEvent *event) override;
-        void contextMenuEvent(QContextMenuEvent *event) override;
-
-private:
-        const int IconSize = 36;
-
-        QString resolveName() const;
-        void updateTooltip();
-
-        std::set<QString> room_ids_;
-
-        QString name_;
-        QString groupId_;
-        QPixmap avatar_;
-
-        QColor highlightedBackgroundColor_;
-        QColor disabledBackgroundColor_;
-        QColor hoverBackgroundColor_;
-        QColor backgroundColor_;
-
-        QColor avatarFgColor_;
-        QColor avatarBgColor_;
-
-        bool isPressed_  = false;
-        bool isDisabled_ = false;
-
-        RippleOverlay *rippleOverlay_;
-        QMenu *menu_;
-        QAction *hideRoomsWithTagAction_;
-};
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index e2b625b044422edc8d30025d26e7ed1dcef55be4..057ee4af889ee029e5f88b9ec38e0d7a15952f92 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -109,10 +109,6 @@ MainWindow::MainWindow(QWidget *parent)
           userSettingsPage_, SIGNAL(trayOptionChanged(bool)), trayIcon_, SLOT(setVisible(bool)));
         connect(
           userSettingsPage_, &UserSettingsPage::themeChanged, chat_page_, &ChatPage::themeChanged);
-        connect(userSettingsPage_,
-                &UserSettingsPage::decryptSidebarChanged,
-                chat_page_,
-                &ChatPage::decryptSidebarChanged);
         connect(trayIcon_,
                 SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
                 this,
@@ -176,20 +172,6 @@ MainWindow::setWindowTitle(int notificationCount)
         QMainWindow::setWindowTitle(name);
 }
 
-void
-MainWindow::showEvent(QShowEvent *event)
-{
-        adjustSideBars();
-        QMainWindow::showEvent(event);
-}
-
-void
-MainWindow::resizeEvent(QResizeEvent *event)
-{
-        adjustSideBars();
-        QMainWindow::resizeEvent(event);
-}
-
 bool
 MainWindow::event(QEvent *event)
 {
@@ -203,22 +185,6 @@ MainWindow::event(QEvent *event)
         return QMainWindow::event(event);
 }
 
-void
-MainWindow::adjustSideBars()
-{
-        const auto sz = splitter::calculateSidebarSizes(QFont{});
-
-        const uint64_t timelineWidth     = chat_page_->timelineWidth();
-        const uint64_t minAvailableWidth = sz.collapsePoint + sz.groups;
-
-        nhlog::ui()->info("timelineWidth: {}, min {}", timelineWidth, minAvailableWidth);
-        if (timelineWidth < minAvailableWidth) {
-                chat_page_->hideSideBars();
-        } else {
-                chat_page_->showSideBars();
-        }
-}
-
 void
 MainWindow::restoreWindowSize()
 {
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 69d07e62e4b683548303cc20ad0195ecb6320508..3571f07955a8b994b9058e3e4e64229c097ce3c1 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -77,13 +77,9 @@ public:
 
 protected:
         void closeEvent(QCloseEvent *event) override;
-        void resizeEvent(QResizeEvent *event) override;
-        void showEvent(QShowEvent *event) override;
         bool event(QEvent *event) override;
 
 private slots:
-        //! Show or hide the sidebars based on window's size.
-        void adjustSideBars();
         //! Handle interaction with the tray icon.
         void iconActivated(QSystemTrayIcon::ActivationReason reason);
 
diff --git a/src/RoomInfoListItem.cpp b/src/RoomInfoListItem.cpp
deleted file mode 100644
index ea5de674c649eda9f25dcaa8d6f7fc3c4c232bdf..0000000000000000000000000000000000000000
--- a/src/RoomInfoListItem.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <QDateTime>
-#include <QInputDialog>
-#include <QMenu>
-#include <QMouseEvent>
-#include <QPainter>
-#include <QtGlobal>
-
-#include "AvatarProvider.h"
-#include "Cache.h"
-#include "ChatPage.h"
-#include "Config.h"
-#include "Logging.h"
-#include "MatrixClient.h"
-#include "RoomInfoListItem.h"
-#include "Splitter.h"
-#include "UserSettingsPage.h"
-#include "Utils.h"
-#include "ui/Ripple.h"
-#include "ui/RippleOverlay.h"
-
-constexpr int MaxUnreadCountDisplayed = 99;
-
-struct WidgetMetrics
-{
-        int maxHeight;
-        int iconSize;
-        int padding;
-        int unit;
-
-        int unreadLineWidth;
-        int unreadLineOffset;
-
-        int inviteBtnX;
-        int inviteBtnY;
-};
-
-WidgetMetrics
-getMetrics(const QFont &font)
-{
-        WidgetMetrics m;
-
-        const int height = QFontMetrics(font).lineSpacing();
-
-        m.unit             = height;
-        m.maxHeight        = std::ceil((double)height * 3.8);
-        m.iconSize         = std::ceil((double)height * 2.8);
-        m.padding          = std::ceil((double)height / 2.0);
-        m.unreadLineWidth  = m.padding - m.padding / 3;
-        m.unreadLineOffset = m.padding - m.padding / 4;
-
-        m.inviteBtnX = m.iconSize + 2 * m.padding;
-        m.inviteBtnY = m.iconSize / 2.0 + m.padding + m.padding / 3.0;
-
-        return m;
-}
-
-void
-RoomInfoListItem::init(QWidget *parent)
-{
-        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
-        setMouseTracking(true);
-        setAttribute(Qt::WA_Hover);
-
-        auto wm = getMetrics(QFont{});
-        setFixedHeight(wm.maxHeight);
-
-        QPainterPath path;
-        path.addRect(0, 0, parent->width(), height());
-
-        ripple_overlay_ = new RippleOverlay(this);
-        ripple_overlay_->setClipPath(path);
-        ripple_overlay_->setClipping(true);
-
-        avatar_ = new Avatar(nullptr, wm.iconSize);
-        avatar_->setLetter(utils::firstChar(roomName_));
-        avatar_->resize(wm.iconSize, wm.iconSize);
-
-        unreadCountFont_.setPointSizeF(unreadCountFont_.pointSizeF() * 0.8);
-        unreadCountFont_.setBold(true);
-
-        bubbleDiameter_ = QFontMetrics(unreadCountFont_).averageCharWidth() * 3;
-
-        menu_      = new QMenu(this);
-        leaveRoom_ = new QAction(tr("Leave room"), this);
-        connect(leaveRoom_, &QAction::triggered, this, [this]() { emit leaveRoom(roomId_); });
-
-        connect(menu_, &QMenu::aboutToShow, this, [this]() {
-                menu_->clear();
-                menu_->addAction(leaveRoom_);
-
-                menu_->addSection(QIcon(":/icons/icons/ui/tag.png"), tr("Tag room as:"));
-
-                auto roomInfo = cache::singleRoomInfo(roomId_.toStdString());
-
-                auto tags = ChatPage::instance()->communitiesList()->currentTags();
-
-                // add default tag, remove server notice tag
-                if (std::find(tags.begin(), tags.end(), "m.favourite") == tags.end())
-                        tags.push_back("m.favourite");
-                if (std::find(tags.begin(), tags.end(), "m.lowpriority") == tags.end())
-                        tags.push_back("m.lowpriority");
-                if (auto it = std::find(tags.begin(), tags.end(), "m.server_notice");
-                    it != tags.end())
-                        tags.erase(it);
-
-                for (const auto &tag : tags) {
-                        QString tagName;
-                        if (tag == "m.favourite")
-                                tagName = tr("Favourite", "Standard matrix tag for favourites");
-                        else if (tag == "m.lowpriority")
-                                tagName =
-                                  tr("Low Priority", "Standard matrix tag for low priority rooms");
-                        else if (tag == "m.server_notice")
-                                tagName =
-                                  tr("Server Notice", "Standard matrix tag for server notices");
-                        else if ((tag.size() > 2 && tag.substr(0, 2) == "u.") ||
-                                 tag.find(".") !=
-                                   std::string::npos) // tag manager creates tags without u., which
-                                                      // is wrong, but we still want to display them
-                                tagName = QString::fromStdString(tag.substr(2));
-
-                        if (tagName.isEmpty())
-                                continue;
-
-                        auto tagAction = menu_->addAction(tagName);
-                        tagAction->setCheckable(true);
-                        tagAction->setWhatsThis(tr("Adds or removes the specified tag.",
-                                                   "WhatsThis hint for tag menu actions"));
-
-                        for (const auto &riTag : roomInfo.tags) {
-                                if (riTag == tag) {
-                                        tagAction->setChecked(true);
-                                        break;
-                                }
-                        }
-
-                        connect(tagAction, &QAction::triggered, this, [this, tag](bool checked) {
-                                if (checked)
-                                        http::client()->put_tag(
-                                          roomId_.toStdString(),
-                                          tag,
-                                          {},
-                                          [tag](mtx::http::RequestErr err) {
-                                                  if (err) {
-                                                          nhlog::ui()->error(
-                                                            "Failed to add tag: {}, {}",
-                                                            tag,
-                                                            err->matrix_error.error);
-                                                  }
-                                          });
-                                else
-                                        http::client()->delete_tag(
-                                          roomId_.toStdString(),
-                                          tag,
-                                          [tag](mtx::http::RequestErr err) {
-                                                  if (err) {
-                                                          nhlog::ui()->error(
-                                                            "Failed to delete tag: {}, {}",
-                                                            tag,
-                                                            err->matrix_error.error);
-                                                  }
-                                          });
-                        });
-                }
-
-                auto newTagAction = menu_->addAction(tr("New tag...", "Add a new tag to the room"));
-                connect(newTagAction, &QAction::triggered, this, [this]() {
-                        QString tagName =
-                          QInputDialog::getText(this,
-                                                tr("New Tag", "Tag name prompt title"),
-                                                tr("Tag:", "Tag name prompt"));
-                        if (tagName.isEmpty())
-                                return;
-
-                        std::string tag = "u." + tagName.toStdString();
-
-                        http::client()->put_tag(
-                          roomId_.toStdString(), tag, {}, [tag](mtx::http::RequestErr err) {
-                                  if (err) {
-                                          nhlog::ui()->error("Failed to add tag: {}, {}",
-                                                             tag,
-                                                             err->matrix_error.error);
-                                  }
-                          });
-                });
-        });
-}
-
-RoomInfoListItem::RoomInfoListItem(QString room_id, const RoomInfo &info, QWidget *parent)
-  : QWidget(parent)
-  , roomType_{info.is_invite ? RoomType::Invited : RoomType::Joined}
-  , roomId_(std::move(room_id))
-  , roomName_{QString::fromStdString(std::move(info.name))}
-  , isPressed_(false)
-  , unreadMsgCount_(0)
-  , unreadHighlightedMsgCount_(0)
-{
-        init(parent);
-}
-
-void
-RoomInfoListItem::resizeEvent(QResizeEvent *)
-{
-        // Update ripple's clipping path.
-        QPainterPath path;
-        path.addRect(0, 0, width(), height());
-
-        const auto sidebarSizes = splitter::calculateSidebarSizes(QFont{});
-
-        if (width() > sidebarSizes.small)
-                setToolTip("");
-        else
-                setToolTip(roomName_);
-
-        ripple_overlay_->setClipPath(path);
-        ripple_overlay_->setClipping(true);
-}
-
-void
-RoomInfoListItem::paintEvent(QPaintEvent *event)
-{
-        Q_UNUSED(event);
-
-        QPainter p(this);
-        p.setRenderHint(QPainter::TextAntialiasing);
-        p.setRenderHint(QPainter::SmoothPixmapTransform);
-        p.setRenderHint(QPainter::Antialiasing);
-
-        QFontMetrics metrics(QFont{});
-
-        QPen titlePen(titleColor_);
-        QPen subtitlePen(subtitleColor_);
-
-        auto wm = getMetrics(QFont{});
-
-        QPixmap pixmap(avatar_->size() * p.device()->devicePixelRatioF());
-        pixmap.setDevicePixelRatio(p.device()->devicePixelRatioF());
-        if (isPressed_) {
-                p.fillRect(rect(), highlightedBackgroundColor_);
-                titlePen.setColor(highlightedTitleColor_);
-                subtitlePen.setColor(highlightedSubtitleColor_);
-                pixmap.fill(highlightedBackgroundColor_);
-        } else if (underMouse()) {
-                p.fillRect(rect(), hoverBackgroundColor_);
-                titlePen.setColor(hoverTitleColor_);
-                subtitlePen.setColor(hoverSubtitleColor_);
-                pixmap.fill(hoverBackgroundColor_);
-        } else {
-                p.fillRect(rect(), backgroundColor_);
-                titlePen.setColor(titleColor_);
-                subtitlePen.setColor(subtitleColor_);
-                pixmap.fill(backgroundColor_);
-        }
-
-        avatar_->render(&pixmap, QPoint(), QRegion(), RenderFlags(DrawChildren));
-        p.drawPixmap(QPoint(wm.padding, wm.padding), pixmap);
-
-        // Description line with the default font.
-        int bottom_y = wm.maxHeight - wm.padding - metrics.ascent() / 2;
-
-        const auto sidebarSizes = splitter::calculateSidebarSizes(QFont{});
-
-        if (width() > sidebarSizes.small) {
-                QFont headingFont;
-                headingFont.setWeight(QFont::Medium);
-                p.setFont(headingFont);
-                p.setPen(titlePen);
-
-                QFont tsFont;
-                tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9);
-#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
-                const int msgStampWidth =
-                  QFontMetrics(tsFont).width(lastMsgInfo_.descriptiveTime) + 4;
-#else
-                const int msgStampWidth =
-                  QFontMetrics(tsFont).horizontalAdvance(lastMsgInfo_.descriptiveTime) + 4;
-#endif
-                // We use the full width of the widget if there is no unread msg bubble.
-                const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0;
-
-                // Name line.
-                QFontMetrics fontNameMetrics(headingFont);
-                int top_y = 2 * wm.padding + fontNameMetrics.ascent() / 2;
-
-                const auto name = metrics.elidedText(
-                  roomName(),
-                  Qt::ElideRight,
-                  (width() - wm.iconSize - 2 * wm.padding - msgStampWidth) * 0.8);
-                p.drawText(QPoint(2 * wm.padding + wm.iconSize, top_y), name);
-
-                if (roomType_ == RoomType::Joined) {
-                        p.setFont(QFont{});
-                        p.setPen(subtitlePen);
-
-                        int descriptionLimit = std::max(
-                          0, width() - 3 * wm.padding - bottomLineWidthLimit - wm.iconSize);
-                        auto description =
-                          metrics.elidedText(lastMsgInfo_.body, Qt::ElideRight, descriptionLimit);
-                        p.drawText(QPoint(2 * wm.padding + wm.iconSize, bottom_y), description);
-
-                        // We show the last message timestamp.
-                        p.save();
-                        if (isPressed_) {
-                                p.setPen(QPen(highlightedTimestampColor_));
-                        } else if (underMouse()) {
-                                p.setPen(QPen(hoverTimestampColor_));
-                        } else {
-                                p.setPen(QPen(timestampColor_));
-                        }
-
-                        p.setFont(tsFont);
-                        p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y),
-                                   lastMsgInfo_.descriptiveTime);
-                        p.restore();
-                } else {
-                        int btnWidth = (width() - wm.iconSize - 6 * wm.padding) / 2;
-
-                        acceptBtnRegion_  = QRectF(wm.inviteBtnX, wm.inviteBtnY, btnWidth, 20);
-                        declineBtnRegion_ = QRectF(
-                          wm.inviteBtnX + btnWidth + 2 * wm.padding, wm.inviteBtnY, btnWidth, 20);
-
-                        QPainterPath acceptPath;
-                        acceptPath.addRoundedRect(acceptBtnRegion_, 10, 10);
-
-                        p.setPen(Qt::NoPen);
-                        p.fillPath(acceptPath, btnColor_);
-                        p.drawPath(acceptPath);
-
-                        QPainterPath declinePath;
-                        declinePath.addRoundedRect(declineBtnRegion_, 10, 10);
-
-                        p.setPen(Qt::NoPen);
-                        p.fillPath(declinePath, btnColor_);
-                        p.drawPath(declinePath);
-
-                        p.setPen(QPen(btnTextColor_));
-                        p.setFont(QFont{});
-                        p.drawText(acceptBtnRegion_,
-                                   Qt::AlignCenter,
-                                   metrics.elidedText(tr("Accept"), Qt::ElideRight, btnWidth));
-                        p.drawText(declineBtnRegion_,
-                                   Qt::AlignCenter,
-                                   metrics.elidedText(tr("Decline"), Qt::ElideRight, btnWidth));
-                }
-        }
-
-        p.setPen(Qt::NoPen);
-
-        if (unreadMsgCount_ > 0) {
-                QBrush brush;
-                brush.setStyle(Qt::SolidPattern);
-                if (unreadHighlightedMsgCount_ > 0) {
-                        brush.setColor(mentionedColor());
-                } else {
-                        brush.setColor(bubbleBgColor());
-                }
-
-                if (isPressed_)
-                        brush.setColor(bubbleFgColor());
-
-                p.setBrush(brush);
-                p.setPen(Qt::NoPen);
-                p.setFont(unreadCountFont_);
-
-                // Extra space on the x-axis to accomodate the extra character space
-                // inside the bubble.
-                const int x_width = unreadMsgCount_ > MaxUnreadCountDisplayed
-                                      ? QFontMetrics(p.font()).averageCharWidth()
-                                      : 0;
-
-                QRectF r(width() - bubbleDiameter_ - wm.padding - x_width,
-                         bottom_y - bubbleDiameter_ / 2 - 5,
-                         bubbleDiameter_ + x_width,
-                         bubbleDiameter_);
-
-                if (width() == sidebarSizes.small)
-                        r = QRectF(width() - bubbleDiameter_ - 5,
-                                   height() - bubbleDiameter_ - 5,
-                                   bubbleDiameter_ + x_width,
-                                   bubbleDiameter_);
-
-                p.setPen(Qt::NoPen);
-                p.drawEllipse(r);
-
-                p.setPen(QPen(bubbleFgColor()));
-
-                if (isPressed_)
-                        p.setPen(QPen(bubbleBgColor()));
-
-                auto countTxt = unreadMsgCount_ > MaxUnreadCountDisplayed
-                                  ? QString("99+")
-                                  : QString::number(unreadMsgCount_);
-
-                p.setBrush(Qt::NoBrush);
-                p.drawText(r.translated(0, -0.5), Qt::AlignCenter, countTxt);
-        }
-
-        if (!isPressed_ && hasUnreadMessages_) {
-                QPen pen;
-                pen.setWidth(wm.unreadLineWidth);
-                pen.setColor(highlightedBackgroundColor_);
-
-                p.setPen(pen);
-                p.drawLine(0, wm.unreadLineOffset, 0, height() - wm.unreadLineOffset);
-        }
-}
-
-void
-RoomInfoListItem::updateUnreadMessageCount(int count, int highlightedCount)
-{
-        unreadMsgCount_            = count;
-        unreadHighlightedMsgCount_ = highlightedCount;
-        update();
-}
-
-enum NotificationImportance : short
-{
-        ImportanceDisabled = -1,
-        AllEventsRead      = 0,
-        NewMessage         = 1,
-        NewMentions        = 2,
-        Invite             = 3
-};
-
-short int
-RoomInfoListItem::calculateImportance() const
-{
-        // Returns the degree of importance of the unread messages in the room.
-        // If sorting by importance is disabled in settings, this only ever
-        // returns ImportanceDisabled or Invite
-        if (isInvite()) {
-                return Invite;
-        } else if (!ChatPage::instance()->userSettings()->sortByImportance()) {
-                return ImportanceDisabled;
-        } else if (unreadHighlightedMsgCount_) {
-                return NewMentions;
-        } else if (unreadMsgCount_) {
-                return NewMessage;
-        } else {
-                return AllEventsRead;
-        }
-}
-
-void
-RoomInfoListItem::setPressedState(bool state)
-{
-        if (isPressed_ != state) {
-                isPressed_ = state;
-                update();
-        }
-}
-
-void
-RoomInfoListItem::contextMenuEvent(QContextMenuEvent *event)
-{
-        Q_UNUSED(event);
-
-        if (roomType_ == RoomType::Invited)
-                return;
-
-        menu_->popup(event->globalPos());
-}
-
-void
-RoomInfoListItem::mousePressEvent(QMouseEvent *event)
-{
-        if (event->buttons() == Qt::RightButton) {
-                QWidget::mousePressEvent(event);
-                return;
-        } else if (event->buttons() == Qt::LeftButton) {
-                if (roomType_ == RoomType::Invited) {
-                        const auto point = event->pos();
-
-                        if (acceptBtnRegion_.contains(point))
-                                emit acceptInvite(roomId_);
-
-                        if (declineBtnRegion_.contains(point))
-                                emit declineInvite(roomId_);
-
-                        return;
-                }
-
-                emit clicked(roomId_);
-
-                setPressedState(true);
-
-                // Ripple on mouse position by default.
-                QPoint pos           = event->pos();
-                qreal radiusEndValue = static_cast<qreal>(width()) / 3;
-
-                Ripple *ripple = new Ripple(pos);
-
-                ripple->setRadiusEndValue(radiusEndValue);
-                ripple->setOpacityStartValue(0.15);
-                ripple->setColor(QColor("white"));
-                ripple->radiusAnimation()->setDuration(200);
-                ripple->opacityAnimation()->setDuration(400);
-
-                ripple_overlay_->addRipple(ripple);
-        }
-}
-
-void
-RoomInfoListItem::setAvatar(const QString &avatar_url)
-{
-        if (avatar_url.isEmpty())
-                avatar_->setLetter(utils::firstChar(roomName_));
-        else
-                avatar_->setImage(avatar_url);
-}
-
-void
-RoomInfoListItem::setDescriptionMessage(const DescInfo &info)
-{
-        lastMsgInfo_ = info;
-        update();
-}
diff --git a/src/RoomInfoListItem.h b/src/RoomInfoListItem.h
deleted file mode 100644
index a5e0009e2b0dd137fc654913819f8fa644a7556a..0000000000000000000000000000000000000000
--- a/src/RoomInfoListItem.h
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QAction>
-#include <QDateTime>
-#include <QSharedPointer>
-#include <QWidget>
-
-#include <mtx/responses/sync.hpp>
-
-#include "CacheStructs.h"
-#include "UserSettingsPage.h"
-#include "ui/Avatar.h"
-
-class QMenu;
-class RippleOverlay;
-
-class RoomInfoListItem : public QWidget
-{
-        Q_OBJECT
-        Q_PROPERTY(QColor highlightedBackgroundColor READ highlightedBackgroundColor WRITE
-                     setHighlightedBackgroundColor)
-        Q_PROPERTY(
-          QColor hoverBackgroundColor READ hoverBackgroundColor WRITE setHoverBackgroundColor)
-        Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
-
-        Q_PROPERTY(QColor bubbleBgColor READ bubbleBgColor WRITE setBubbleBgColor)
-        Q_PROPERTY(QColor bubbleFgColor READ bubbleFgColor WRITE setBubbleFgColor)
-
-        Q_PROPERTY(QColor titleColor READ titleColor WRITE setTitleColor)
-        Q_PROPERTY(QColor subtitleColor READ subtitleColor WRITE setSubtitleColor)
-
-        Q_PROPERTY(QColor timestampColor READ timestampColor WRITE setTimestampColor)
-        Q_PROPERTY(QColor highlightedTimestampColor READ highlightedTimestampColor WRITE
-                     setHighlightedTimestampColor)
-        Q_PROPERTY(QColor hoverTimestampColor READ hoverTimestampColor WRITE setHoverTimestampColor)
-
-        Q_PROPERTY(
-          QColor highlightedTitleColor READ highlightedTitleColor WRITE setHighlightedTitleColor)
-        Q_PROPERTY(QColor highlightedSubtitleColor READ highlightedSubtitleColor WRITE
-                     setHighlightedSubtitleColor)
-
-        Q_PROPERTY(QColor hoverTitleColor READ hoverTitleColor WRITE setHoverTitleColor)
-        Q_PROPERTY(QColor hoverSubtitleColor READ hoverSubtitleColor WRITE setHoverSubtitleColor)
-
-        Q_PROPERTY(QColor mentionedColor READ mentionedColor WRITE setMentionedColor)
-        Q_PROPERTY(QColor btnColor READ btnColor WRITE setBtnColor)
-        Q_PROPERTY(QColor btnTextColor READ btnTextColor WRITE setBtnTextColor)
-
-public:
-        RoomInfoListItem(QString room_id, const RoomInfo &info, QWidget *parent = nullptr);
-
-        void updateUnreadMessageCount(int count, int highlightedCount);
-        void clearUnreadMessageCount() { updateUnreadMessageCount(0, 0); };
-
-        short int calculateImportance() const;
-
-        QString roomId() { return roomId_; }
-        bool isPressed() const { return isPressed_; }
-        int unreadMessageCount() const { return unreadMsgCount_; }
-
-        void setAvatar(const QString &avatar_url);
-        void setDescriptionMessage(const DescInfo &info);
-        DescInfo lastMessageInfo() const { return lastMsgInfo_; }
-
-        QColor highlightedBackgroundColor() const { return highlightedBackgroundColor_; }
-        QColor hoverBackgroundColor() const { return hoverBackgroundColor_; }
-        QColor hoverTitleColor() const { return hoverTitleColor_; }
-        QColor hoverSubtitleColor() const { return hoverSubtitleColor_; }
-        QColor hoverTimestampColor() const { return hoverTimestampColor_; }
-        QColor backgroundColor() const { return backgroundColor_; }
-
-        QColor highlightedTitleColor() const { return highlightedTitleColor_; }
-        QColor highlightedSubtitleColor() const { return highlightedSubtitleColor_; }
-        QColor highlightedTimestampColor() const { return highlightedTimestampColor_; }
-
-        QColor titleColor() const { return titleColor_; }
-        QColor subtitleColor() const { return subtitleColor_; }
-        QColor timestampColor() const { return timestampColor_; }
-        QColor btnColor() const { return btnColor_; }
-        QColor btnTextColor() const { return btnTextColor_; }
-
-        QColor bubbleFgColor() const { return bubbleFgColor_; }
-        QColor bubbleBgColor() const { return bubbleBgColor_; }
-        QColor mentionedColor() const { return mentionedFontColor_; }
-
-        void setHighlightedBackgroundColor(QColor &color) { highlightedBackgroundColor_ = color; }
-        void setHoverBackgroundColor(QColor &color) { hoverBackgroundColor_ = color; }
-        void setHoverSubtitleColor(QColor &color) { hoverSubtitleColor_ = color; }
-        void setHoverTitleColor(QColor &color) { hoverTitleColor_ = color; }
-        void setHoverTimestampColor(QColor &color) { hoverTimestampColor_ = color; }
-        void setBackgroundColor(QColor &color) { backgroundColor_ = color; }
-        void setTimestampColor(QColor &color) { timestampColor_ = color; }
-
-        void setHighlightedTitleColor(QColor &color) { highlightedTitleColor_ = color; }
-        void setHighlightedSubtitleColor(QColor &color) { highlightedSubtitleColor_ = color; }
-        void setHighlightedTimestampColor(QColor &color) { highlightedTimestampColor_ = color; }
-
-        void setTitleColor(QColor &color) { titleColor_ = color; }
-        void setSubtitleColor(QColor &color) { subtitleColor_ = color; }
-
-        void setBtnColor(QColor &color) { btnColor_ = color; }
-        void setBtnTextColor(QColor &color) { btnTextColor_ = color; }
-
-        void setBubbleFgColor(QColor &color) { bubbleFgColor_ = color; }
-        void setBubbleBgColor(QColor &color) { bubbleBgColor_ = color; }
-        void setMentionedColor(QColor &color) { mentionedFontColor_ = color; }
-
-        void setRoomName(const QString &name) { roomName_ = name; }
-        void setRoomType(bool isInvite)
-        {
-                if (isInvite)
-                        roomType_ = RoomType::Invited;
-                else
-                        roomType_ = RoomType::Joined;
-        }
-
-        bool isInvite() const { return roomType_ == RoomType::Invited; }
-        void setReadState(bool hasUnreadMessages)
-        {
-                if (hasUnreadMessages_ != hasUnreadMessages) {
-                        hasUnreadMessages_ = hasUnreadMessages;
-                        update();
-                }
-        }
-
-signals:
-        void clicked(const QString &room_id);
-        void leaveRoom(const QString &room_id);
-        void acceptInvite(const QString &room_id);
-        void declineInvite(const QString &room_id);
-
-public slots:
-        void setPressedState(bool state);
-
-protected:
-        void mousePressEvent(QMouseEvent *event) override;
-        void paintEvent(QPaintEvent *event) override;
-        void resizeEvent(QResizeEvent *event) override;
-        void contextMenuEvent(QContextMenuEvent *event) override;
-
-private:
-        void init(QWidget *parent);
-        QString roomName() { return roomName_; }
-
-        RippleOverlay *ripple_overlay_;
-        Avatar *avatar_;
-
-        enum class RoomType
-        {
-                Joined,
-                Invited,
-        };
-
-        RoomType roomType_ = RoomType::Joined;
-
-        // State information for the invited rooms.
-        mtx::responses::InvitedRoom invitedRoom_;
-
-        QString roomId_;
-        QString roomName_;
-
-        DescInfo lastMsgInfo_;
-
-        QMenu *menu_;
-        QAction *leaveRoom_;
-
-        bool isPressed_         = false;
-        bool hasUnreadMessages_ = true;
-
-        int unreadMsgCount_            = 0;
-        int unreadHighlightedMsgCount_ = 0;
-
-        QColor highlightedBackgroundColor_;
-        QColor hoverBackgroundColor_;
-        QColor backgroundColor_;
-
-        QColor highlightedTitleColor_;
-        QColor highlightedSubtitleColor_;
-
-        QColor titleColor_;
-        QColor subtitleColor_;
-
-        QColor hoverTitleColor_;
-        QColor hoverSubtitleColor_;
-
-        QColor btnColor_;
-        QColor btnTextColor_;
-
-        QRectF acceptBtnRegion_;
-        QRectF declineBtnRegion_;
-
-        // Fonts
-        QColor mentionedFontColor_;
-        QFont unreadCountFont_;
-        int bubbleDiameter_;
-
-        QColor timestampColor_;
-        QColor highlightedTimestampColor_;
-        QColor hoverTimestampColor_;
-
-        QColor bubbleBgColor_;
-        QColor bubbleFgColor_;
-
-        friend struct room_sort;
-};
diff --git a/src/RoomList.cpp b/src/RoomList.cpp
deleted file mode 100644
index 5839c4a0389001da37cdec374ed1f9c9a71d6ec5..0000000000000000000000000000000000000000
--- a/src/RoomList.cpp
+++ /dev/null
@@ -1,535 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <limits>
-#include <set>
-
-#include <QObject>
-#include <QPainter>
-#include <QScroller>
-#include <QStyle>
-#include <QStyleOption>
-#include <QTimer>
-
-#include "Logging.h"
-#include "MainWindow.h"
-#include "RoomInfoListItem.h"
-#include "RoomList.h"
-#include "UserSettingsPage.h"
-#include "Utils.h"
-#include "ui/OverlayModal.h"
-
-RoomList::RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent)
-  : QWidget(parent)
-{
-        topLayout_ = new QVBoxLayout(this);
-        topLayout_->setSpacing(0);
-        topLayout_->setMargin(0);
-
-        scrollArea_ = new QScrollArea(this);
-        scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-        scrollArea_->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
-        scrollArea_->setWidgetResizable(true);
-        scrollArea_->setAlignment(Qt::AlignLeading | Qt::AlignTop | Qt::AlignVCenter);
-        scrollArea_->setAttribute(Qt::WA_AcceptTouchEvents);
-
-        QScroller::grabGesture(scrollArea_, QScroller::TouchGesture);
-        QScroller::grabGesture(scrollArea_, QScroller::LeftMouseButtonGesture);
-
-// The scrollbar on macOS will hide itself when not active so it won't interfere
-// with the content.
-#if not defined(Q_OS_MAC)
-        scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-#endif
-
-        scrollAreaContents_ = new QWidget(this);
-        scrollAreaContents_->setObjectName("roomlist_area");
-
-        contentsLayout_ = new QVBoxLayout(scrollAreaContents_);
-        contentsLayout_->setAlignment(Qt::AlignTop);
-        contentsLayout_->setSpacing(0);
-        contentsLayout_->setMargin(0);
-
-        scrollArea_->setWidget(scrollAreaContents_);
-        topLayout_->addWidget(scrollArea_);
-
-        connect(this, &RoomList::updateRoomAvatarCb, this, &RoomList::updateRoomAvatar);
-        connect(userSettings.data(),
-                &UserSettings::roomSortingChanged,
-                this,
-                &RoomList::sortRoomsByLastMessage);
-}
-
-void
-RoomList::addRoom(const QString &room_id, const RoomInfo &info)
-{
-        auto room_item = new RoomInfoListItem(room_id, info, scrollArea_);
-        room_item->setRoomName(QString::fromStdString(std::move(info.name)));
-
-        connect(room_item, &RoomInfoListItem::clicked, this, &RoomList::highlightSelectedRoom);
-        connect(room_item, &RoomInfoListItem::leaveRoom, this, [](const QString &room_id) {
-                MainWindow::instance()->openLeaveRoomDialog(room_id);
-        });
-
-        QSharedPointer<RoomInfoListItem> roomWidget(room_item, &QObject::deleteLater);
-        rooms_.emplace(room_id, roomWidget);
-        rooms_sort_cache_.push_back(roomWidget);
-
-        if (!info.avatar_url.empty())
-                updateAvatar(room_id, QString::fromStdString(info.avatar_url));
-
-        int pos = contentsLayout_->count() - 1;
-        contentsLayout_->insertWidget(pos, room_item);
-}
-
-void
-RoomList::updateAvatar(const QString &room_id, const QString &url)
-{
-        emit updateRoomAvatarCb(room_id, url);
-}
-
-void
-RoomList::removeRoom(const QString &room_id, bool reset)
-{
-        auto roomIt = rooms_.find(room_id);
-        if (roomIt == rooms_.end()) {
-                return;
-        }
-
-        for (auto roomSortIt = rooms_sort_cache_.begin(); roomSortIt != rooms_sort_cache_.end();
-             ++roomSortIt) {
-                if (roomIt->second == *roomSortIt) {
-                        rooms_sort_cache_.erase(roomSortIt);
-                        break;
-                }
-        }
-        rooms_.erase(room_id);
-
-        if (rooms_.empty() || !reset)
-                return;
-
-        auto room = firstRoom();
-
-        if (room.second.isNull())
-                return;
-
-        room.second->setPressedState(true);
-        emit roomChanged(room.first);
-}
-
-void
-RoomList::updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount)
-{
-        if (!roomExists(roomid)) {
-                nhlog::ui()->warn("updateUnreadMessageCount: unknown room_id {}",
-                                  roomid.toStdString());
-                return;
-        }
-
-        rooms_[roomid]->updateUnreadMessageCount(count, highlightedCount);
-
-        calculateUnreadMessageCount();
-
-        sortRoomsByLastMessage();
-}
-
-void
-RoomList::calculateUnreadMessageCount()
-{
-        int total_unread_msgs = 0;
-
-        for (const auto &room : rooms_) {
-                if (!room.second.isNull())
-                        total_unread_msgs += room.second->unreadMessageCount();
-        }
-
-        emit totalUnreadMessageCountUpdated(total_unread_msgs);
-}
-
-void
-RoomList::initialize(const QMap<QString, RoomInfo> &info)
-{
-        nhlog::ui()->info("initialize room list");
-
-        rooms_.clear();
-
-        // prevent flickering and save time sorting over and over again
-        setUpdatesEnabled(false);
-        for (auto it = info.begin(); it != info.end(); it++) {
-                if (it.value().is_invite)
-                        addInvitedRoom(it.key(), it.value());
-                else
-                        addRoom(it.key(), it.value());
-        }
-
-        for (auto it = info.begin(); it != info.end(); it++)
-                updateRoomDescription(it.key(), it.value().msgInfo);
-
-        setUpdatesEnabled(true);
-
-        if (rooms_.empty())
-                return;
-
-        sortRoomsByLastMessage();
-
-        auto room = firstRoom();
-        if (room.second.isNull())
-                return;
-
-        room.second->setPressedState(true);
-        emit roomChanged(room.first);
-}
-
-void
-RoomList::cleanupInvites(const QHash<QString, RoomInfo> &invites)
-{
-        if (invites.size() == 0)
-                return;
-
-        utils::erase_if(rooms_, [invites](auto &room) {
-                auto room_id = room.first;
-                auto item    = room.second;
-
-                if (!item)
-                        return false;
-
-                return item->isInvite() && (invites.find(room_id) == invites.end());
-        });
-}
-
-void
-RoomList::sync(const std::map<QString, RoomInfo> &info)
-
-{
-        for (const auto &room : info)
-                updateRoom(room.first, room.second);
-
-        if (!info.empty())
-                sortRoomsByLastMessage();
-}
-
-void
-RoomList::highlightSelectedRoom(const QString &room_id)
-{
-        emit roomChanged(room_id);
-
-        if (!roomExists(room_id)) {
-                nhlog::ui()->warn("roomlist: clicked unknown room_id");
-                return;
-        }
-
-        for (auto const &room : rooms_) {
-                if (room.second.isNull())
-                        continue;
-
-                if (room.first != room_id) {
-                        room.second->setPressedState(false);
-                } else {
-                        room.second->setPressedState(true);
-                        scrollArea_->ensureWidgetVisible(room.second.data());
-                }
-        }
-
-        selectedRoom_ = room_id;
-}
-
-void
-RoomList::nextRoom()
-{
-        for (int ii = 0; ii < contentsLayout_->count() - 1; ++ii) {
-                auto room = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(ii)->widget());
-
-                if (!room)
-                        continue;
-
-                if (room->roomId() == selectedRoom_) {
-                        auto nextRoom = qobject_cast<RoomInfoListItem *>(
-                          contentsLayout_->itemAt(ii + 1)->widget());
-
-                        // Not a room message.
-                        if (!nextRoom || nextRoom->isInvite())
-                                return;
-
-                        emit roomChanged(nextRoom->roomId());
-                        if (!roomExists(nextRoom->roomId())) {
-                                nhlog::ui()->warn("roomlist: clicked unknown room_id");
-                                return;
-                        }
-
-                        room->setPressedState(false);
-                        nextRoom->setPressedState(true);
-
-                        scrollArea_->ensureWidgetVisible(nextRoom);
-                        selectedRoom_ = nextRoom->roomId();
-                        return;
-                }
-        }
-}
-
-void
-RoomList::previousRoom()
-{
-        for (int ii = 1; ii < contentsLayout_->count(); ++ii) {
-                auto room = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(ii)->widget());
-
-                if (!room)
-                        continue;
-
-                if (room->roomId() == selectedRoom_) {
-                        auto nextRoom = qobject_cast<RoomInfoListItem *>(
-                          contentsLayout_->itemAt(ii - 1)->widget());
-
-                        // Not a room message.
-                        if (!nextRoom || nextRoom->isInvite())
-                                return;
-
-                        emit roomChanged(nextRoom->roomId());
-                        if (!roomExists(nextRoom->roomId())) {
-                                nhlog::ui()->warn("roomlist: clicked unknown room_id");
-                                return;
-                        }
-
-                        room->setPressedState(false);
-                        nextRoom->setPressedState(true);
-
-                        scrollArea_->ensureWidgetVisible(nextRoom);
-                        selectedRoom_ = nextRoom->roomId();
-                        return;
-                }
-        }
-}
-
-void
-RoomList::updateRoomAvatar(const QString &roomid, const QString &img)
-{
-        if (!roomExists(roomid)) {
-                return;
-        }
-
-        rooms_[roomid]->setAvatar(img);
-
-        // Used to inform other widgets for the new image data.
-        emit roomAvatarChanged(roomid, img);
-}
-
-void
-RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info)
-{
-        if (!roomExists(roomid)) {
-                return;
-        }
-
-        rooms_[roomid]->setDescriptionMessage(info);
-
-        if (underMouse()) {
-                // When the user hover out of the roomlist a sort will be triggered.
-                isSortPending_ = true;
-                return;
-        }
-
-        isSortPending_ = false;
-
-        emit sortRoomsByLastMessage();
-}
-
-struct room_sort
-{
-        bool operator()(const QSharedPointer<RoomInfoListItem> &a,
-                        const QSharedPointer<RoomInfoListItem> &b) const
-        {
-                // Sort by "importance" (i.e. invites before mentions before
-                // notifs before new events before old events), then secondly
-                // by recency.
-
-                // Checking importance first
-                const auto a_importance = a->calculateImportance();
-                const auto b_importance = b->calculateImportance();
-                if (a_importance != b_importance) {
-                        return a_importance > b_importance;
-                }
-
-                // Now sort by recency
-                // Zero if empty, otherwise the time that the event occured
-                const uint64_t a_recency =
-                  a->lastMsgInfo_.userid.isEmpty() ? 0 : a->lastMsgInfo_.timestamp;
-                const uint64_t b_recency =
-                  b->lastMsgInfo_.userid.isEmpty() ? 0 : b->lastMsgInfo_.timestamp;
-                return a_recency > b_recency;
-        }
-};
-
-void
-RoomList::sortRoomsByLastMessage()
-{
-        isSortPending_ = false;
-
-        std::stable_sort(begin(rooms_sort_cache_), end(rooms_sort_cache_), room_sort{});
-
-        int newIndex = 0;
-        for (const auto &roomWidget : rooms_sort_cache_) {
-                const auto currentIndex = contentsLayout_->indexOf(roomWidget.data());
-
-                if (currentIndex != newIndex) {
-                        contentsLayout_->removeWidget(roomWidget.data());
-                        contentsLayout_->insertWidget(newIndex, roomWidget.data());
-                }
-                newIndex++;
-        }
-}
-
-void
-RoomList::leaveEvent(QEvent *event)
-{
-        if (isSortPending_)
-                QTimer::singleShot(700, this, &RoomList::sortRoomsByLastMessage);
-
-        QWidget::leaveEvent(event);
-}
-
-void
-RoomList::closeJoinRoomDialog(bool isJoining, QString roomAlias)
-{
-        joinRoomModal_->hide();
-
-        if (isJoining)
-                emit joinRoom(roomAlias);
-}
-
-void
-RoomList::removeFilter(const std::set<QString> &roomsToHide)
-{
-        setUpdatesEnabled(false);
-        for (int i = 0; i < contentsLayout_->count(); i++) {
-                auto widget =
-                  qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
-                if (widget) {
-                        if (roomsToHide.find(widget->roomId()) == roomsToHide.end())
-                                widget->show();
-                        else
-                                widget->hide();
-                }
-        }
-        setUpdatesEnabled(true);
-}
-
-void
-RoomList::applyFilter(const std::set<QString> &filter)
-{
-        // Disabling paint updates will resolve issues with screen flickering on big room lists.
-        setUpdatesEnabled(false);
-
-        for (int i = 0; i < contentsLayout_->count(); i++) {
-                // If filter contains the room for the current RoomInfoListItem,
-                // show the list item, otherwise hide it
-                auto listitem =
-                  qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
-
-                if (!listitem)
-                        continue;
-
-                if (filter.find(listitem->roomId()) != filter.end())
-                        listitem->show();
-                else
-                        listitem->hide();
-        }
-
-        setUpdatesEnabled(true);
-
-        // If the already selected room is part of the group, make sure it's visible.
-        if (!selectedRoom_.isEmpty() && (filter.find(selectedRoom_) != filter.end()))
-                return;
-
-        selectFirstVisibleRoom();
-}
-
-void
-RoomList::selectFirstVisibleRoom()
-{
-        for (int i = 0; i < contentsLayout_->count(); i++) {
-                auto item = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
-
-                if (item && item->isVisible()) {
-                        highlightSelectedRoom(item->roomId());
-                        break;
-                }
-        }
-}
-
-void
-RoomList::paintEvent(QPaintEvent *)
-{
-        QStyleOption opt;
-        opt.init(this);
-        QPainter p(this);
-        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
-}
-
-void
-RoomList::updateRoom(const QString &room_id, const RoomInfo &info)
-{
-        if (!roomExists(room_id)) {
-                if (info.is_invite)
-                        addInvitedRoom(room_id, info);
-                else
-                        addRoom(room_id, info);
-
-                return;
-        }
-
-        auto room = rooms_[room_id];
-        updateAvatar(room_id, QString::fromStdString(info.avatar_url));
-        room->setRoomName(QString::fromStdString(info.name));
-        room->setRoomType(info.is_invite);
-        room->update();
-}
-
-void
-RoomList::addInvitedRoom(const QString &room_id, const RoomInfo &info)
-{
-        auto room_item = new RoomInfoListItem(room_id, info, scrollArea_);
-
-        connect(room_item, &RoomInfoListItem::acceptInvite, this, &RoomList::acceptInvite);
-        connect(room_item, &RoomInfoListItem::declineInvite, this, &RoomList::declineInvite);
-
-        QSharedPointer<RoomInfoListItem> roomWidget(room_item);
-        rooms_.emplace(room_id, roomWidget);
-        rooms_sort_cache_.push_back(roomWidget);
-
-        updateAvatar(room_id, QString::fromStdString(info.avatar_url));
-
-        int pos = contentsLayout_->count() - 1;
-        contentsLayout_->insertWidget(pos, room_item);
-}
-
-std::pair<QString, QSharedPointer<RoomInfoListItem>>
-RoomList::firstRoom() const
-{
-        for (int i = 0; i < contentsLayout_->count(); i++) {
-                auto item = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(i)->widget());
-
-                if (item) {
-                        auto topRoom = rooms_.find(item->roomId());
-                        if (topRoom != rooms_.end()) {
-                                return std::pair<QString, QSharedPointer<RoomInfoListItem>>(
-                                  item->roomId(), topRoom->second);
-                        }
-                }
-        }
-
-        return {};
-}
-
-void
-RoomList::updateReadStatus(const std::map<QString, bool> &status)
-{
-        for (const auto &room : status) {
-                if (roomExists(room.first)) {
-                        auto item = rooms_.at(room.first);
-
-                        if (item)
-                                item->setReadState(room.second);
-                }
-        }
-}
diff --git a/src/RoomList.h b/src/RoomList.h
deleted file mode 100644
index af792fd7090e6568ec034fa3c0d75adc0d0a8b89..0000000000000000000000000000000000000000
--- a/src/RoomList.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-FileCopyrightText: 2017 Konstantinos Sideris <siderisk@auth.gr>
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QPushButton>
-#include <QScrollArea>
-#include <QSharedPointer>
-#include <QVBoxLayout>
-#include <QWidget>
-
-#include <set>
-
-#include "CacheStructs.h"
-#include "UserSettingsPage.h"
-
-class LeaveRoomDialog;
-class OverlayModal;
-class RoomInfoListItem;
-class Sync;
-struct DescInfo;
-struct RoomInfo;
-
-class RoomList : public QWidget
-{
-        Q_OBJECT
-
-public:
-        explicit RoomList(QSharedPointer<UserSettings> userSettings, QWidget *parent = nullptr);
-
-        void initialize(const QMap<QString, RoomInfo> &info);
-        void sync(const std::map<QString, RoomInfo> &info);
-
-        void clear()
-        {
-                rooms_.clear();
-                rooms_sort_cache_.clear();
-        };
-        void updateAvatar(const QString &room_id, const QString &url);
-
-        void addRoom(const QString &room_id, const RoomInfo &info);
-        void addInvitedRoom(const QString &room_id, const RoomInfo &info);
-        void removeRoom(const QString &room_id, bool reset);
-        //! Hide rooms that are not present in the given filter.
-        void applyFilter(const std::set<QString> &rooms);
-        //! Show all the available rooms.
-        void removeFilter(const std::set<QString> &roomsToHide);
-        void updateRoom(const QString &room_id, const RoomInfo &info);
-        void cleanupInvites(const QHash<QString, RoomInfo> &invites);
-
-signals:
-        void roomChanged(const QString &room_id);
-        void totalUnreadMessageCountUpdated(int count);
-        void acceptInvite(const QString &room_id);
-        void declineInvite(const QString &room_id);
-        void roomAvatarChanged(const QString &room_id, const QString &img);
-        void joinRoom(const QString &room_id);
-        void updateRoomAvatarCb(const QString &room_id, const QString &img);
-
-public slots:
-        void updateRoomAvatar(const QString &roomid, const QString &img);
-        void highlightSelectedRoom(const QString &room_id);
-        void updateUnreadMessageCount(const QString &roomid, int count, int highlightedCount);
-        void updateRoomDescription(const QString &roomid, const DescInfo &info);
-        void closeJoinRoomDialog(bool isJoining, QString roomAlias);
-        void updateReadStatus(const std::map<QString, bool> &status);
-        void nextRoom();
-        void previousRoom();
-
-protected:
-        void paintEvent(QPaintEvent *event) override;
-        void leaveEvent(QEvent *event) override;
-
-private slots:
-        void sortRoomsByLastMessage();
-
-private:
-        //! Return the first non-null room.
-        std::pair<QString, QSharedPointer<RoomInfoListItem>> firstRoom() const;
-        void calculateUnreadMessageCount();
-        bool roomExists(const QString &room_id) { return rooms_.find(room_id) != rooms_.end(); }
-        //! Select the first visible room in the room list.
-        void selectFirstVisibleRoom();
-
-        QVBoxLayout *topLayout_;
-        QVBoxLayout *contentsLayout_;
-        QScrollArea *scrollArea_;
-        QWidget *scrollAreaContents_;
-
-        QPushButton *joinRoomButton_;
-
-        OverlayModal *joinRoomModal_;
-
-        std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_;
-        std::vector<QSharedPointer<RoomInfoListItem>> rooms_sort_cache_;
-        QString selectedRoom_;
-
-        bool isSortPending_ = false;
-};
diff --git a/src/popups/PopupItem.cpp b/src/popups/PopupItem.cpp
deleted file mode 100644
index 2daa61435bf29326d4db42879c7b1bc98e43830d..0000000000000000000000000000000000000000
--- a/src/popups/PopupItem.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <QLabel>
-#include <QPaintEvent>
-#include <QPainter>
-#include <QStyleOption>
-
-#include "../Utils.h"
-#include "../ui/Avatar.h"
-#include "PopupItem.h"
-
-constexpr int PopupHMargin    = 4;
-constexpr int PopupItemMargin = 3;
-
-PopupItem::PopupItem(QWidget *parent)
-  : QWidget(parent)
-  , avatar_{new Avatar(this, conf::popup::avatar)}
-  , hovering_{false}
-{
-        setMouseTracking(true);
-        setAttribute(Qt::WA_Hover);
-
-        topLayout_ = new QHBoxLayout(this);
-        topLayout_->setContentsMargins(
-          PopupHMargin, PopupItemMargin, PopupHMargin, PopupItemMargin);
-
-        setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
-}
-
-void
-PopupItem::paintEvent(QPaintEvent *)
-{
-        QStyleOption opt;
-        opt.init(this);
-        QPainter p(this);
-        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
-
-        if (underMouse() || hovering_)
-                p.fillRect(rect(), hoverColor_);
-}
-
-RoomItem::RoomItem(QWidget *parent, const RoomSearchResult &res)
-  : PopupItem(parent)
-  , roomId_{QString::fromStdString(res.room_id)}
-{
-        auto name = QFontMetrics(QFont()).elidedText(
-          QString::fromStdString(res.info.name), Qt::ElideRight, parentWidget()->width() - 10);
-
-        avatar_->setLetter(utils::firstChar(name));
-
-        roomName_ = new QLabel(name, this);
-        roomName_->setMargin(0);
-
-        topLayout_->addWidget(avatar_);
-        topLayout_->addWidget(roomName_, 1);
-
-        if (!res.info.avatar_url.empty())
-                avatar_->setImage(QString::fromStdString(res.info.avatar_url));
-}
-
-void
-RoomItem::updateItem(const RoomSearchResult &result)
-{
-        roomId_ = QString::fromStdString(std::move(result.room_id));
-
-        auto name =
-          QFontMetrics(QFont()).elidedText(QString::fromStdString(std::move(result.info.name)),
-                                           Qt::ElideRight,
-                                           parentWidget()->width() - 10);
-
-        roomName_->setText(name);
-
-        // if there is not an avatar set for the room, we want to at least show the letter
-        // correctly!
-        avatar_->setLetter(utils::firstChar(name));
-        if (!result.info.avatar_url.empty())
-                avatar_->setImage(QString::fromStdString(result.info.avatar_url));
-}
-
-void
-RoomItem::mousePressEvent(QMouseEvent *event)
-{
-        if (event->buttons() != Qt::RightButton)
-                emit clicked(selectedText());
-
-        QWidget::mousePressEvent(event);
-}
diff --git a/src/popups/PopupItem.h b/src/popups/PopupItem.h
deleted file mode 100644
index fc24915eea60202e6b64d8722f5f16b5e9b6b06a..0000000000000000000000000000000000000000
--- a/src/popups/PopupItem.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QWidget>
-
-#include "../AvatarProvider.h"
-#include "../ChatPage.h"
-
-class Avatar;
-struct SearchResult;
-class QLabel;
-class QHBoxLayout;
-
-class PopupItem : public QWidget
-{
-        Q_OBJECT
-
-        Q_PROPERTY(QColor hoverColor READ hoverColor WRITE setHoverColor)
-        Q_PROPERTY(bool hovering READ hovering WRITE setHovering)
-
-public:
-        PopupItem(QWidget *parent);
-
-        QString selectedText() const { return QString(); }
-        QColor hoverColor() const { return hoverColor_; }
-        void setHoverColor(QColor &color) { hoverColor_ = color; }
-
-        bool hovering() const { return hovering_; }
-        void setHovering(const bool hover) { hovering_ = hover; };
-
-protected:
-        void paintEvent(QPaintEvent *event) override;
-
-signals:
-        void clicked(const QString &text);
-
-protected:
-        QHBoxLayout *topLayout_;
-        Avatar *avatar_;
-        QColor hoverColor_;
-
-        //! Set if the item is currently being
-        //! hovered during tab completion (cycling).
-        bool hovering_;
-};
-
-class RoomItem : public PopupItem
-{
-        Q_OBJECT
-
-public:
-        RoomItem(QWidget *parent, const RoomSearchResult &res);
-        QString selectedText() const { return roomId_; }
-        void updateItem(const RoomSearchResult &res);
-
-protected:
-        void mousePressEvent(QMouseEvent *event) override;
-
-private:
-        QLabel *roomName_;
-        QString roomId_;
-        RoomSearchResult info_;
-};
diff --git a/src/popups/SuggestionsPopup.cpp b/src/popups/SuggestionsPopup.cpp
deleted file mode 100644
index 7b545d61690bcb802d12037fdbd800decd687fd9..0000000000000000000000000000000000000000
--- a/src/popups/SuggestionsPopup.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <QPaintEvent>
-#include <QPainter>
-#include <QStyleOption>
-
-#include "../Config.h"
-#include "../Utils.h"
-#include "../ui/Avatar.h"
-#include "../ui/DropShadow.h"
-#include "ChatPage.h"
-#include "PopupItem.h"
-#include "SuggestionsPopup.h"
-
-SuggestionsPopup::SuggestionsPopup(QWidget *parent)
-  : QWidget(parent)
-{
-        setAttribute(Qt::WA_ShowWithoutActivating, true);
-        setWindowFlags(Qt::ToolTip | Qt::NoDropShadowWindowHint);
-
-        layout_ = new QVBoxLayout(this);
-        layout_->setMargin(0);
-        layout_->setSpacing(0);
-}
-
-QString
-SuggestionsPopup::displayName(QString room, QString user)
-{
-        return cache::displayName(room, user);
-}
-
-void
-SuggestionsPopup::addRooms(const std::vector<RoomSearchResult> &rooms)
-{
-        if (rooms.empty()) {
-                hide();
-                return;
-        }
-
-        const int layoutCount = (int)layout_->count();
-        const int roomCount   = (int)rooms.size();
-
-        // Remove the extra widgets from the layout.
-        if (roomCount < layoutCount)
-                removeLayoutItemsAfter(roomCount - 1);
-
-        for (int i = 0; i < roomCount; ++i) {
-                auto item = layout_->itemAt(i);
-
-                // Create a new widget if there isn't already one in that
-                // layout position.
-                if (!item) {
-                        auto room = new RoomItem(this, rooms.at(i));
-                        connect(room, &RoomItem::clicked, this, &SuggestionsPopup::itemSelected);
-                        layout_->addWidget(room);
-                } else {
-                        // Update the current widget with the new data.
-                        auto room = qobject_cast<RoomItem *>(item->widget());
-                        if (room)
-                                room->updateItem(rooms.at(i));
-                }
-        }
-
-        resetSelection();
-        adjustSize();
-
-        resize(geometry().width(), 40 * (int)rooms.size());
-
-        selectNextSuggestion();
-}
-
-void
-SuggestionsPopup::hoverSelection()
-{
-        resetHovering();
-        setHovering(selectedItem_);
-        update();
-}
-
-void
-SuggestionsPopup::selectHoveredSuggestion()
-{
-        const auto item = layout_->itemAt(selectedItem_);
-        if (!item)
-                return;
-
-        const auto &widget = qobject_cast<RoomItem *>(item->widget());
-        emit itemSelected(displayName(ChatPage::instance()->currentRoom(), widget->selectedText()));
-
-        resetSelection();
-}
-
-void
-SuggestionsPopup::selectNextSuggestion()
-{
-        selectedItem_++;
-        if (selectedItem_ >= layout_->count())
-                selectFirstItem();
-
-        hoverSelection();
-}
-
-void
-SuggestionsPopup::selectPreviousSuggestion()
-{
-        selectedItem_--;
-        if (selectedItem_ < 0)
-                selectLastItem();
-
-        hoverSelection();
-}
-
-void
-SuggestionsPopup::resetHovering()
-{
-        for (int i = 0; i < layout_->count(); ++i) {
-                const auto item = qobject_cast<PopupItem *>(layout_->itemAt(i)->widget());
-
-                if (item)
-                        item->setHovering(false);
-        }
-}
-
-void
-SuggestionsPopup::setHovering(int pos)
-{
-        const auto &item   = layout_->itemAt(pos);
-        const auto &widget = qobject_cast<PopupItem *>(item->widget());
-
-        if (widget)
-                widget->setHovering(true);
-}
-
-void
-SuggestionsPopup::paintEvent(QPaintEvent *)
-{
-        QStyleOption opt;
-        opt.init(this);
-        QPainter p(this);
-        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
-}
-
-void
-SuggestionsPopup::selectLastItem()
-{
-        selectedItem_ = layout_->count() - 1;
-}
-
-void
-SuggestionsPopup::removeLayoutItemsAfter(size_t startingPos)
-{
-        size_t posToRemove = layout_->count() - 1;
-
-        QLayoutItem *item;
-        while (startingPos <= posToRemove &&
-               (item = layout_->takeAt((int)posToRemove)) != nullptr) {
-                delete item->widget();
-                delete item;
-
-                posToRemove = layout_->count() - 1;
-        }
-}
diff --git a/src/popups/SuggestionsPopup.h b/src/popups/SuggestionsPopup.h
deleted file mode 100644
index 281edddb9fd02d52ce499dc0100a386ae85f71d6..0000000000000000000000000000000000000000
--- a/src/popups/SuggestionsPopup.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QWidget>
-
-#include "CacheStructs.h"
-
-class QVBoxLayout;
-class QLayoutItem;
-
-class SuggestionsPopup : public QWidget
-{
-        Q_OBJECT
-
-public:
-        explicit SuggestionsPopup(QWidget *parent = nullptr);
-
-        void selectHoveredSuggestion();
-
-public slots:
-        void addRooms(const std::vector<RoomSearchResult> &rooms);
-
-        //! Move to the next available suggestion item.
-        void selectNextSuggestion();
-        //! Move to the previous available suggestion item.
-        void selectPreviousSuggestion();
-        //! Remove hovering from all items.
-        void resetHovering();
-        //! Set hovering to the item in the given layout position.
-        void setHovering(int pos);
-
-protected:
-        void paintEvent(QPaintEvent *event) override;
-
-signals:
-        void itemSelected(const QString &user);
-
-private:
-        QString displayName(QString roomid, QString userid);
-        void hoverSelection();
-        void resetSelection() { selectedItem_ = -1; }
-        void selectFirstItem() { selectedItem_ = 0; }
-        void selectLastItem();
-        void removeLayoutItemsAfter(size_t startingPos);
-
-        QVBoxLayout *layout_;
-
-        //! Counter for tab completion (cycling).
-        int selectedItem_ = -1;
-};
diff --git a/src/popups/UserMentions.cpp b/src/popups/UserMentions.cpp
deleted file mode 100644
index 56b57503a7fd5ea89ed71bcef3dd0994c296fd22..0000000000000000000000000000000000000000
--- a/src/popups/UserMentions.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <QPaintEvent>
-#include <QPainter>
-#include <QScrollArea>
-#include <QStyleOption>
-#include <QTabWidget>
-#include <QTimer>
-#include <QVBoxLayout>
-
-#include "Cache.h"
-#include "ChatPage.h"
-#include "EventAccessors.h"
-#include "Logging.h"
-#include "UserMentions.h"
-
-using namespace popups;
-
-UserMentions::UserMentions(QWidget *parent)
-  : QWidget{parent}
-{
-        setAttribute(Qt::WA_ShowWithoutActivating, true);
-        setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
-
-        tab_layout_ = new QTabWidget(this);
-
-        top_layout_ = new QVBoxLayout(this);
-        top_layout_->setSpacing(0);
-        top_layout_->setMargin(0);
-
-        local_scroll_area_ = new QScrollArea(this);
-        local_scroll_area_->setWidgetResizable(true);
-        local_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-
-        local_scroll_widget_ = new QWidget(this);
-        local_scroll_widget_->setObjectName("local_scroll_widget");
-
-        all_scroll_area_ = new QScrollArea(this);
-        all_scroll_area_->setWidgetResizable(true);
-        all_scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-
-        all_scroll_widget_ = new QWidget(this);
-        all_scroll_widget_->setObjectName("all_scroll_widget");
-
-        // Height of the typing display.
-        QFont f;
-        f.setPointSizeF(f.pointSizeF() * 0.9);
-        const int bottomMargin = QFontMetrics(f).height() + 6;
-
-        local_scroll_layout_ = new QVBoxLayout(local_scroll_widget_);
-        local_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin);
-        local_scroll_layout_->setSpacing(0);
-        local_scroll_layout_->setObjectName("localscrollarea");
-
-        all_scroll_layout_ = new QVBoxLayout(all_scroll_widget_);
-        all_scroll_layout_->setContentsMargins(4, 0, 15, bottomMargin);
-        all_scroll_layout_->setSpacing(0);
-        all_scroll_layout_->setObjectName("allscrollarea");
-
-        local_scroll_area_->setWidget(local_scroll_widget_);
-        local_scroll_area_->setAlignment(Qt::AlignBottom);
-
-        all_scroll_area_->setWidget(all_scroll_widget_);
-        all_scroll_area_->setAlignment(Qt::AlignBottom);
-
-        tab_layout_->addTab(local_scroll_area_, tr("This Room"));
-        tab_layout_->addTab(all_scroll_area_, tr("All Rooms"));
-        top_layout_->addWidget(tab_layout_);
-
-        setLayout(top_layout_);
-}
-
-void
-UserMentions::initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs)
-{
-        nhlog::ui()->debug("Initializing " + std::to_string(notifs.size()) + " notifications.");
-
-        for (const auto &item : notifs) {
-                for (const auto &notif : item.notifications) {
-                        const auto event_id =
-                          QString::fromStdString(mtx::accessors::event_id(notif.event));
-
-                        try {
-                                const auto room_id = QString::fromStdString(notif.room_id);
-                                const auto user_id =
-                                  QString::fromStdString(mtx::accessors::sender(notif.event));
-                                const auto body =
-                                  QString::fromStdString(mtx::accessors::body(notif.event));
-
-                                pushItem(event_id,
-                                         user_id,
-                                         body,
-                                         room_id,
-                                         ChatPage::instance()->currentRoom());
-
-                        } catch (const lmdb::error &e) {
-                                nhlog::db()->warn("error while sending desktop notification: {}",
-                                                  e.what());
-                        }
-                }
-        }
-}
-
-void
-UserMentions::showPopup()
-{
-        for (auto widget : all_scroll_layout_->findChildren<QWidget *>()) {
-                delete widget;
-        }
-        for (auto widget : local_scroll_layout_->findChildren<QWidget *>()) {
-                delete widget;
-        }
-
-        auto notifs = cache::getTimelineMentions();
-
-        initializeMentions(notifs);
-        show();
-}
-
-void
-UserMentions::pushItem(const QString &event_id,
-                       const QString &user_id,
-                       const QString &body,
-                       const QString &room_id,
-                       const QString &current_room_id)
-{
-        (void)event_id;
-        (void)user_id;
-        (void)body;
-        (void)room_id;
-        (void)current_room_id;
-        //        setUpdatesEnabled(false);
-        //
-        //        // Add to the 'all' section
-        //        TimelineItem *view_item = new TimelineItem(
-        //          mtx::events::MessageType::Text, user_id, body, true, room_id,
-        //          all_scroll_widget_);
-        //        view_item->setEventId(event_id);
-        //        view_item->hide();
-        //
-        //        all_scroll_layout_->addWidget(view_item);
-        //        QTimer::singleShot(0, this, [view_item, this]() {
-        //                view_item->show();
-        //                view_item->adjustSize();
-        //                setUpdatesEnabled(true);
-        //        });
-        //
-        //        // if it matches the current room... add it to the current room as well.
-        //        if (QString::compare(room_id, current_room_id, Qt::CaseInsensitive) == 0) {
-        //                // Add to the 'local' section
-        //                TimelineItem *local_view_item = new
-        //                TimelineItem(mtx::events::MessageType::Text,
-        //                                                                 user_id,
-        //                                                                 body,
-        //                                                                 true,
-        //                                                                 room_id,
-        //                                                                 local_scroll_widget_);
-        //                local_view_item->setEventId(event_id);
-        //                local_view_item->hide();
-        //                local_scroll_layout_->addWidget(local_view_item);
-        //
-        //                QTimer::singleShot(0, this, [local_view_item]() {
-        //                        local_view_item->show();
-        //                        local_view_item->adjustSize();
-        //                });
-        //        }
-}
-
-void
-UserMentions::paintEvent(QPaintEvent *)
-{
-        QStyleOption opt;
-        opt.init(this);
-        QPainter p(this);
-        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
-}
diff --git a/src/popups/UserMentions.h b/src/popups/UserMentions.h
deleted file mode 100644
index f0b662d8d9d77e8f0fea489b4b6526a946dfe438..0000000000000000000000000000000000000000
--- a/src/popups/UserMentions.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-FileCopyrightText: 2021 Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <mtx/responses/notifications.hpp>
-
-#include <QMap>
-#include <QString>
-#include <QWidget>
-
-class QPaintEvent;
-class QTabWidget;
-class QScrollArea;
-class QVBoxLayout;
-
-namespace popups {
-
-class UserMentions : public QWidget
-{
-        Q_OBJECT
-public:
-        UserMentions(QWidget *parent = nullptr);
-
-        void initializeMentions(const QMap<QString, mtx::responses::Notifications> &notifs);
-        void showPopup();
-
-protected:
-        void paintEvent(QPaintEvent *) override;
-
-private:
-        void pushItem(const QString &event_id,
-                      const QString &user_id,
-                      const QString &body,
-                      const QString &room_id,
-                      const QString &current_room_id);
-        QTabWidget *tab_layout_;
-        QVBoxLayout *top_layout_;
-        QVBoxLayout *local_scroll_layout_;
-        QVBoxLayout *all_scroll_layout_;
-
-        QScrollArea *local_scroll_area_;
-        QWidget *local_scroll_widget_;
-
-        QScrollArea *all_scroll_area_;
-        QWidget *all_scroll_widget_;
-};
-}
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index a283d24e9fe4c2a5090c088faa5fa464f57a95ca..c309daab37d32bd065c18afe29c5998ccfbbb5eb 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -20,6 +20,7 @@
 #include "Cache.h"
 #include "ChatPage.h"
 #include "CompletionProxyModel.h"
+#include "Config.h"
 #include "Logging.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index ad4177a49af893606623ef40ebc094b7f5b2dc64..9f926d2b9bf2e153b61aa4063b62fe9f5e1f7e0e 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -530,3 +530,33 @@ FilteredRoomlistModel::toggleTag(QString roomid, QString tag, bool on)
                   });
         }
 }
+
+void
+FilteredRoomlistModel::nextRoom()
+{
+        auto r = currentRoom();
+
+        if (r) {
+                int idx = roomidToIndex(r->roomId());
+                idx++;
+                if (idx < rowCount()) {
+                        setCurrentRoom(
+                          data(index(idx, 0), RoomlistModel::Roles::RoomId).toString());
+                }
+        }
+}
+
+void
+FilteredRoomlistModel::previousRoom()
+{
+        auto r = currentRoom();
+
+        if (r) {
+                int idx = roomidToIndex(r->roomId());
+                idx--;
+                if (idx > 0) {
+                        setCurrentRoom(
+                          data(index(idx, 0), RoomlistModel::Roles::RoomId).toString());
+                }
+        }
+}
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 1c6fa8339c682216b66337f69cf087cc82316416..d3e1e1f9fa78e1521a626be4b13ab8cbe3229c83 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -118,6 +118,9 @@ public slots:
         TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
         void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
 
+        void nextRoom();
+        void previousRoom();
+
 signals:
         void currentRoomChanged();