diff --git a/src/AliasEditModel.h b/src/AliasEditModel.h
index 2263659b..04de5016 100644
--- a/src/AliasEditModel.h
+++ b/src/AliasEditModel.h
@@ -5,6 +5,7 @@
#pragma once
#include <QAbstractListModel>
+#include <QQmlEngine>
#include <QVector>
#include <mtx/events/canonical_alias.hpp>
@@ -29,6 +30,9 @@ signals:
class AliasEditingModel final : public QAbstractListModel
{
Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("Please use editAliases to create the models")
+
Q_PROPERTY(bool canAdvertize READ canAdvertize CONSTANT)
public:
diff --git a/src/CacheCryptoStructs.h b/src/CacheCryptoStructs.h
index 96fc35ec..2a5b895f 100644
--- a/src/CacheCryptoStructs.h
+++ b/src/CacheCryptoStructs.h
@@ -5,6 +5,7 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <map>
#include <mutex>
@@ -16,6 +17,8 @@
namespace crypto {
Q_NAMESPACE
+QML_NAMED_ELEMENT(Crypto)
+
//! How much a participant is trusted.
enum Trust
{
diff --git a/src/Clipboard.h b/src/Clipboard.h
index bad9fd10..8bf89c22 100644
--- a/src/Clipboard.h
+++ b/src/Clipboard.h
@@ -5,11 +5,15 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <QString>
class Clipboard final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
diff --git a/src/LoginPage.h b/src/LoginPage.h
index f20ba0c6..e3d0d2e0 100644
--- a/src/LoginPage.h
+++ b/src/LoginPage.h
@@ -5,13 +5,10 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <QVariantList>
-namespace mtx {
-namespace responses {
-struct Login;
-}
-}
+#include <mtx/responses/login.hpp>
struct SSOProvider
{
@@ -33,6 +30,7 @@ public:
class LoginPage : public QObject
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString mxid READ mxid WRITE setMxid NOTIFY matrixIdChanged)
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
index 51b23e0f..d06171de 100644
--- a/src/MainWindow.cpp
+++ b/src/MainWindow.cpp
@@ -25,21 +25,15 @@
#include "InviteesModel.h"
#include "JdenticonProvider.h"
#include "Logging.h"
-#include "LoginPage.h"
#include "MainWindow.h"
#include "MatrixClient.h"
#include "MemberList.h"
#include "MxcImageProvider.h"
#include "PowerlevelsEditModels.h"
-#include "ReadReceiptsModel.h"
-#include "RegisterPage.h"
-#include "RoomDirectoryModel.h"
-#include "RoomsModel.h"
#include "SingleImagePackModel.h"
#include "TrayIcon.h"
#include "UserDirectoryModel.h"
#include "UserSettingsPage.h"
-#include "UsersModel.h"
#include "Utils.h"
#include "dock/Dock.h"
#include "emoji/Provider.h"
@@ -48,12 +42,6 @@
#include "timeline/DelegateChooser.h"
#include "timeline/TimelineFilter.h"
#include "timeline/TimelineViewManager.h"
-#include "ui/HiddenEvents.h"
-#include "ui/MxcAnimatedImage.h"
-#include "ui/MxcMediaProxy.h"
-#include "ui/NhekoCursorShape.h"
-#include "ui/NhekoDropArea.h"
-#include "ui/NhekoEventObserver.h"
#include "ui/NhekoGlobalObject.h"
#include "ui/RoomSummary.h"
#include "ui/UIA.h"
@@ -83,7 +71,7 @@ MainWindow::MainWindow(QWindow *parent)
registerQmlTypes();
setColor(Theme::paletteFromTheme(userSettings_->theme()).window().color());
- setSource(QUrl(QStringLiteral("qrc:///qml/Root.qml")));
+ setSource(QUrl(QStringLiteral("qrc:///resources/qml/Root.qml")));
trayIcon_ = new TrayIcon(QStringLiteral(":/logos/nheko.svg"), this);
@@ -132,156 +120,57 @@ MainWindow::MainWindow(QWindow *parent)
void
MainWindow::registerQmlTypes()
{
- qmlRegisterUncreatableMetaObject(qml_mtx_events::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "MtxEvent",
- QStringLiteral("Can't instantiate enum!"));
- qmlRegisterUncreatableMetaObject(
- olm::staticMetaObject, "im.nheko", 1, 0, "Olm", QStringLiteral("Can't instantiate enum!"));
- qmlRegisterUncreatableMetaObject(crypto::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "Crypto",
- QStringLiteral("Can't instantiate enum!"));
- qmlRegisterUncreatableMetaObject(verification::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "VerificationStatus",
- QStringLiteral("Can't instantiate enum!"));
-
- qmlRegisterType<DelegateChoice>("im.nheko", 1, 0, "DelegateChoice");
- qmlRegisterType<DelegateChooser>("im.nheko", 1, 0, "DelegateChooser");
- qmlRegisterType<NhekoDropArea>("im.nheko", 1, 0, "NhekoDropArea");
- qmlRegisterType<NhekoCursorShape>("im.nheko", 1, 0, "CursorShape");
- qmlRegisterType<NhekoEventObserver>("im.nheko", 1, 0, "EventObserver");
- qmlRegisterType<MxcAnimatedImage>("im.nheko", 1, 0, "MxcAnimatedImage");
- qmlRegisterType<MxcMediaProxy>("im.nheko", 1, 0, "MxcMedia");
- qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
- qmlRegisterType<UserDirectoryModel>("im.nheko", 1, 0, "UserDirectoryModel");
- qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
- qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
- qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
- qmlRegisterType<TimelineFilter>("im.nheko", 1, 0, "TimelineFilter");
- qmlRegisterUncreatableType<RoomSummary>(
- "im.nheko",
- 1,
- 0,
- "RoomSummary",
- QStringLiteral("Please use joinRoom to create a room summary."));
- qmlRegisterUncreatableType<AliasEditingModel>(
- "im.nheko",
- 1,
- 0,
- "AliasEditingModel",
- QStringLiteral("Please use editAliases to create the models"));
-
- qmlRegisterUncreatableType<PowerlevelEditingModels>(
- "im.nheko",
- 1,
- 0,
- "PowerlevelEditingModels",
- QStringLiteral("Please use editPowerlevels to create the models"));
- qmlRegisterUncreatableType<DeviceVerificationFlow>(
- "im.nheko",
- 1,
- 0,
- "DeviceVerificationFlow",
- QStringLiteral("Can't create verification flow from QML!"));
- qmlRegisterUncreatableType<UserProfile>(
- "im.nheko",
- 1,
- 0,
- "UserProfileModel",
- QStringLiteral("UserProfile needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<MemberList>(
- "im.nheko",
- 1,
- 0,
- "MemberList",
- QStringLiteral("MemberList needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<RoomSettings>(
- "im.nheko",
- 1,
- 0,
- "RoomSettingsModel",
- QStringLiteral("Room Settings needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<TimelineModel>(
- "im.nheko", 1, 0, "Room", QStringLiteral("Room needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<ImagePackListModel>(
- "im.nheko",
- 1,
- 0,
- "ImagePackListModel",
- QStringLiteral("ImagePackListModel needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<SingleImagePackModel>(
- "im.nheko",
- 1,
- 0,
- "SingleImagePackModel",
- QStringLiteral("SingleImagePackModel needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<InviteesModel>(
- "im.nheko",
- 1,
- 0,
- "InviteesModel",
- QStringLiteral("InviteesModel needs to be instantiated on the C++ side"));
- qmlRegisterUncreatableType<ReadReceiptsProxy>(
- "im.nheko",
- 1,
- 0,
- "ReadReceiptsProxy",
- QStringLiteral("ReadReceiptsProxy needs to be instantiated on the C++ side"));
-
- qmlRegisterSingletonType<Clipboard>(
- "im.nheko", 1, 0, "Clipboard", [](QQmlEngine *, QJSEngine *) -> QObject * {
- return new Clipboard();
- });
- qmlRegisterSingletonType<Nheko>(
- "im.nheko", 1, 0, "Nheko", [](QQmlEngine *, QJSEngine *) -> QObject * {
- return new Nheko();
- });
- qmlRegisterSingletonType<UserSettingsModel>(
- "im.nheko", 1, 0, "UserSettingsModel", [](QQmlEngine *, QJSEngine *) -> QObject * {
- return new UserSettingsModel();
- });
-
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "Settings", userSettings_.data());
-
- qmlRegisterUncreatableType<FilteredCommunitiesModel>(
- "im.nheko",
- 1,
- 0,
- "FilteredCommunitiesModel",
- QStringLiteral("Use Communities.filtered() to create a FilteredCommunitiesModel"));
-
- qmlRegisterUncreatableType<MediaUpload>(
- "im.nheko", 1, 0, "MediaUpload", QStringLiteral("MediaUploads can not be created in Qml"));
- qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
- "im.nheko.EmojiModel",
- 1,
- 0,
- "EmojiCategory",
- QStringLiteral("Error: Only enums"));
-
- qmlRegisterType<RoomDirectoryModel>("im.nheko", 1, 0, "RoomDirectoryModel");
-
- qmlRegisterSingletonType<SelfVerificationStatus>(
- "im.nheko", 1, 0, "SelfVerificationStatus", [](QQmlEngine *, QJSEngine *) -> QObject * {
- auto ptr = new SelfVerificationStatus();
- QObject::connect(ChatPage::instance(),
- &ChatPage::initializeEmptyViews,
- ptr,
- &SelfVerificationStatus::invalidate);
- return ptr;
- });
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "MainWindow", this);
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "UIA", UIA::instance());
- qmlRegisterSingletonInstance(
- "im.nheko", 1, 0, "CallManager", ChatPage::instance()->callManager());
+ // qmlRegisterUncreatableType<DeviceVerificationFlow>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "DeviceVerificationFlow",
+ // QStringLiteral("Can't create verification flow from QML!"));
+ // qmlRegisterUncreatableType<UserProfile>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "UserProfileModel",
+ // QStringLiteral("UserProfile needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<MemberList>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "MemberList",
+ // QStringLiteral("MemberList needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<RoomSettings>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "RoomSettingsModel",
+ // QStringLiteral("Room Settings needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<TimelineModel>(
+ // "im.nheko", 1, 0, "Room", QStringLiteral("Room needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<ImagePackListModel>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "ImagePackListModel",
+ // QStringLiteral("ImagePackListModel needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<SingleImagePackModel>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "SingleImagePackModel",
+ // QStringLiteral("SingleImagePackModel needs to be instantiated on the C++ side"));
+ // qmlRegisterUncreatableType<InviteesModel>(
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "InviteesModel",
+ // QStringLiteral("InviteesModel needs to be instantiated on the C++ side"));
+
+ // qmlRegisterUncreatableMetaObject(emoji::staticMetaObject,
+ // "im.nheko.EmojiModel",
+ // 1,
+ // 0,
+ // "EmojiCategory",
+ // QStringLiteral("Error: Only enums"));
imgProvider = new MxcImageProvider();
engine()->addImageProvider(QStringLiteral("MxcImage"), imgProvider);
diff --git a/src/MainWindow.h b/src/MainWindow.h
index 0a5f9433..20e81efc 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -50,14 +50,35 @@ public:
bool eventFilter(QObject *obj, QEvent *event) override;
};
-class MainWindow final : public QQuickView
+class MainWindow : public QQuickView
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
public:
- explicit MainWindow(QWindow *parent = nullptr);
+ explicit MainWindow(QWindow *parent);
static MainWindow *instance() { return instance_; }
+ static MainWindow *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 saveCurrentWindowSize();
void openJoinRoomDialog(std::function<void(const QString &room_id)> callback);
diff --git a/src/PowerlevelsEditModels.h b/src/PowerlevelsEditModels.h
index fe9735d3..c9d262d8 100644
--- a/src/PowerlevelsEditModels.h
+++ b/src/PowerlevelsEditModels.h
@@ -5,6 +5,7 @@
#pragma once
#include <QAbstractListModel>
+#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include <mtx/events/power_levels.hpp>
@@ -196,6 +197,9 @@ class PowerlevelEditingModels final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("Please use editPowerlevels to create the models")
+
Q_PROPERTY(PowerlevelsUserListModel *users READ users CONSTANT)
Q_PROPERTY(PowerlevelsTypeListModel *types READ types CONSTANT)
Q_PROPERTY(PowerlevelsSpacesListModel *spaces READ spaces CONSTANT)
diff --git a/src/ReadReceiptsModel.h b/src/ReadReceiptsModel.h
index b870061a..56f67509 100644
--- a/src/ReadReceiptsModel.h
+++ b/src/ReadReceiptsModel.h
@@ -8,6 +8,7 @@
#include <QAbstractListModel>
#include <QDateTime>
#include <QObject>
+#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include <QString>
@@ -54,6 +55,9 @@ class ReadReceiptsProxy final : public QSortFilterProxyModel
{
Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
Q_PROPERTY(QString eventId READ eventId CONSTANT)
Q_PROPERTY(QString roomId READ roomId CONSTANT)
diff --git a/src/RegisterPage.h b/src/RegisterPage.h
index 7c58b40c..dcf61489 100644
--- a/src/RegisterPage.h
+++ b/src/RegisterPage.h
@@ -5,6 +5,7 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <QString>
#include <mtx/user_interactive.hpp>
@@ -13,6 +14,7 @@
class RegisterPage : public QObject
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
Q_PROPERTY(QString hsError READ hsError NOTIFY hsErrorChanged)
diff --git a/src/RoomDirectoryModel.h b/src/RoomDirectoryModel.h
index 8a367e2e..a5103112 100644
--- a/src/RoomDirectoryModel.h
+++ b/src/RoomDirectoryModel.h
@@ -5,6 +5,7 @@
#pragma once
#include <QAbstractListModel>
+#include <QQmlEngine>
#include <QString>
#include <string>
#include <vector>
@@ -32,6 +33,7 @@ signals:
class RoomDirectoryModel : public QAbstractListModel
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(bool loadingMoreRooms READ loadingMoreRooms NOTIFY loadingMoreRoomsChanged)
Q_PROPERTY(
diff --git a/src/UserDirectoryModel.h b/src/UserDirectoryModel.h
index f0416ecf..ffa9ae93 100644
--- a/src/UserDirectoryModel.h
+++ b/src/UserDirectoryModel.h
@@ -5,6 +5,7 @@
#pragma once
#include <QAbstractListModel>
+#include <QQmlEngine>
#include <QString>
#include <string>
#include <vector>
@@ -26,6 +27,7 @@ signals:
class UserDirectoryModel : public QAbstractListModel
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(bool searchingUsers READ searchingUsers NOTIFY searchingUsersChanged)
diff --git a/src/UserSettingsPage.h b/src/UserSettingsPage.h
index 657a362d..301a1b67 100644
--- a/src/UserSettingsPage.h
+++ b/src/UserSettingsPage.h
@@ -6,6 +6,7 @@
#include <QAbstractListModel>
#include <QProcessEnvironment>
+#include <QQmlEngine>
#include <QSettings>
#include <QSharedPointer>
@@ -23,6 +24,8 @@ class QVBoxLayout;
class UserSettings final : public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Settings)
+ QML_SINGLETON
Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(bool messageHoverHighlight READ messageHoverHighlight WRITE setMessageHoverHighlight
@@ -131,6 +134,24 @@ class UserSettings final : public QObject
public:
static QSharedPointer<UserSettings> instance();
static void initialize(std::optional<QString> profile);
+ static UserSettings *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().get(), QJSEngine::CppOwnership);
+ return instance().get();
+ }
QSettings *qsettings() { return &settings; }
@@ -431,9 +452,10 @@ private:
static QSharedPointer<UserSettings> instance_;
};
-class UserSettingsModel final : public QAbstractListModel
+class UserSettingsModel : public QAbstractListModel
{
Q_OBJECT
+ QML_ELEMENT
enum Indices
{
diff --git a/src/encryption/Olm.h b/src/encryption/Olm.h
index f0e51070..726b9590 100644
--- a/src/encryption/Olm.h
+++ b/src/encryption/Olm.h
@@ -9,10 +9,13 @@
#include <mtx/events/encrypted.hpp>
#include <mtxclient/crypto/client.hpp>
+#include <QQmlEngine>
+
#include <CacheCryptoStructs.h>
namespace olm {
Q_NAMESPACE
+QML_NAMED_ELEMENT(Olm)
enum DecryptionErrorCode
{
diff --git a/src/encryption/SelfVerificationStatus.cpp b/src/encryption/SelfVerificationStatus.cpp
index 6fa737d4..d9d3d787 100644
--- a/src/encryption/SelfVerificationStatus.cpp
+++ b/src/encryption/SelfVerificationStatus.cpp
@@ -29,6 +29,11 @@ SelfVerificationStatus::SelfVerificationStatus(QObject *o)
Qt::UniqueConnection);
cache::client()->markUserKeysOutOfDate({http::client()->user_id().to_string()});
});
+
+ connect(ChatPage::instance(),
+ &ChatPage::initializeEmptyViews,
+ this,
+ &SelfVerificationStatus::invalidate);
}
void
diff --git a/src/encryption/SelfVerificationStatus.h b/src/encryption/SelfVerificationStatus.h
index ea790c8b..c65fffd0 100644
--- a/src/encryption/SelfVerificationStatus.h
+++ b/src/encryption/SelfVerificationStatus.h
@@ -5,11 +5,15 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
class SelfVerificationStatus final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(bool hasSSSS READ hasSSSS NOTIFY hasSSSSChanged)
diff --git a/src/encryption/VerificationManager.cpp b/src/encryption/VerificationManager.cpp
index 802a8177..d1248755 100644
--- a/src/encryption/VerificationManager.cpp
+++ b/src/encryption/VerificationManager.cpp
@@ -15,6 +15,7 @@ VerificationManager::VerificationManager(TimelineViewManager *o)
: QObject(o)
, rooms_(o->rooms())
{
+ instance_ = this;
}
static bool
diff --git a/src/encryption/VerificationManager.h b/src/encryption/VerificationManager.h
index 7b32bc98..cdc8af30 100644
--- a/src/encryption/VerificationManager.h
+++ b/src/encryption/VerificationManager.h
@@ -6,6 +6,7 @@
#include <QHash>
#include <QObject>
+#include <QQmlEngine>
#include <QSharedPointer>
#include <mtx/events.hpp>
@@ -21,8 +22,30 @@ class VerificationManager final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
public:
- VerificationManager(TimelineViewManager *o = nullptr);
+ VerificationManager(TimelineViewManager *o);
+
+ static VerificationManager *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_;
+ }
Q_INVOKABLE void removeVerificationFlow(DeviceVerificationFlow *flow);
void verifyUser(QString userid);
@@ -45,4 +68,6 @@ private:
QHash<QString, QSharedPointer<DeviceVerificationFlow>> dvList;
bool isInitialSync_ = false;
RoomlistModel *rooms_;
+
+ inline static VerificationManager *instance_ = nullptr;
};
diff --git a/src/main.cpp b/src/main.cpp
index da67ca43..07397d62 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -346,7 +346,7 @@ main(int argc, char *argv[])
QStringLiteral(":/translations")))
app.installTranslator(&appTranslator);
- MainWindow w;
+ MainWindow w(nullptr);
// QQuickView w;
// Move the MainWindow to the center
diff --git a/src/timeline/CommunitiesModel.cpp b/src/timeline/CommunitiesModel.cpp
index b04fd7a9..3c09d747 100644
--- a/src/timeline/CommunitiesModel.cpp
+++ b/src/timeline/CommunitiesModel.cpp
@@ -22,6 +22,7 @@ CommunitiesModel::CommunitiesModel(QObject *parent)
, hiddenTagIds_{UserSettings::instance()->hiddenTags()}
, mutedTagIds_{UserSettings::instance()->mutedTags()}
{
+ instance_ = this;
}
QHash<int, QByteArray>
diff --git a/src/timeline/CommunitiesModel.h b/src/timeline/CommunitiesModel.h
index a90fa6a2..d0841f4b 100644
--- a/src/timeline/CommunitiesModel.h
+++ b/src/timeline/CommunitiesModel.h
@@ -6,6 +6,7 @@
#include <QAbstractListModel>
#include <QHash>
+#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include <QString>
#include <QStringList>
@@ -21,6 +22,8 @@ class CommunitiesModel;
class FilteredCommunitiesModel final : public QSortFilterProxyModel
{
Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("Use Communities.filtered() to create a FilteredCommunitiesModel")
public:
explicit FilteredCommunitiesModel(CommunitiesModel *model, QObject *parent = nullptr);
@@ -73,6 +76,9 @@ public:
class CommunitiesModel final : public QAbstractListModel
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Communities)
+ QML_SINGLETON
+
Q_PROPERTY(QString currentTagId READ currentTagId WRITE setCurrentTagId NOTIFY
currentTagIdChanged RESET resetCurrentTagId)
Q_PROPERTY(QStringList tags READ tags NOTIFY tagsChanged)
@@ -149,6 +155,26 @@ public:
};
CommunitiesModel(QObject *parent = nullptr);
+
+ static CommunitiesModel *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_;
+ }
+
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
@@ -221,4 +247,6 @@ private:
mtx::responses::UnreadNotifications dmUnreads{};
friend class FilteredCommunitiesModel;
+
+ inline static CommunitiesModel *instance_ = nullptr;
};
diff --git a/src/timeline/DelegateChooser.h b/src/timeline/DelegateChooser.h
index c27f2c43..ac227382 100644
--- a/src/timeline/DelegateChooser.h
+++ b/src/timeline/DelegateChooser.h
@@ -19,6 +19,7 @@ class QQmlAdaptorModel;
class DelegateChoice : public QObject
{
Q_OBJECT
+ QML_ELEMENT
Q_CLASSINFO("DefaultProperty", "delegate")
public:
@@ -45,6 +46,7 @@ private:
class DelegateChooser : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
Q_CLASSINFO("DefaultProperty", "choices")
public:
diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h
index f03e6019..3cd65524 100644
--- a/src/timeline/InputBar.h
+++ b/src/timeline/InputBar.h
@@ -7,11 +7,13 @@
#include <QIODevice>
#include <QImage>
#include <QObject>
+#include <QQmlEngine>
#include <QSize>
#include <QStringList>
#include <QTimer>
#include <QUrl>
#include <QVariantList>
+
#include <deque>
#include <memory>
@@ -43,6 +45,10 @@ enum class MarkdownOverride
class MediaUpload final : public QObject
{
Q_OBJECT
+
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
Q_PROPERTY(int mediaType READ type NOTIFY mediaTypeChanged)
// https://stackoverflow.com/questions/33422265/pass-qimage-to-qml/68554646#68554646
Q_PROPERTY(QUrl thumbnail READ thumbnailDataUrl NOTIFY thumbnailChanged)
diff --git a/src/timeline/PresenceEmitter.h b/src/timeline/PresenceEmitter.h
index e89fb316..09ad1301 100644
--- a/src/timeline/PresenceEmitter.h
+++ b/src/timeline/PresenceEmitter.h
@@ -5,6 +5,7 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <vector>
@@ -15,10 +16,33 @@ class PresenceEmitter final : public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Presence)
+ QML_SINGLETON
+
public:
PresenceEmitter(QObject *p = nullptr)
: QObject(p)
{
+ instance_ = this;
+ }
+
+ static PresenceEmitter *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 sync(const std::vector<mtx::events::Event<mtx::events::presence::Presence>> &presences);
@@ -28,4 +52,7 @@ public:
signals:
void presenceChanged(QString userid);
+
+private:
+ inline static PresenceEmitter *instance_ = nullptr;
};
diff --git a/src/timeline/RoomlistModel.cpp b/src/timeline/RoomlistModel.cpp
index ec41cc12..8d8d2977 100644
--- a/src/timeline/RoomlistModel.cpp
+++ b/src/timeline/RoomlistModel.cpp
@@ -909,6 +909,8 @@ FilteredRoomlistModel::FilteredRoomlistModel(RoomlistModel *model, QObject *pare
: QSortFilterProxyModel(parent)
, roomlistmodel(model)
{
+ instance_ = this;
+
this->sortByImportance = UserSettings::instance()->sortByImportance();
this->sortByAlphabet = UserSettings::instance()->sortByAlphabet();
setSourceModel(model);
diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h
index c06ab67d..34bf3f9a 100644
--- a/src/timeline/RoomlistModel.h
+++ b/src/timeline/RoomlistModel.h
@@ -167,12 +167,36 @@ private:
class FilteredRoomlistModel final : public QSortFilterProxyModel
{
Q_OBJECT
+
+ QML_NAMED_ELEMENT(Rooms)
+ QML_SINGLETON
+
Q_PROPERTY(
TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET resetCurrentRoom)
Q_PROPERTY(RoomPreview currentRoomPreview READ currentRoomPreview NOTIFY currentRoomChanged
RESET resetCurrentRoom)
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_;
+ }
+
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override;
@@ -249,4 +273,6 @@ private:
FilterBy filterType = FilterBy::Nothing;
QStringList hiddenTags, hiddenSpaces;
bool hideDMs = false;
+
+ inline static FilteredRoomlistModel *instance_ = nullptr;
};
diff --git a/src/timeline/TimelineFilter.h b/src/timeline/TimelineFilter.h
index 1c92c89a..658a8c57 100644
--- a/src/timeline/TimelineFilter.h
+++ b/src/timeline/TimelineFilter.h
@@ -4,6 +4,7 @@
#pragma once
+#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include <QString>
@@ -14,6 +15,7 @@
class TimelineFilter : public QSortFilterProxyModel
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString filterByThread READ filterByThread WRITE setThreadId NOTIFY threadIdChanged)
Q_PROPERTY(QString filterByContent READ filterByContent WRITE setContentFilter NOTIFY
diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h
index a232b4ee..fd1a4396 100644
--- a/src/timeline/TimelineModel.h
+++ b/src/timeline/TimelineModel.h
@@ -11,6 +11,7 @@
#include <QTimer>
#include <QVariant>
+#include <mtx/responses/common.hpp>
#include <mtxclient/http/errors.hpp>
#include "CacheCryptoStructs.h"
@@ -36,6 +37,7 @@ struct RelatedInfo;
namespace qml_mtx_events {
Q_NAMESPACE
+QML_NAMED_ELEMENT(MtxEvent)
enum EventType
{
@@ -193,6 +195,9 @@ class TimelineViewManager;
class TimelineModel final : public QAbstractListModel
{
Q_OBJECT
+ QML_NAMED_ELEMENT(Room)
+ QML_UNCREATABLE("")
+
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
Q_PROPERTY(std::vector<QString> typingUsers READ typingUsers WRITE updateTypingUsers NOTIFY
typingUsersChanged)
diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp
index a3b91ce7..2f6553e5 100644
--- a/src/timeline/TimelineViewManager.cpp
+++ b/src/timeline/TimelineViewManager.cpp
@@ -96,29 +96,21 @@ TimelineViewManager::userColor(QString id, QColor background)
TimelineViewManager::TimelineViewManager(CallManager *, ChatPage *parent)
: QObject(parent)
, rooms_(new RoomlistModel(this))
+ , frooms_(new FilteredRoomlistModel(this->rooms_))
, communities_(new CommunitiesModel(this))
, verificationManager_(new VerificationManager(this))
, presenceEmitter(new PresenceEmitter(this))
{
- static auto self = this;
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "TimelineManager", self);
- qmlRegisterSingletonType<RoomlistModel>(
- "im.nheko", 1, 0, "Rooms", [](QQmlEngine *, QJSEngine *) -> QObject * {
- auto ptr = new FilteredRoomlistModel(self->rooms_);
-
- connect(self->communities_,
- &CommunitiesModel::currentTagIdChanged,
- ptr,
- &FilteredRoomlistModel::updateFilterTag);
- connect(self->communities_,
- &CommunitiesModel::hiddenTagsChanged,
- ptr,
- &FilteredRoomlistModel::updateHiddenTagsAndSpaces);
- return ptr;
- });
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "Communities", self->communities_);
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "VerificationManager", verificationManager_);
- qmlRegisterSingletonInstance("im.nheko", 1, 0, "Presence", presenceEmitter);
+ instance_ = this;
+
+ connect(this->communities_,
+ &CommunitiesModel::currentTagIdChanged,
+ frooms_,
+ &FilteredRoomlistModel::updateFilterTag);
+ connect(this->communities_,
+ &CommunitiesModel::hiddenTagsChanged,
+ frooms_,
+ &FilteredRoomlistModel::updateHiddenTagsAndSpaces);
updateColorPalette();
diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h
index 303e2af2..a4bc6c41 100644
--- a/src/timeline/TimelineViewManager.h
+++ b/src/timeline/TimelineViewManager.h
@@ -34,6 +34,9 @@ class TimelineViewManager final : public QObject
{
Q_OBJECT
+ QML_NAMED_ELEMENT(TimelineManager)
+ QML_SINGLETON
+
Q_PROPERTY(
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged)
@@ -41,6 +44,25 @@ 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_;
+ }
+
void sync(const mtx::responses::Sync &sync_);
VerificationManager *verificationManager() { return verificationManager_; }
@@ -123,6 +145,7 @@ private:
bool isConnected_ = true;
RoomlistModel *rooms_ = nullptr;
+ FilteredRoomlistModel *frooms_ = nullptr;
CommunitiesModel *communities_ = nullptr;
// don't move this above the rooms_
@@ -130,4 +153,6 @@ private:
PresenceEmitter *presenceEmitter = nullptr;
QHash<QPair<QString, quint64>, QColor> userColors;
+
+ inline static TimelineViewManager *instance_ = nullptr;
};
diff --git a/src/ui/HiddenEvents.h b/src/ui/HiddenEvents.h
index bb68e0fa..4f0d23b4 100644
--- a/src/ui/HiddenEvents.h
+++ b/src/ui/HiddenEvents.h
@@ -5,6 +5,7 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <QString>
#include <QVariantList>
@@ -13,6 +14,7 @@
class HiddenEvents : public QObject
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged REQUIRED)
Q_PROPERTY(QVariantList hiddenEvents READ hiddenEvents NOTIFY hiddenEventsChanged)
public:
diff --git a/src/ui/MxcAnimatedImage.h b/src/ui/MxcAnimatedImage.h
index bc53e711..c9f89764 100644
--- a/src/ui/MxcAnimatedImage.h
+++ b/src/ui/MxcAnimatedImage.h
@@ -15,6 +15,7 @@
class MxcAnimatedImage : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool animatable READ animatable NOTIFY animatableChanged)
diff --git a/src/ui/MxcMediaProxy.h b/src/ui/MxcMediaProxy.h
index 5c2eac33..d245dcae 100644
--- a/src/ui/MxcMediaProxy.h
+++ b/src/ui/MxcMediaProxy.h
@@ -8,6 +8,7 @@
#include <QMediaPlayer>
#include <QObject>
#include <QPointer>
+#include <QQuickItem>
#include <QString>
#include <QUrl>
#include <QVideoSink>
@@ -21,6 +22,8 @@ class TimelineModel;
class MxcMediaProxy : public QMediaPlayer
{
Q_OBJECT
+ QML_NAMED_ELEMENT(MxcMedia)
+
Q_PROPERTY(TimelineModel *roomm READ room WRITE setRoom NOTIFY roomChanged REQUIRED)
Q_PROPERTY(QString eventId READ eventId WRITE setEventId NOTIFY eventIdChanged)
Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
diff --git a/src/ui/NhekoCursorShape.h b/src/ui/NhekoCursorShape.h
index 84d56fad..123852f9 100644
--- a/src/ui/NhekoCursorShape.h
+++ b/src/ui/NhekoCursorShape.h
@@ -12,7 +12,7 @@
class NhekoCursorShape : public QQuickItem
{
Q_OBJECT
-
+ QML_ELEMENT
Q_PROPERTY(
Qt::CursorShape cursorShape READ cursorShape WRITE setCursorShape NOTIFY cursorShapeChanged)
diff --git a/src/ui/NhekoDropArea.h b/src/ui/NhekoDropArea.h
index 91116844..46a02da5 100644
--- a/src/ui/NhekoDropArea.h
+++ b/src/ui/NhekoDropArea.h
@@ -7,6 +7,7 @@
class NhekoDropArea : public QQuickItem
{
Q_OBJECT
+ QML_ELEMENT
Q_PROPERTY(QString roomid READ roomid WRITE setRoomid NOTIFY roomidChanged)
public:
NhekoDropArea(QQuickItem *parent = nullptr);
diff --git a/src/ui/NhekoEventObserver.cpp b/src/ui/NhekoEventObserver.cpp
deleted file mode 100644
index 713a0733..00000000
--- a/src/ui/NhekoEventObserver.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "NhekoEventObserver.h"
-
-#include <QMouseEvent>
-
-#include "Logging.h"
-
-NhekoEventObserver::NhekoEventObserver(QQuickItem *parent)
- : QQuickItem(parent)
-{
- setFiltersChildMouseEvents(true);
-}
-
-bool
-NhekoEventObserver::childMouseEventFilter(QQuickItem * /*item*/, QEvent *event)
-{
- // nhlog::ui()->debug("Touched {}", item->metaObject()->className());
-
- auto setTouched = [this](bool touched) {
- if (touched != this->wasTouched_) {
- this->wasTouched_ = touched;
- emit wasTouchedChanged();
- }
- };
-
- // see
- // https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quicktemplates2/qquickscrollview.cpp?id=7f29e89c26ae2babc358b1c4e6f965af6ec759f4#n471
- switch (event->type()) {
- case QEvent::TouchBegin:
- case QEvent::TouchEnd:
- setTouched(true);
- break;
-
- case QEvent::MouseButtonPress:
- if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
- setTouched(false);
- }
- break;
-
- case QEvent::MouseMove:
- case QEvent::MouseButtonRelease:
- if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
- setTouched(false);
- break;
-
- case QEvent::HoverEnter:
- case QEvent::HoverMove:
- case QEvent::Wheel:
- setTouched(false);
- break;
-
- default:
- break;
- }
-
- return false;
-}
diff --git a/src/ui/NhekoEventObserver.h b/src/ui/NhekoEventObserver.h
deleted file mode 100644
index 63739d4a..00000000
--- a/src/ui/NhekoEventObserver.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QQuickItem>
-
-class NhekoEventObserver : public QQuickItem
-{
- Q_OBJECT
-
- Q_PROPERTY(bool wasTouched READ wasTouched NOTIFY wasTouchedChanged)
-
-public:
- explicit NhekoEventObserver(QQuickItem *parent = 0);
-
- bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
-
-private:
- bool wasTouched() { return wasTouched_; }
-
- bool wasTouched_ = false;
-
-signals:
- void wasTouchedChanged();
-};
diff --git a/src/ui/NhekoGlobalObject.h b/src/ui/NhekoGlobalObject.h
index b7a7a637..91210c54 100644
--- a/src/ui/NhekoGlobalObject.h
+++ b/src/ui/NhekoGlobalObject.h
@@ -7,6 +7,7 @@
#include <QFontDatabase>
#include <QObject>
#include <QPalette>
+#include <QQmlEngine>
#include <QWindow>
#include "AliasEditModel.h"
@@ -19,6 +20,9 @@ class Nheko final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
Q_PROPERTY(QPalette colors READ colors NOTIFY colorsChanged)
Q_PROPERTY(QPalette inactiveColors READ inactiveColors NOTIFY colorsChanged)
Q_PROPERTY(Theme theme READ theme NOTIFY colorsChanged)
diff --git a/src/ui/RoomSummary.h b/src/ui/RoomSummary.h
index c02ea5d5..8225f0ae 100644
--- a/src/ui/RoomSummary.h
+++ b/src/ui/RoomSummary.h
@@ -7,6 +7,7 @@
#include <optional>
#include <QObject>
+#include <QQmlEngine>
#include <mtx/responses/public_rooms.hpp>
@@ -25,6 +26,9 @@ class RoomSummary final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("Please use joinRoom to create a room summary.")
+
Q_PROPERTY(QString reason READ reason WRITE setReason NOTIFY reasonChanged)
Q_PROPERTY(QString roomid READ roomid NOTIFY loaded)
diff --git a/src/ui/UIA.h b/src/ui/UIA.h
index 7d23d88e..414cb804 100644
--- a/src/ui/UIA.h
+++ b/src/ui/UIA.h
@@ -5,6 +5,7 @@
#pragma once
#include <QObject>
+#include <QQmlEngine>
#include <mtxclient/http/client.hpp>
@@ -12,10 +13,31 @@ class UIA final : public QObject
{
Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
public:
static UIA *instance();
+ static UIA *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();
+ }
UIA(QObject *parent = nullptr)
: QObject(parent)
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index a880f320..d8e06aa1 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -6,6 +6,7 @@
#include <QAbstractListModel>
#include <QObject>
+#include <QQmlEngine>
#include <QString>
#include <QVector>
#include <mtx/responses.hpp>
@@ -16,6 +17,7 @@
namespace verification {
Q_NAMESPACE
+QML_NAMED_ELEMENT(VerificationStatus)
enum Status
{
diff --git a/src/voip/CallManager.cpp b/src/voip/CallManager.cpp
index feb06835..5479ba31 100644
--- a/src/voip/CallManager.cpp
+++ b/src/voip/CallManager.cpp
@@ -54,6 +54,27 @@ std::vector<std::string>
getTurnURIs(const mtx::responses::TurnServer &turnServer);
}
+CallManager *
+CallManager::create(QQmlEngine *qmlEngine, QJSEngine *)
+{
+ // The instance has to exist before it is used. We cannot replace it.
+ auto instance = ChatPage::instance()->callManager();
+ 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;
+}
+
CallManager::CallManager(QObject *parent)
: QObject(parent)
, session_(WebRTCSession::instance())
diff --git a/src/voip/CallManager.h b/src/voip/CallManager.h
index bbc7a903..e84b79c9 100644
--- a/src/voip/CallManager.h
+++ b/src/voip/CallManager.h
@@ -9,6 +9,7 @@
#include <QMediaPlayer>
#include <QObject>
+#include <QQmlEngine>
#include <QString>
#include <QStringList>
#include <QTimer>
@@ -29,6 +30,10 @@ class QUrl;
class CallManager final : public QObject
{
Q_OBJECT
+
+ QML_ELEMENT
+ QML_SINGLETON
+
Q_PROPERTY(bool haveCallInvite READ haveCallInvite NOTIFY newInviteState)
Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY newCallState)
Q_PROPERTY(bool isOnCallOnOtherDevice READ isOnCallOnOtherDevice NOTIFY newCallDeviceState)
@@ -49,6 +54,8 @@ class CallManager final : public QObject
public:
CallManager(QObject *);
+ static CallManager *create(QQmlEngine *qmlEngine, QJSEngine *);
+
bool haveCallInvite() const { return haveCallInvite_; }
bool isOnCall() const { return (session_.state() != webrtc::State::DISCONNECTED); }
bool isOnCallOnOtherDevice() const { return (isOnCallOnOtherDevice_ != ""); }
diff --git a/src/voip/WebRTCSession.cpp b/src/voip/WebRTCSession.cpp
index c40b39a4..ff459bf9 100644
--- a/src/voip/WebRTCSession.cpp
+++ b/src/voip/WebRTCSession.cpp
@@ -48,26 +48,26 @@ using webrtc::State;
WebRTCSession::WebRTCSession()
: devices_(CallDevices::instance())
{
- qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "CallType",
- QStringLiteral("Can't instantiate enum"));
-
- qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "ScreenShareType",
- QStringLiteral("Can't instantiate enum"));
-
- qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
- "im.nheko",
- 1,
- 0,
- "WebRTCState",
- QStringLiteral("Can't instantiate enum"));
+ // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "CallType",
+ // QStringLiteral("Can't instantiate enum"));
+
+ // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "ScreenShareType",
+ // QStringLiteral("Can't instantiate enum"));
+
+ // qmlRegisterUncreatableMetaObject(webrtc::staticMetaObject,
+ // "im.nheko",
+ // 1,
+ // 0,
+ // "WebRTCState",
+ // QStringLiteral("Can't instantiate enum"));
connect(this, &WebRTCSession::stateChanged, this, &WebRTCSession::setState);
init();
diff --git a/src/voip/WebRTCSession.h b/src/voip/WebRTCSession.h
index 82753372..3357bff7 100644
--- a/src/voip/WebRTCSession.h
+++ b/src/voip/WebRTCSession.h
@@ -8,6 +8,7 @@
#include <vector>
#include <QObject>
+#include <QQmlEngine>
#include "mtx/events/voip.hpp"
@@ -17,6 +18,7 @@ class QQuickItem;
namespace webrtc {
Q_NAMESPACE
+QML_NAMED_ELEMENT(Voip)
enum class CallType
{
|