diff --git a/main.cpp b/main.cpp index 2f64a99..767e0de 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,12 @@ #include #include #include +#include #include "matrix/controller.h" #include "matrix/roomlistmodel.h" +#include "matrix/imageprovider.h" + using namespace QMatrixClient; int main(int argc, char *argv[]) @@ -25,6 +28,13 @@ int main(int argc, char *argv[]) qmlRegisterType("Matrique", 0, 1, "RoomListModel"); QQmlApplicationEngine engine; + + Connection* m_connection = new Connection(); + ImageProvider* m_provider = new ImageProvider(); + m_provider->setConnection(m_connection); + + engine.rootContext()->setContextProperty("m_connection", m_connection); + engine.addImageProvider(QLatin1String("mxc"), m_provider); engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; diff --git a/matrique.pro b/matrique.pro index 332d518..7f63d01 100644 --- a/matrique.pro +++ b/matrique.pro @@ -16,7 +16,8 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += main.cpp \ matrix/controller.cpp \ - matrix/roomlistmodel.cpp + matrix/roomlistmodel.cpp \ + matrix/imageprovider.cpp RESOURCES += \ res.qrc @@ -48,4 +49,5 @@ DISTFILES += \ HEADERS += \ matrix/controller.h \ - matrix/roomlistmodel.h + matrix/roomlistmodel.h \ + matrix/imageprovider.h diff --git a/matrix/controller.cpp b/matrix/controller.cpp index b647585..a90581a 100644 --- a/matrix/controller.cpp +++ b/matrix/controller.cpp @@ -3,10 +3,7 @@ #include "libqmatrixclient/connection.h" Controller::Controller(QObject *parent) : QObject(parent) { - connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected); - connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect); - connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect); - connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync); + } Controller::~Controller() { @@ -31,6 +28,18 @@ void Controller::login(QString home, QString user, QString pass) { } } +void Controller::setConnection(QMatrixClient::Connection* conn) { + qDebug() << "Setting controller connection."; + m_connection = conn; + roomListModel = new RoomListModel(m_connection); + emit roomListModelChanged(); + connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected); + connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect); + connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect); + connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync); + emit connectionChanged(); +} + void Controller::logout() { userID = ""; token = ""; diff --git a/matrix/controller.h b/matrix/controller.h index a6563e9..5e23ebf 100644 --- a/matrix/controller.h +++ b/matrix/controller.h @@ -15,13 +15,11 @@ class Controller : public QObject Q_OBJECT Q_PROPERTY(RoomListModel *roomListModel READ getRoomListModel NOTIFY roomListModelChanged) + Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection NOTIFY connectionChanged) Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged) Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged) Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged) -private: - QMatrixClient::Connection* m_connection = new QMatrixClient::Connection(); - public: explicit Controller(QObject *parent = nullptr); ~Controller(); @@ -33,9 +31,13 @@ public: // All the non-Q_INVOKABLE functions. // All the Q_PROPERTYs. - RoomListModel* roomListModel = new RoomListModel(m_connection); + RoomListModel* roomListModel; RoomListModel* getRoomListModel() { return roomListModel; } + QMatrixClient::Connection* m_connection; + QMatrixClient::Connection* getConnection() { return m_connection; } + void setConnection(QMatrixClient::Connection* conn); + bool isLogin = false; bool getIsLogin() { return isLogin; } void setIsLogin(bool n) { @@ -70,6 +72,7 @@ private: signals: void roomListModelChanged(); + void connectionChanged(); void isLoginChanged(); void userIDChanged(); void tokenChanged(); diff --git a/matrix/imageprovider.cpp b/matrix/imageprovider.cpp new file mode 100644 index 0000000..ee0b9c8 --- /dev/null +++ b/matrix/imageprovider.cpp @@ -0,0 +1,71 @@ +#include "imageprovider.h" + +#include "connection.h" +#include "jobs/mediathumbnailjob.h" + +#include +#include +#include + +using QMatrixClient::MediaThumbnailJob; + +ImageProvider::ImageProvider(QObject *parent) + : QQuickImageProvider(QQmlImageProviderBase::Image, + QQmlImageProviderBase::ForceAsynchronousImageLoading) +{ +#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) + qRegisterMetaType(); +#endif +} + +QImage ImageProvider::requestImage(const QString& id, + QSize* pSize, const QSize& requestedSize) +{ + if (!id.startsWith("mxc://")) + { + qWarning() << "ImageProvider: won't fetch an invalid id:" << id + << "doesn't follow server/mediaId pattern"; + return {}; + } + + QUrl mxcUri { id }; + qDebug() << "ImageProvider::requestImage:" << mxcUri.toString(); + + MediaThumbnailJob* job = nullptr; + QReadLocker locker(&m_lock); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + QMetaObject::invokeMethod(m_connection, + [=] { return m_connection->getThumbnail(mxcUri, requestedSize); }, + Qt::BlockingQueuedConnection, &job); +#else + QMetaObject::invokeMethod(m_connection, "getThumbnail", + Qt::BlockingQueuedConnection, Q_RETURN_ARG(MediaThumbnailJob*, job), + Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize)); +#endif + if (!job) + { + qDebug() << "ImageProvider: failed to send a request"; + return {}; + } + QImage result; + { + QWaitCondition condition; // The most compact way to block on a signal + job->connect(job, &MediaThumbnailJob::finished, job, [&] { + result = job->thumbnail(); + condition.wakeAll(); + }); + condition.wait(&m_lock); + } + + if( pSize != nullptr ) + *pSize = result.size(); + + return result; +} + +void ImageProvider::setConnection(QMatrixClient::Connection* connection) +{ + QWriteLocker locker(&m_lock); + + m_connection = connection; +} diff --git a/matrix/imageprovider.h b/matrix/imageprovider.h new file mode 100644 index 0000000..78cb179 --- /dev/null +++ b/matrix/imageprovider.h @@ -0,0 +1,28 @@ +#ifndef IMAGEPROVIDER_H +#define IMAGEPROVIDER_H + +#include +#include + +namespace QMatrixClient { + class Connection; +} + +class ImageProvider: public QQuickImageProvider +{ + public: + explicit ImageProvider(QObject *parent = nullptr); + + QImage requestImage(const QString& id, QSize* pSize, + const QSize& requestedSize) override; + + void setConnection(QMatrixClient::Connection* connection); + + void initializeEngine(QQmlEngine *engine, const char *uri); + + private: + QMatrixClient::Connection* m_connection; + QReadWriteLock m_lock; +}; + +#endif // IMAGEPROVIDER_H diff --git a/matrix/roomlistmodel.cpp b/matrix/roomlistmodel.cpp index 905a932..56cc774 100644 --- a/matrix/roomlistmodel.cpp +++ b/matrix/roomlistmodel.cpp @@ -53,8 +53,8 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const { if(role == ValueRole) { return room->topic(); } - if(role == IconRole) { - return room->avatar(48); + if(role == AvatarRole) { + return room->avatarUrl(); } return QVariant(); } @@ -63,7 +63,7 @@ QHash RoomListModel::roleNames() const { QHash roles; roles[NameRole] = "name"; roles[ValueRole] = "value"; - roles[IconRole] = "icon"; + roles[AvatarRole] = "avatar"; return roles; } @@ -75,8 +75,3 @@ void RoomListModel::namesChanged(QMatrixClient::Room* room) { void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) { } - -RoomModel::RoomModel(QString name, QString value) { - m_name = name; - m_value = value; -} diff --git a/matrix/roomlistmodel.h b/matrix/roomlistmodel.h index e25fbe6..21fb553 100644 --- a/matrix/roomlistmodel.h +++ b/matrix/roomlistmodel.h @@ -12,28 +12,6 @@ namespace QMatrixClient { class Room; } -class RoomModel : public QObject -{ - Q_OBJECT - - Q_PROPERTY(QString name READ getName) - Q_PROPERTY(QString value READ getValue) - -public: - explicit RoomModel(QString name, QString value); - - QString getName() { return m_name; } - QString getValue() { return m_value; } - -signals: - void nameChanged(); - void valueChanged(); - -private: - QString m_name; - QString m_value; -}; - class RoomListModel : public QAbstractListModel { Q_OBJECT @@ -43,7 +21,7 @@ public: ~RoomListModel(); enum RoomModelRoles { - NameRole, ValueRole, IconRole + NameRole, ValueRole, AvatarRole }; QHash roleNames() const; diff --git a/qml/form/RoomListForm.qml b/qml/form/RoomListForm.qml index b29062b..a241c57 100644 --- a/qml/form/RoomListForm.qml +++ b/qml/form/RoomListForm.qml @@ -81,6 +81,7 @@ Item { Text { z: 10 text: "Here? No, not here." + color: "#424242" anchors.centerIn: parent visible: listView.count === 0 } @@ -113,7 +114,7 @@ Item { ImageStatus { width: parent.height height: parent.height - source: "qrc:/asset/img/avatar.png" + source: "image://mxc/" + avatar } Column { diff --git a/qml/main.qml b/qml/main.qml index ad91ffb..c75b2ab 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -18,17 +18,16 @@ ApplicationWindow { title: qsTr("Matrique") Controller { - id: controller - - onIsLoginChanged: console.log("Status:", isLogin) + id: matrixController + connection: m_connection } - Settings { - id: settings +// Settings { +// id: settings - property alias userID: controller.userID - property alias token: controller.token - } +// property var userID +// property var token +// } FontLoader { id: materialFont; source: "qrc:/asset/font/material.ttf" } @@ -51,7 +50,7 @@ ApplicationWindow { page: Room { id: roomPage - roomListModel: controller.roomListModel + roomListModel: matrixController.roomListModel//BUG: It will cause random crash as roomListModel may not be initialized. } } @@ -72,7 +71,7 @@ ApplicationWindow { page: Login { id: loginPage - controller: controller + controller: matrixController } }