summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CMakeLists.txt3
-rw-r--r--im.nheko.Nheko.yaml2
-rw-r--r--src/Cache.cpp2
-rw-r--r--src/CacheCryptoStructs.cpp15
-rw-r--r--src/CacheCryptoStructs.h11
-rw-r--r--src/Cache_p.h8
-rw-r--r--src/ChatPage.cpp2
-rw-r--r--src/EventAccessors.h26
-rw-r--r--src/InviteesModel.cpp1
-rw-r--r--src/InviteesModel.h2
-rw-r--r--src/JdenticonProvider.h2
-rw-r--r--src/MainWindow.cpp2
-rw-r--r--src/MemberList.cpp2
-rw-r--r--src/MxcImageProvider.cpp3
-rw-r--r--src/MxcImageProvider.h6
-rw-r--r--src/RegisterPage.h3
-rw-r--r--src/RoomDirectoryModel.cpp2
-rw-r--r--src/TrayIcon.h2
-rw-r--r--src/dbus/NhekoDBusBackend.cpp1
-rw-r--r--src/encryption/DeviceVerificationFlow.cpp1
-rw-r--r--src/encryption/DeviceVerificationFlow.h6
-rw-r--r--src/encryption/VerificationManager.cpp3
-rw-r--r--src/timeline/EventDelegateChooser.h2
-rw-r--r--src/timeline/InputBar.cpp1
-rw-r--r--src/timeline/RoomlistModel.cpp28
-rw-r--r--src/timeline/RoomlistModel.h29
-rw-r--r--src/timeline/TimelineFilter.cpp1
-rw-r--r--src/timeline/TimelineFilter.h2
-rw-r--r--src/timeline/TimelineModel.cpp6
-rw-r--r--src/timeline/TimelineModel.h5
-rw-r--r--src/timeline/TimelineViewManager.cpp63
-rw-r--r--src/timeline/TimelineViewManager.h61
-rw-r--r--src/ui/MxcAnimatedImage.h2
-rw-r--r--src/ui/MxcMediaProxy.cpp1
-rw-r--r--src/ui/NhekoDropArea.cpp1
-rw-r--r--src/ui/NhekoGlobalObject.cpp3
-rw-r--r--src/ui/UIA.cpp1
-rw-r--r--src/ui/UserProfile.cpp1
-rw-r--r--src/ui/UserProfile.h4
39 files changed, 198 insertions, 118 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6b4bf52f..99fb2ab1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -444,6 +444,7 @@ set(SRC_FILES
     src/BlurhashProvider.h
     src/Cache.cpp
     src/Cache.h
+    src/CacheCryptoStructs.cpp
     src/CacheCryptoStructs.h
     src/CacheStructs.h
     src/Cache_p.h
@@ -603,7 +604,7 @@ if(USE_BUNDLED_MTXCLIENT)
     FetchContent_Declare(
         MatrixClient
             GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
-            GIT_TAG        188ecb899744e55842c1debaa4597cdc5184be8a
+            GIT_TAG        4fb7d678aeea197d16b52bfb1dc35b506673bb52
     )
     set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
     set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
diff --git a/im.nheko.Nheko.yaml b/im.nheko.Nheko.yaml
index a2141baa..ad879e7a 100644
--- a/im.nheko.Nheko.yaml
+++ b/im.nheko.Nheko.yaml
@@ -223,7 +223,7 @@ modules:
     buildsystem: cmake-ninja
     name: mtxclient
     sources:
-      - commit: 188ecb899744e55842c1debaa4597cdc5184be8a
+      - commit: 4fb7d678aeea197d16b52bfb1dc35b506673bb52
         #tag: v0.9.2
         type: git
         url: https://github.com/Nheko-Reborn/mtxclient.git
diff --git a/src/Cache.cpp b/src/Cache.cpp
index f8d282e0..e12e9512 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -6296,3 +6296,5 @@ NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::policy_rule::ServerRu
 NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Child)
 NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::state::space::Parent)
 NHEKO_CACHE_GET_STATE_EVENT_DEFINITION(mtx::events::msc2545::ImagePack)
+
+#include "moc_Cache_p.cpp"
diff --git a/src/CacheCryptoStructs.cpp b/src/CacheCryptoStructs.cpp
new file mode 100644
index 00000000..7dc2468a
--- /dev/null
+++ b/src/CacheCryptoStructs.cpp
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "CacheCryptoStructs.h"
+
+#include <mtx/events/encrypted.hpp>
+
+MegolmSessionIndex::MegolmSessionIndex(std::string room_id_, const mtx::events::msg::Encrypted &e)
+  : room_id(std::move(room_id_))
+  , session_id(e.session_id)
+{
+}
+
+#include "moc_CacheCryptoStructs.cpp"
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index 22c7bcf0..11644a2b 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -11,10 +11,13 @@
 #include <mutex>
 #include <set>
 
-#include <mtx/events/encrypted.hpp>
 #include <mtx/responses/crypto.hpp>
 #include <mtxclient/crypto/objects.hpp>
 
+namespace mtx::events::msg {
+struct Encrypted;
+}
+
 namespace crypto {
 Q_NAMESPACE
 QML_NAMED_ELEMENT(Crypto)
@@ -96,11 +99,7 @@ from_json(const nlohmann::json &obj, DevicePublicKeys &msg);
 struct MegolmSessionIndex
 {
     MegolmSessionIndex() = default;
-    MegolmSessionIndex(std::string room_id_, const mtx::events::msg::Encrypted &e)
-      : room_id(std::move(room_id_))
-      , session_id(e.session_id)
-    {
-    }
+    MegolmSessionIndex(std::string room_id_, const mtx::events::msg::Encrypted &e);
 
     //! The room in which this session exists.
     std::string room_id;
diff --git a/src/Cache_p.h b/src/Cache_p.h
index 24ea2939..ad03bb0e 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -19,13 +19,14 @@
 #include <mtx/responses/notifications.hpp>
 #include <mtx/responses/sync.hpp>
 #include <mtxclient/crypto/types.hpp>
-#include <mtxclient/http/client.hpp>
+#include <mtxclient/http/errors.hpp>
 
 #include "CacheCryptoStructs.h"
 #include "CacheStructs.h"
 
 namespace mtx::responses {
 struct Messages;
+struct StateEvents;
 }
 
 class Cache final : public QObject
@@ -51,8 +52,9 @@ public:
                                lmdb::dbi &db,
                                const std::vector<std::string> &user_ids,
                                const std::string &sync_token);
-    void query_keys(const std::string &user_id,
-                    std::function<void(const UserKeyCache &, mtx::http::RequestErr)> cb);
+    void query_keys(
+      const std::string &user_id,
+      std::function<void(const UserKeyCache &, const std::optional<mtx::http::ClientError> &)> cb);
 
     // device & user verification cache
     std::optional<UserKeyCache> userKeys(const std::string &user_id);
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 956888d0..be05f8bd 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -31,6 +31,8 @@
 
 #include "notifications/Manager.h"
 
+#include "timeline/RoomlistModel.h"
+#include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 
 ChatPage *ChatPage::instance_                    = nullptr;
diff --git a/src/EventAccessors.h b/src/EventAccessors.h
index 3651e941..9868d290 100644
--- a/src/EventAccessors.h
+++ b/src/EventAccessors.h
@@ -17,32 +17,6 @@ struct TimelineEvents;
 struct StateEvents;
 }
 
-namespace nheko {
-struct nonesuch
-{
-    ~nonesuch()                      = delete;
-    nonesuch(nonesuch const &)       = delete;
-    void operator=(nonesuch const &) = delete;
-};
-
-namespace detail {
-template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
-struct detector
-{
-    using value_t = std::false_type;
-    using type    = Default;
-};
-
-template<class Default, template<class...> class Op, class... Args>
-struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
-{
-    using value_t = std::true_type;
-    using type    = Op<Args...>;
-};
-
-} // namespace detail
-}
-
 namespace mtx::accessors {
 const std::string &
 event_id(const mtx::events::collections::TimelineEvents &event);
diff --git a/src/InviteesModel.cpp b/src/InviteesModel.cpp
index 7385c118..4dc8372a 100644
--- a/src/InviteesModel.cpp
+++ b/src/InviteesModel.cpp
@@ -7,6 +7,7 @@
 #include "Logging.h"
 #include "MatrixClient.h"
 #include "mtx/responses/profile.hpp"
+#include "timeline/TimelineModel.h"
 
 InviteesModel::InviteesModel(TimelineModel *room, QObject *parent)
   : QAbstractListModel{parent}
diff --git a/src/InviteesModel.h b/src/InviteesModel.h
index 36d04c0f..64e013b1 100644
--- a/src/InviteesModel.h
+++ b/src/InviteesModel.h
@@ -8,7 +8,7 @@
 #include <QQmlEngine>
 #include <QVector>
 
-#include "timeline/TimelineModel.h"
+class TimelineModel;
 
 class Invitee final : public QObject
 {
diff --git a/src/JdenticonProvider.h b/src/JdenticonProvider.h
index 1c2c0665..f13efc46 100644
--- a/src/JdenticonProvider.h
+++ b/src/JdenticonProvider.h
@@ -9,8 +9,6 @@
 #include <QQuickImageResponse>
 #include <QThreadPool>
 
-#include <mtx/common.hpp>
-
 class JdenticonRunnable final
   : public QObject
   , public QRunnable
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 9f719227..ea9f560d 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -24,6 +24,8 @@
 #include "Utils.h"
 #include "dock/Dock.h"
 #include "encryption/DeviceVerificationFlow.h"
+#include "timeline/RoomlistModel.h"
+#include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 #include "ui/Theme.h"
 #include "voip/CallManager.h"
diff --git a/src/MemberList.cpp b/src/MemberList.cpp
index 56f2b5b7..1d939bfa 100644
--- a/src/MemberList.cpp
+++ b/src/MemberList.cpp
@@ -8,6 +8,8 @@
 #include "Cache_p.h"
 #include "ChatPage.h"
 #include "Logging.h"
+#include "timeline/RoomlistModel.h"
+#include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 
 MemberListBackend::MemberListBackend(const QString &room_id, QObject *parent)
diff --git a/src/MxcImageProvider.cpp b/src/MxcImageProvider.cpp
index de8027c3..8d1ac01e 100644
--- a/src/MxcImageProvider.cpp
+++ b/src/MxcImageProvider.cpp
@@ -6,6 +6,7 @@
 
 #include <optional>
 
+#include <mtx/common.hpp>
 #include <mtxclient/crypto/client.hpp>
 
 #include <QByteArray>
@@ -87,7 +88,7 @@ MxcImageProvider::requestImageResponse(const QString &id, const QSize &requested
 }
 
 void
-MxcImageProvider::addEncryptionInfo(mtx::crypto::EncryptedFile info)
+MxcImageProvider::addEncryptionInfo(const mtx::crypto::EncryptedFile &info)
 {
     infos.insert(QString::fromStdString(info.url), info);
 }
diff --git a/src/MxcImageProvider.h b/src/MxcImageProvider.h
index 5c3e5c58..3ee67fc5 100644
--- a/src/MxcImageProvider.h
+++ b/src/MxcImageProvider.h
@@ -11,7 +11,9 @@
 
 #include <functional>
 
-#include <mtx/common.hpp>
+namespace mtx::crypto {
+struct EncryptedFile;
+}
 
 class MxcImageRunnable final : public QObject
 {
@@ -81,7 +83,7 @@ public slots:
     QQuickImageResponse *
     requestImageResponse(const QString &id, const QSize &requestedSize) override;
 
-    static void addEncryptionInfo(mtx::crypto::EncryptedFile info);
+    static void addEncryptionInfo(const mtx::crypto::EncryptedFile &info);
     static void download(const QString &id,
                          const QSize &requestedSize,
                          std::function<void(QString, QSize, QImage, QString)> then,
diff --git a/src/RegisterPage.h b/src/RegisterPage.h
index e26acaba..84463c1c 100644
--- a/src/RegisterPage.h
+++ b/src/RegisterPage.h
@@ -8,9 +8,6 @@
 #include <QQmlEngine>
 #include <QString>
 
-#include <mtx/user_interactive.hpp>
-#include <mtxclient/http/client.hpp>
-
 class RegisterPage : public QObject
 {
     Q_OBJECT
diff --git a/src/RoomDirectoryModel.cpp b/src/RoomDirectoryModel.cpp
index 9a71cbc3..12e0aa72 100644
--- a/src/RoomDirectoryModel.cpp
+++ b/src/RoomDirectoryModel.cpp
@@ -6,6 +6,8 @@
 
 #include <algorithm>
 
+#include <mtx/requests.hpp>
+
 #include "Cache.h"
 #include "ChatPage.h"
 #include "Logging.h"
diff --git a/src/TrayIcon.h b/src/TrayIcon.h
index 23da7549..f2009612 100644
--- a/src/TrayIcon.h
+++ b/src/TrayIcon.h
@@ -47,5 +47,7 @@ private:
     QAction *viewAction_;
     QAction *quitAction_;
 
+#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN)
     MsgCountComposedIcon *icon_;
+#endif
 };
diff --git a/src/dbus/NhekoDBusBackend.cpp b/src/dbus/NhekoDBusBackend.cpp
index b397a670..898286f8 100644
--- a/src/dbus/NhekoDBusBackend.cpp
+++ b/src/dbus/NhekoDBusBackend.cpp
@@ -12,6 +12,7 @@
 #include "MainWindow.h"
 #include "MxcImageProvider.h"
 #include "timeline/RoomlistModel.h"
+#include "timeline/TimelineModel.h"
 
 #include <QDBusConnection>
 
diff --git a/src/encryption/DeviceVerificationFlow.cpp b/src/encryption/DeviceVerificationFlow.cpp
index ac228669..cb595df0 100644
--- a/src/encryption/DeviceVerificationFlow.cpp
+++ b/src/encryption/DeviceVerificationFlow.cpp
@@ -15,6 +15,7 @@
 #include "Cache_p.h"
 #include "ChatPage.h"
 #include "Logging.h"
+#include "MatrixClient.h"
 #include "Utils.h"
 #include "timeline/TimelineModel.h"
 
diff --git a/src/encryption/DeviceVerificationFlow.h b/src/encryption/DeviceVerificationFlow.h
index 6f8f413e..f78f0dbd 100644
--- a/src/encryption/DeviceVerificationFlow.h
+++ b/src/encryption/DeviceVerificationFlow.h
@@ -5,13 +5,11 @@
 #pragma once
 
 #include <QObject>
+#include <QQmlEngine>
 
-#include <mtx/responses/crypto.hpp>
 #include <mtxclient/crypto/client.hpp>
 
 #include "CacheCryptoStructs.h"
-#include "Logging.h"
-#include "MatrixClient.h"
 
 class QTimer;
 class TimelineModel;
@@ -152,8 +150,6 @@ public:
     bool isSelfVerification() const;
     bool isMultiDeviceVerification() const { return deviceIds.size() > 1; }
 
-    void callback_fn(const UserKeyCache &res, mtx::http::RequestErr err, std::string user_id);
-
 public slots:
     //! unverifies a device
     void unverify();
diff --git a/src/encryption/VerificationManager.cpp b/src/encryption/VerificationManager.cpp
index 985bd619..2b5b7f20 100644
--- a/src/encryption/VerificationManager.cpp
+++ b/src/encryption/VerificationManager.cpp
@@ -9,6 +9,9 @@
 #include "Cache.h"
 #include "ChatPage.h"
 #include "DeviceVerificationFlow.h"
+#include "Logging.h"
+#include "timeline/RoomlistModel.h"
+#include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 
 VerificationManager::VerificationManager(TimelineViewManager *o)
diff --git a/src/timeline/EventDelegateChooser.h b/src/timeline/EventDelegateChooser.h
index 139b143a..f5c683e1 100644
--- a/src/timeline/EventDelegateChooser.h
+++ b/src/timeline/EventDelegateChooser.h
@@ -12,7 +12,7 @@
 #include <QtCore/QObject>
 #include <QtCore/QVariant>
 
-#include "TimelineModel.h"
+class TimelineModel;
 
 class EventDelegateChooserAttachedType : public QObject
 {
diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp
index afb4585a..e0dfe9b9 100644
--- a/src/timeline/InputBar.cpp
+++ b/src/timeline/InputBar.cpp
@@ -36,6 +36,7 @@
 #include "TimelineViewManager.h"
 #include "UserSettingsPage.h"
 #include "Utils.h"
+#include "ui/UserProfile.h"
 
 #include "blurhash.hpp"
 
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index 898e6e83..4cc50fee 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -945,6 +945,34 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
     sort(0);
 }
 
+FilteredRoomlistModel *
+FilteredRoomlistModel::create(QQmlEngine *qmlEngine, QJSEngine *)
+{
+    // The instance has to exist before it is used. We cannot replace it.
+    Q_ASSERT(instance_);
+
+    // The engine has to have the same thread affinity as the singleton.
+    Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+    // There can only be one engine accessing the singleton.
+    static QJSEngine *s_engine = nullptr;
+    if (s_engine)
+        Q_ASSERT(qmlEngine == s_engine);
+    else
+        s_engine = qmlEngine;
+
+    QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+    return instance_;
+}
+
+TimelineModel *
+FilteredRoomlistModel::getRoomById(const QString &id) const
+{
+    auto r = roomlistmodel->getRoomById(id).data();
+    QQmlEngine::setObjectOwnership(r, QQmlEngine::CppOwnership);
+    return r;
+}
+
 void
 FilteredRoomlistModel::updateHiddenTagsAndSpaces()
 {
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index 2294864f..c3f485ef 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -15,12 +15,11 @@
 
 #include <mtx/responses/sync.hpp>
 
-#include "TimelineModel.h"
-
 #ifdef NHEKO_DBUS_SYS
 #include "dbus/NhekoDBusBackend.h"
 #endif
 
+class TimelineModel;
 class TimelineViewManager;
 
 class RoomPreview
@@ -178,24 +177,7 @@ class FilteredRoomlistModel final : public QSortFilterProxyModel
 public:
     FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
 
-    static FilteredRoomlistModel *create(QQmlEngine *qmlEngine, QJSEngine *)
-    {
-        // The instance has to exist before it is used. We cannot replace it.
-        Q_ASSERT(instance_);
-
-        // The engine has to have the same thread affinity as the singleton.
-        Q_ASSERT(qmlEngine->thread() == instance_->thread());
-
-        // There can only be one engine accessing the singleton.
-        static QJSEngine *s_engine = nullptr;
-        if (s_engine)
-            Q_ASSERT(qmlEngine == s_engine);
-        else
-            s_engine = qmlEngine;
-
-        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
-        return instance_;
-    }
+    static FilteredRoomlistModel *create(QQmlEngine *qmlEngine, QJSEngine *);
 
     static FilteredRoomlistModel *instance() { return instance_; }
 
@@ -218,12 +200,7 @@ public slots:
     RoomPreview currentRoomPreview() const { return roomlistmodel->currentRoomPreview(); }
     void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
     void resetCurrentRoom() { roomlistmodel->resetCurrentRoom(); }
-    TimelineModel *getRoomById(const QString &id) const
-    {
-        auto r = roomlistmodel->getRoomById(id).data();
-        QQmlEngine::setObjectOwnership(r, QQmlEngine::CppOwnership);
-        return r;
-    }
+    TimelineModel *getRoomById(const QString &id) const;
     RoomPreview getRoomPreviewById(QString roomid) const
     {
         return roomlistmodel->getRoomPreviewById(roomid);
diff --git a/src/timeline/TimelineFilter.cpp b/src/timeline/TimelineFilter.cpp
index a92dfb13..0833900e 100644
--- a/src/timeline/TimelineFilter.cpp
+++ b/src/timeline/TimelineFilter.cpp
@@ -8,6 +8,7 @@
 #include <QEvent>
 
 #include "Logging.h"
+#include "TimelineModel.h"
 
 /// Searching currently can be done incrementally. For that we define a specific role to filter on
 /// and then process that role in chunk. This is the `FilterRole`. Of course we need to then also
diff --git a/src/timeline/TimelineFilter.h b/src/timeline/TimelineFilter.h
index 658a8c57..336339e2 100644
--- a/src/timeline/TimelineFilter.h
+++ b/src/timeline/TimelineFilter.h
@@ -10,7 +10,7 @@
 
 #include <mtx/events/power_levels.hpp>
 
-#include "TimelineModel.h"
+class TimelineModel;
 
 class TimelineFilter : public QSortFilterProxyModel
 {
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 92a37aa1..b41d1e0c 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -29,9 +29,12 @@
 #include "Logging.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
+#include "ReadReceiptsModel.h"
+#include "RoomlistModel.h"
 #include "TimelineViewManager.h"
 #include "Utils.h"
 #include "encryption/Olm.h"
+#include "ui/UserProfile.h"
 
 namespace std {
 inline uint // clazy:exclude=qhash-namespace
@@ -1703,7 +1706,8 @@ TimelineModel::checkAfterFetch()
 
 template<typename T>
 void
-TimelineModel::sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType)
+TimelineModel::sendEncryptedMessage(const mtx::events::RoomEvent<T> &msg,
+                                    mtx::events::EventType eventType)
 {
     const auto room_id = room_id_.toStdString();
 
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index c7f3ebb6..3a189e39 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -20,7 +20,6 @@
 #include "InputBar.h"
 #include "Permissions.h"
 #include "Reaction.h"
-#include "ReadReceiptsModel.h"
 #include "ui/RoomSummary.h"
 
 namespace mtx::http {
@@ -33,6 +32,7 @@ struct ClaimKeys;
 struct StateEvents;
 }
 struct RelatedInfo;
+class ReadReceiptsProxy;
 
 namespace qml_mtx_events {
 Q_NAMESPACE
@@ -516,7 +516,8 @@ signals:
 
 private:
     template<typename T>
-    void sendEncryptedMessage(mtx::events::RoomEvent<T> msg, mtx::events::EventType eventType);
+    void
+    sendEncryptedMessage(const mtx::events::RoomEvent<T> &msg, mtx::events::EventType eventType);
     void readEvent(const std::string &id);
 
     void setPaginationInProgress(const bool paginationInProgress);
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index 9ea8dc77..479fe7e1 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -8,6 +8,8 @@
 #include <QClipboard>
 #include <QFileDialog>
 #include <QMimeData>
+#include <QQuickItem>
+#include <QQuickTextDocument>
 #include <QStandardPaths>
 #include <QString>
 
@@ -24,17 +26,48 @@
 #include "Logging.h"
 #include "MainWindow.h"
 #include "MatrixClient.h"
+#include "MemberList.h"
 #include "RoomsModel.h"
+#include "TimelineModel.h"
 #include "UserSettingsPage.h"
 #include "UsersModel.h"
 #include "Utils.h"
 #include "encryption/VerificationManager.h"
+#include "timeline/CommunitiesModel.h"
+#include "timeline/PresenceEmitter.h"
+#include "timeline/RoomlistModel.h"
+#include "ui/RoomSettings.h"
+#include "ui/UserProfile.h"
 #include "voip/CallManager.h"
 #include "voip/WebRTCSession.h"
 
 namespace {
+struct nonesuch
+{
+    ~nonesuch()                      = delete;
+    nonesuch(nonesuch const &)       = delete;
+    void operator=(nonesuch const &) = delete;
+};
+
+namespace detail {
+template<class Default, class AlwaysVoid, template<class...> class Op, class... Args>
+struct detector
+{
+    using value_t = std::false_type;
+    using type    = Default;
+};
+
+template<class Default, template<class...> class Op, class... Args>
+struct detector<Default, std::void_t<Op<Args...>>, Op, Args...>
+{
+    using value_t = std::true_type;
+    using type    = Op<Args...>;
+};
+
+} // namespace detail
+
 template<template<class...> class Op, class... Args>
-using is_detected = typename nheko::detail::detector<nheko::nonesuch, void, Op, Args...>::value_t;
+using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
 
 template<class Content>
 using file_t = decltype(Content::file);
@@ -88,7 +121,7 @@ TimelineViewManager::updateColorPalette()
 QColor
 TimelineViewManager::userColor(QString id, QColor background)
 {
-    QPair<QString, quint64> idx{id, background.rgba64()};
+    std::pair<QString, quint64> idx{id, background.rgba64()};
     if (!userColors.contains(idx))
         userColors.insert(idx, QColor(utils::generateContrastingHexColor(id, background)));
     return userColors.value(idx);
@@ -148,6 +181,32 @@ TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent)
     });
 }
 
+TimelineViewManager *
+TimelineViewManager::create(QQmlEngine *qmlEngine, QJSEngine *)
+{
+    // The instance has to exist before it is used. We cannot replace it.
+    Q_ASSERT(instance_);
+
+    // The engine has to have the same thread affinity as the singleton.
+    Q_ASSERT(qmlEngine->thread() == instance_->thread());
+
+    // There can only be one engine accessing the singleton.
+    static QJSEngine *s_engine = nullptr;
+    if (s_engine)
+        Q_ASSERT(qmlEngine == s_engine);
+    else
+        s_engine = qmlEngine;
+
+    QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
+    return instance_;
+}
+
+void
+TimelineViewManager::clearAll()
+{
+    rooms_->clear();
+}
+
 void
 TimelineViewManager::openRoomMembers(TimelineModel *room)
 {
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index b4e176cd..b116402b 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -5,19 +5,12 @@
 #pragma once
 
 #include <QHash>
-#include <QQuickItem>
-#include <QQuickTextDocument>
+#include <QQmlEngine>
 
-#include <mtx/common.hpp>
-#include <mtx/responses/messages.hpp>
+#include <unordered_map>
 
-#include "InviteesModel.h"
-#include "MemberList.h"
-#include "timeline/CommunitiesModel.h"
-#include "timeline/PresenceEmitter.h"
-#include "timeline/RoomlistModel.h"
-#include "ui/RoomSettings.h"
-#include "ui/UserProfile.h"
+class QQuickItem;
+class QQuickTextDocument;
 
 class UserSettings;
 class ChatPage;
@@ -25,9 +18,32 @@ class ImagePackListModel;
 class TimelineModel;
 class CallManager;
 class VerificationManager;
+class InviteesModel;
+class MemberList;
+class CommunitiesModel;
+class RoomlistModel;
+class PresenceEmitter;
+class UserProfile;
+class RoomSettings;
+class FilteredRoomlistModel;
+class QAbstractItemModel;
 
 namespace mtx::responses {
 struct Sync;
+struct AccountData;
+}
+
+namespace mtx::events::voip {
+struct CallInvite;
+struct CallCandidates;
+struct CallAnswer;
+struct CallHangUp;
+struct CallSelectAnswer;
+struct CallReject;
+struct CallNegotiate;
+}
+namespace mtx::events::collections {
+struct TimelineEvents;
 }
 
 class TimelineViewManager final : public QObject
@@ -45,24 +61,7 @@ class TimelineViewManager final : public QObject
 public:
     TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr);
 
-    static TimelineViewManager *create(QQmlEngine *qmlEngine, QJSEngine *)
-    {
-        // The instance has to exist before it is used. We cannot replace it.
-        Q_ASSERT(instance_);
-
-        // The engine has to have the same thread affinity as the singleton.
-        Q_ASSERT(qmlEngine->thread() == instance_->thread());
-
-        // There can only be one engine accessing the singleton.
-        static QJSEngine *s_engine = nullptr;
-        if (s_engine)
-            Q_ASSERT(qmlEngine == s_engine);
-        else
-            s_engine = qmlEngine;
-
-        QJSEngine::setObjectOwnership(instance_, QJSEngine::CppOwnership);
-        return instance_;
-    }
+    static TimelineViewManager *create(QQmlEngine *qmlEngine, QJSEngine *);
 
     static TimelineViewManager *instance() { return TimelineViewManager::instance_; }
 
@@ -72,7 +71,7 @@ public:
 
     VerificationManager *verificationManager() { return verificationManager_; }
 
-    void clearAll() { rooms_->clear(); }
+    void clearAll();
 
     Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
     bool isConnected() const { return isConnected_; }
@@ -158,7 +157,7 @@ private:
     VerificationManager *verificationManager_ = nullptr;
     PresenceEmitter *presenceEmitter          = nullptr;
 
-    QHash<QPair<QString, quint64>, QColor> userColors;
+    QHash<std::pair<QString, quint64>, QColor> userColors;
 
     inline static TimelineViewManager *instance_ = nullptr;
 
diff --git a/src/ui/MxcAnimatedImage.h b/src/ui/MxcAnimatedImage.h
index 1f2c0b74..2e5ae4f7 100644
--- a/src/ui/MxcAnimatedImage.h
+++ b/src/ui/MxcAnimatedImage.h
@@ -9,7 +9,7 @@
 #include <QObject>
 #include <QQuickItem>
 
-#include "timeline/TimelineModel.h"
+class TimelineModel;
 
 // This is an AnimatedImage, that can draw encrypted images
 class MxcAnimatedImage : public QQuickItem
diff --git a/src/ui/MxcMediaProxy.cpp b/src/ui/MxcMediaProxy.cpp
index 1b7a31be..3773b141 100644
--- a/src/ui/MxcMediaProxy.cpp
+++ b/src/ui/MxcMediaProxy.cpp
@@ -17,6 +17,7 @@
 #include "EventAccessors.h"
 #include "Logging.h"
 #include "MatrixClient.h"
+#include "timeline/RoomlistModel.h"
 #include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 
diff --git a/src/ui/NhekoDropArea.cpp b/src/ui/NhekoDropArea.cpp
index 6751a729..bc490a23 100644
--- a/src/ui/NhekoDropArea.cpp
+++ b/src/ui/NhekoDropArea.cpp
@@ -8,6 +8,7 @@
 
 #include "ChatPage.h"
 #include "timeline/InputBar.h"
+#include "timeline/RoomlistModel.h"
 #include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 
diff --git a/src/ui/NhekoGlobalObject.cpp b/src/ui/NhekoGlobalObject.cpp
index 591eed3c..138b4283 100644
--- a/src/ui/NhekoGlobalObject.cpp
+++ b/src/ui/NhekoGlobalObject.cpp
@@ -11,12 +11,13 @@
 #include <QUrl>
 #include <QWindow>
 
+#include <mtx/requests.hpp>
+
 #include "Cache_p.h"
 #include "ChatPage.h"
 #include "Logging.h"
 #include "UserSettingsPage.h"
 #include "Utils.h"
-#include "voip/WebRTCSession.h"
 
 #if XCB_AVAILABLE
 #include <xcb/xproto.h>
diff --git a/src/ui/UIA.cpp b/src/ui/UIA.cpp
index f212fc1d..71bbf8e5 100644
--- a/src/ui/UIA.cpp
+++ b/src/ui/UIA.cpp
@@ -9,6 +9,7 @@
 #include <QInputDialog>
 #include <QTimer>
 
+#include <mtx/requests.hpp>
 #include <mtx/responses/common.hpp>
 
 #include "Logging.h"
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 6f5fbc61..d05b6f69 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -16,6 +16,7 @@
 #include "UserProfile.h"
 #include "Utils.h"
 #include "encryption/VerificationManager.h"
+#include "timeline/RoomlistModel.h"
 #include "timeline/TimelineModel.h"
 #include "timeline/TimelineViewManager.h"
 #include "ui/UIA.h"
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index 64dbf99c..b4b73ed3 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -13,7 +13,9 @@
 #include <mtx/responses/common.hpp>
 
 #include "CacheCryptoStructs.h"
-#include "timeline/TimelineModel.h"
+#include "CacheStructs.h"
+
+class TimelineModel;
 
 namespace verification {
 Q_NAMESPACE