Support Qt 5.11 and fix image provider.
This commit is contained in:
parent
a850224c98
commit
17fa7cc7da
18
main.cpp
18
main.cpp
|
@ -3,6 +3,7 @@
|
||||||
#include <QNetworkProxy>
|
#include <QNetworkProxy>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include "room.h"
|
||||||
#include "matrix/controller.h"
|
#include "matrix/controller.h"
|
||||||
#include "matrix/roomlistmodel.h"
|
#include "matrix/roomlistmodel.h"
|
||||||
#include "matrix/imageprovider.h"
|
#include "matrix/imageprovider.h"
|
||||||
|
@ -19,11 +20,13 @@ int main(int argc, char *argv[])
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
// Enable this if you need proxy.
|
// Enable this if you need proxy.
|
||||||
QNetworkProxy proxy;
|
// QNetworkProxy proxy;
|
||||||
proxy.setType(QNetworkProxy::HttpProxy);
|
// proxy.setType(QNetworkProxy::HttpProxy);
|
||||||
proxy.setHostName("localhost");
|
// proxy.setHostName("localhost");
|
||||||
proxy.setPort(1082);
|
// proxy.setPort(1082);
|
||||||
QNetworkProxy::setApplicationProxy(proxy);
|
// QNetworkProxy::setApplicationProxy(proxy);
|
||||||
|
|
||||||
|
qmlRegisterType<Room>(); qRegisterMetaType<Room*> ("Room*");
|
||||||
|
|
||||||
qmlRegisterType<Controller>("Matrique", 0, 1, "Controller");
|
qmlRegisterType<Controller>("Matrique", 0, 1, "Controller");
|
||||||
qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel");
|
qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel");
|
||||||
|
@ -31,13 +34,12 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QQmlApplicationEngine engine;
|
QQmlApplicationEngine engine;
|
||||||
|
|
||||||
Connection* m_connection = new Connection();
|
|
||||||
ImageProvider* m_provider = new ImageProvider();
|
ImageProvider* m_provider = new ImageProvider();
|
||||||
m_provider->setConnection(m_connection);
|
|
||||||
|
|
||||||
engine.rootContext()->setContextProperty("m_connection", m_connection);
|
engine.rootContext()->setContextProperty("imageProvider", m_provider->getConnection());
|
||||||
engine.addImageProvider(QLatin1String("mxc"), m_provider);
|
engine.addImageProvider(QLatin1String("mxc"), m_provider);
|
||||||
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
|
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
|
||||||
|
|
||||||
if (engine.rootObjects().isEmpty())
|
if (engine.rootObjects().isEmpty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@ SOURCES += main.cpp \
|
||||||
matrix/controller.cpp \
|
matrix/controller.cpp \
|
||||||
matrix/roomlistmodel.cpp \
|
matrix/roomlistmodel.cpp \
|
||||||
matrix/imageprovider.cpp \
|
matrix/imageprovider.cpp \
|
||||||
matrix/messageeventmodel.cpp \
|
matrix/messageeventmodel.cpp
|
||||||
matrix/matriqueroom.cpp
|
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
res.qrc
|
res.qrc
|
||||||
|
@ -53,5 +52,4 @@ HEADERS += \
|
||||||
matrix/controller.h \
|
matrix/controller.h \
|
||||||
matrix/roomlistmodel.h \
|
matrix/roomlistmodel.h \
|
||||||
matrix/imageprovider.h \
|
matrix/imageprovider.h \
|
||||||
matrix/messageeventmodel.h \
|
matrix/messageeventmodel.h
|
||||||
matrix/matriqueroom.h
|
|
||||||
|
|
|
@ -3,51 +3,52 @@
|
||||||
#include "libqmatrixclient/connection.h"
|
#include "libqmatrixclient/connection.h"
|
||||||
|
|
||||||
Controller::Controller(QObject *parent) : QObject(parent) {
|
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() {
|
Controller::~Controller() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::login(QString home, QString user, QString pass) {
|
void Controller::login() {
|
||||||
if(!isLogin) {
|
if (!isLogin) {
|
||||||
if(home.isEmpty()) home = "matrix.org";
|
|
||||||
|
|
||||||
qDebug() << "UserID:" << userID;
|
qDebug() << "UserID:" << userID;
|
||||||
qDebug() << "Token:" << token;
|
qDebug() << "Token:" << token;
|
||||||
qDebug() << "Home:" << home;
|
|
||||||
|
m_connection->setHomeserver(QUrl(homeserver));
|
||||||
|
m_connection->connectWithToken(userID, token, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass) {
|
||||||
|
if(!isLogin) {
|
||||||
|
qDebug() << "Server:" << serverAddr;
|
||||||
qDebug() << "User:" << user;
|
qDebug() << "User:" << user;
|
||||||
qDebug() << "Pass:" << pass;
|
qDebug() << "Pass:" << pass;
|
||||||
|
|
||||||
if(!userID.isEmpty() && !token.isEmpty()) {
|
if(!user.isEmpty() && !pass.isEmpty()) {
|
||||||
qDebug() << "Using token.";
|
|
||||||
m_connection->connectWithToken(userID, token, "");
|
|
||||||
} else if(!user.isEmpty() && !pass.isEmpty()) {
|
|
||||||
qDebug() << "Using given credential.";
|
qDebug() << "Using given credential.";
|
||||||
m_connection->connectToServer("@"+user+":"+home, pass, "");
|
m_connection->setHomeserver(QUrl(serverAddr));
|
||||||
|
m_connection->connectToServer(user, pass, "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "You are already logged in.";
|
qDebug() << "You are already logged in.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::setConnection(QMatrixClient::Connection* conn) {
|
|
||||||
m_connection = conn;
|
|
||||||
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() {
|
void Controller::logout() {
|
||||||
userID = "";
|
qDebug() << "Logging out.";
|
||||||
token = "";
|
setUserID("");
|
||||||
|
setToken("");
|
||||||
setIsLogin(false);
|
setIsLogin(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::connected() {
|
void Controller::connected() {
|
||||||
|
qDebug() << "Logged in.";
|
||||||
|
setHomeserver(m_connection->homeserver().toString());
|
||||||
setUserID(m_connection->userId());
|
setUserID(m_connection->userId());
|
||||||
setToken(m_connection->accessToken());
|
setToken(m_connection->accessToken());
|
||||||
m_connection->loadState();
|
m_connection->loadState();
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
#define CONTROLLER_H
|
#define CONTROLLER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "libqmatrixclient/connection.h"
|
#include "libqmatrixclient/connection.h"
|
||||||
|
|
||||||
#include "roomlistmodel.h"
|
#include "roomlistmodel.h"
|
||||||
|
|
||||||
namespace QMatrixClient {
|
namespace QMatrixClient {
|
||||||
|
@ -15,25 +13,27 @@ class Controller : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection NOTIFY connectionChanged)
|
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY connectionChanged)
|
||||||
Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged)
|
Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged)
|
||||||
|
Q_PROPERTY(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY homeserverChanged)
|
||||||
Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
|
Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
|
||||||
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
|
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
|
||||||
|
Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Controller(QObject *parent = nullptr);
|
explicit Controller(QObject *parent = nullptr);
|
||||||
~Controller();
|
~Controller();
|
||||||
|
|
||||||
// All the Q_INVOKABLEs.
|
// All the Q_INVOKABLEs.
|
||||||
Q_INVOKABLE void login(QString, QString, QString);
|
Q_INVOKABLE void login();
|
||||||
|
Q_INVOKABLE void loginWithCredentials(QString, QString, QString);
|
||||||
Q_INVOKABLE void logout();
|
Q_INVOKABLE void logout();
|
||||||
|
|
||||||
// All the non-Q_INVOKABLE functions.
|
// All the non-Q_INVOKABLE functions.
|
||||||
|
|
||||||
// All the Q_PROPERTYs.
|
// All the Q_PROPERTYs.
|
||||||
QMatrixClient::Connection* m_connection;
|
QMatrixClient::Connection* m_connection = new QMatrixClient::Connection();
|
||||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||||
void setConnection(QMatrixClient::Connection* conn);
|
|
||||||
|
|
||||||
bool isLogin = false;
|
bool isLogin = false;
|
||||||
bool getIsLogin() { return isLogin; }
|
bool getIsLogin() { return isLogin; }
|
||||||
|
@ -62,6 +62,24 @@ class Controller : public QObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString homeserver;
|
||||||
|
QString getHomeserver() { return homeserver; }
|
||||||
|
void setHomeserver(QString n) {
|
||||||
|
if (n != homeserver) {
|
||||||
|
homeserver = n;
|
||||||
|
emit homeserverChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool busy = false;
|
||||||
|
bool getBusy() { return busy; }
|
||||||
|
void setBusy(bool b) {
|
||||||
|
if (b != busy) {
|
||||||
|
busy = b;
|
||||||
|
emit busyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void connected();
|
void connected();
|
||||||
void resync();
|
void resync();
|
||||||
|
@ -72,7 +90,9 @@ class Controller : public QObject
|
||||||
void isLoginChanged();
|
void isLoginChanged();
|
||||||
void userIDChanged();
|
void userIDChanged();
|
||||||
void tokenChanged();
|
void tokenChanged();
|
||||||
void homeServerChanged();
|
void homeserverChanged();
|
||||||
|
void busyChanged();
|
||||||
|
void errorOccured();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,13 +10,22 @@
|
||||||
|
|
||||||
using QMatrixClient::MediaThumbnailJob;
|
using QMatrixClient::MediaThumbnailJob;
|
||||||
|
|
||||||
ImageProvider::ImageProvider(QObject *parent)
|
ImageProviderConnection::ImageProviderConnection(QObject* parent) : QObject(parent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProviderConnection::~ImageProviderConnection() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageProvider::ImageProvider(QObject* parent)
|
||||||
: QQuickImageProvider(QQmlImageProviderBase::Image,
|
: QQuickImageProvider(QQmlImageProviderBase::Image,
|
||||||
QQmlImageProviderBase::ForceAsynchronousImageLoading)
|
QQmlImageProviderBase::ForceAsynchronousImageLoading)
|
||||||
{
|
{
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
|
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
|
||||||
qRegisterMetaType<MediaThumbnailJob*>();
|
qRegisterMetaType<MediaThumbnailJob*>();
|
||||||
#endif
|
#endif
|
||||||
|
m_connection = new ImageProviderConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ImageProvider::requestImage(const QString& id,
|
QImage ImageProvider::requestImage(const QString& id,
|
||||||
|
@ -34,9 +43,10 @@ QImage ImageProvider::requestImage(const QString& id,
|
||||||
|
|
||||||
MediaThumbnailJob* job = nullptr;
|
MediaThumbnailJob* job = nullptr;
|
||||||
QReadLocker locker(&m_lock);
|
QReadLocker locker(&m_lock);
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||||
QMetaObject::invokeMethod(m_connection,
|
QMetaObject::invokeMethod(m_connection,
|
||||||
[=] { return m_connection->getThumbnail(mxcUri, requestedSize); },
|
[=] { return m_connection->getConnection()->getThumbnail(mxcUri, requestedSize); },
|
||||||
Qt::BlockingQueuedConnection, &job);
|
Qt::BlockingQueuedConnection, &job);
|
||||||
#else
|
#else
|
||||||
QMetaObject::invokeMethod(m_connection, "getThumbnail",
|
QMetaObject::invokeMethod(m_connection, "getThumbnail",
|
||||||
|
@ -64,9 +74,3 @@ QImage ImageProvider::requestImage(const QString& id,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageProvider::setConnection(QMatrixClient::Connection* connection)
|
|
||||||
{
|
|
||||||
QWriteLocker locker(&m_lock);
|
|
||||||
|
|
||||||
m_connection = connection;
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,26 +3,47 @@
|
||||||
|
|
||||||
#include <QtQuick/QQuickImageProvider>
|
#include <QtQuick/QQuickImageProvider>
|
||||||
#include <QtCore/QReadWriteLock>
|
#include <QtCore/QReadWriteLock>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
namespace QMatrixClient {
|
#include "libqmatrixclient/connection.h"
|
||||||
class Connection;
|
|
||||||
}
|
class ImageProviderConnection: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE setConnection NOTIFY connectionChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ImageProviderConnection(QObject* parent = nullptr);
|
||||||
|
~ImageProviderConnection();
|
||||||
|
|
||||||
|
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||||
|
Q_INVOKABLE void setConnection(QMatrixClient::Connection* connection) {
|
||||||
|
qDebug() << "Connection changed.";
|
||||||
|
emit connectionChanged();
|
||||||
|
m_connection = connection;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QMatrixClient::Connection* m_connection;
|
||||||
|
signals:
|
||||||
|
void connectionChanged();
|
||||||
|
};
|
||||||
|
|
||||||
class ImageProvider: public QQuickImageProvider
|
class ImageProvider: public QQuickImageProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ImageProvider(QObject *parent = nullptr);
|
explicit ImageProvider(QObject* parent = nullptr);
|
||||||
|
|
||||||
QImage requestImage(const QString& id, QSize* pSize,
|
QImage requestImage(const QString& id, QSize* pSize,
|
||||||
const QSize& requestedSize) override;
|
const QSize& requestedSize) override;
|
||||||
|
|
||||||
void setConnection(QMatrixClient::Connection* connection);
|
|
||||||
|
|
||||||
void initializeEngine(QQmlEngine *engine, const char *uri);
|
void initializeEngine(QQmlEngine *engine, const char *uri);
|
||||||
|
|
||||||
|
ImageProviderConnection* getConnection() { return m_connection; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMatrixClient::Connection* m_connection;
|
|
||||||
QReadWriteLock m_lock;
|
QReadWriteLock m_lock;
|
||||||
|
ImageProviderConnection* m_connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // IMAGEPROVIDER_H
|
#endif // IMAGEPROVIDER_H
|
||||||
|
|
|
@ -23,7 +23,6 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const
|
||||||
roles[AuthorRole] = "author";
|
roles[AuthorRole] = "author";
|
||||||
roles[ContentRole] = "content";
|
roles[ContentRole] = "content";
|
||||||
roles[ContentTypeRole] = "contentType";
|
roles[ContentTypeRole] = "contentType";
|
||||||
roles[HighlightRole] = "highlight";
|
|
||||||
roles[ReadMarkerRole] = "readMarker";
|
roles[ReadMarkerRole] = "readMarker";
|
||||||
roles[SpecialMarksRole] = "marks";
|
roles[SpecialMarksRole] = "marks";
|
||||||
roles[LongOperationRole] = "progressInfo";
|
roles[LongOperationRole] = "progressInfo";
|
||||||
|
@ -38,7 +37,7 @@ MessageEventModel::MessageEventModel(QObject* parent)
|
||||||
qRegisterMetaType<QMatrixClient::FileTransferInfo>();
|
qRegisterMetaType<QMatrixClient::FileTransferInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageEventModel::changeRoom(MatriqueRoom* room)
|
void MessageEventModel::changeRoom(QMatrixClient::Room* room)
|
||||||
{
|
{
|
||||||
if (room == m_currentRoom)
|
if (room == m_currentRoom)
|
||||||
return;
|
return;
|
||||||
|
@ -114,7 +113,7 @@ inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti)
|
||||||
return ti->timestamp().isValid();
|
return ti->timestamp().isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime MessageEventModel::makeMessageTimestamp(MatriqueRoom::rev_iter_t baseIt) const
|
QDateTime MessageEventModel::makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const
|
||||||
{
|
{
|
||||||
const auto& timeline = m_currentRoom->messageEvents();
|
const auto& timeline = m_currentRoom->messageEvents();
|
||||||
auto ts = baseIt->event()->timestamp();
|
auto ts = baseIt->event()->timestamp();
|
||||||
|
@ -137,7 +136,7 @@ QDateTime MessageEventModel::makeMessageTimestamp(MatriqueRoom::rev_iter_t baseI
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MessageEventModel::makeDateString(MatriqueRoom::rev_iter_t baseIt) const
|
QString MessageEventModel::makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const
|
||||||
{
|
{
|
||||||
auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
|
auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
|
||||||
if (QMatrixClient::SettingsGroup("UI")
|
if (QMatrixClient::SettingsGroup("UI")
|
||||||
|
@ -402,9 +401,6 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(role == HighlightRole)
|
|
||||||
return m_currentRoom->isEventHighlighted(event);
|
|
||||||
|
|
||||||
if(role == ReadMarkerRole)
|
if(role == ReadMarkerRole)
|
||||||
return event->id() == lastReadEventId;
|
return event->id() == lastReadEventId;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
#define MESSAGEEVENTMODEL_H
|
#define MESSAGEEVENTMODEL_H
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
#include <QtCore/QAbstractListModel>
|
||||||
|
#include "room.h"
|
||||||
#include "matriqueroom.h"
|
|
||||||
|
|
||||||
class MessageEventModel: public QAbstractListModel
|
class MessageEventModel: public QAbstractListModel
|
||||||
{
|
{
|
||||||
|
@ -13,7 +12,7 @@ class MessageEventModel: public QAbstractListModel
|
||||||
// has to be re-calculated anyway).
|
// has to be re-calculated anyway).
|
||||||
// XXX: A better way would be to make [Room::]Timeline a list model
|
// XXX: A better way would be to make [Room::]Timeline a list model
|
||||||
// itself, leaving only representation of the model to a client.
|
// itself, leaving only representation of the model to a client.
|
||||||
Q_PROPERTY(MatriqueRoom* room MEMBER m_currentRoom CONSTANT)
|
Q_PROPERTY(QMatrixClient::Room* room MEMBER m_currentRoom CONSTANT)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum EventRoles {
|
enum EventRoles {
|
||||||
|
@ -25,7 +24,6 @@ class MessageEventModel: public QAbstractListModel
|
||||||
AuthorRole,
|
AuthorRole,
|
||||||
ContentRole,
|
ContentRole,
|
||||||
ContentTypeRole,
|
ContentTypeRole,
|
||||||
HighlightRole,
|
|
||||||
ReadMarkerRole,
|
ReadMarkerRole,
|
||||||
SpecialMarksRole,
|
SpecialMarksRole,
|
||||||
LongOperationRole,
|
LongOperationRole,
|
||||||
|
@ -33,7 +31,7 @@ class MessageEventModel: public QAbstractListModel
|
||||||
|
|
||||||
explicit MessageEventModel(QObject* parent = nullptr);
|
explicit MessageEventModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
void changeRoom(MatriqueRoom* room);
|
void changeRoom(QMatrixClient::Room* room);
|
||||||
|
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
|
@ -43,11 +41,11 @@ class MessageEventModel: public QAbstractListModel
|
||||||
void refreshEvent(const QString& eventId);
|
void refreshEvent(const QString& eventId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MatriqueRoom* m_currentRoom;
|
QMatrixClient::Room* m_currentRoom;
|
||||||
QString lastReadEventId;
|
QString lastReadEventId;
|
||||||
|
|
||||||
QDateTime makeMessageTimestamp(MatriqueRoom::rev_iter_t baseIt) const;
|
QDateTime makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||||
QString makeDateString(MatriqueRoom::rev_iter_t baseIt) const;
|
QString makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||||
void refreshEventRoles(const QString& eventId, const QVector<int> roles);
|
void refreshEventRoles(const QString& eventId, const QVector<int> roles);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,131 +1,43 @@
|
||||||
#include "roomlistmodel.h"
|
#include "roomlistmodel.h"
|
||||||
|
|
||||||
#include <QtGui/QIcon>
|
#include <QtGui/QBrush>
|
||||||
|
#include <QtGui/QColor>
|
||||||
#include "matriqueroom.h"
|
#include <QtCore/QDebug>
|
||||||
#include "connection.h"
|
|
||||||
#include "user.h"
|
|
||||||
|
|
||||||
RoomListModel::RoomListModel(QObject* parent)
|
RoomListModel::RoomListModel(QObject* parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{ }
|
{
|
||||||
|
m_connection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomListModel::~RoomListModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void RoomListModel::setConnection(QMatrixClient::Connection* connection)
|
void RoomListModel::setConnection(QMatrixClient::Connection* connection)
|
||||||
{
|
{
|
||||||
Q_ASSERT(connection);
|
|
||||||
|
|
||||||
using QMatrixClient::Room;
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_connection = connection;
|
m_connection = connection;
|
||||||
connect( connection, &QMatrixClient::Connection::loggedOut,
|
m_rooms.clear();
|
||||||
this, [=]{ deleteConnection(connection); } );
|
connect( connection, &QMatrixClient::Connection::newRoom, this, &RoomListModel::addRoom );
|
||||||
connect( connection, &QMatrixClient::Connection::invitedRoom,
|
for( QMatrixClient::Room* room: connection->roomMap().values() ) {
|
||||||
this, &RoomListModel::updateRoom);
|
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
|
||||||
connect( connection, &QMatrixClient::Connection::joinedRoom,
|
m_rooms.append(room);
|
||||||
this, &RoomListModel::updateRoom);
|
}
|
||||||
connect( connection, &QMatrixClient::Connection::leftRoom,
|
|
||||||
this, &RoomListModel::updateRoom);
|
|
||||||
connect( connection, &QMatrixClient::Connection::aboutToDeleteRoom,
|
|
||||||
this, &RoomListModel::deleteRoom);
|
|
||||||
|
|
||||||
for( auto r: connection->roomMap() )
|
|
||||||
doAddRoom(r);
|
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomListModel::deleteConnection(QMatrixClient::Connection* connection) {
|
QMatrixClient::Room* RoomListModel::roomAt(int row)
|
||||||
|
{
|
||||||
|
return m_rooms.at(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
MatriqueRoom* RoomListModel::roomAt(QModelIndex index) const
|
void RoomListModel::addRoom(QMatrixClient::Room* room)
|
||||||
{
|
{
|
||||||
return m_rooms.at(index.row());
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex RoomListModel::indexOf(MatriqueRoom* room) const
|
|
||||||
{
|
|
||||||
return index(m_rooms.indexOf(room), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::updateRoom(QMatrixClient::Room* room,
|
|
||||||
QMatrixClient::Room* prev)
|
|
||||||
{
|
|
||||||
// There are two cases when this method is called:
|
|
||||||
// 1. (prev == nullptr) adding a new room to the room list
|
|
||||||
// 2. (prev != nullptr) accepting/rejecting an invitation or inviting to
|
|
||||||
// the previously left room (in both cases prev has the previous state).
|
|
||||||
if (prev == room)
|
|
||||||
{
|
|
||||||
qCritical() << "RoomListModel::updateRoom: room tried to replace itself";
|
|
||||||
refresh(static_cast<MatriqueRoom*>(room));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (prev && room->id() != prev->id())
|
|
||||||
{
|
|
||||||
qCritical() << "RoomListModel::updateRoom: attempt to update room"
|
|
||||||
<< room->id() << "to" << prev->id();
|
|
||||||
// That doesn't look right but technically we still can do it.
|
|
||||||
}
|
|
||||||
// Ok, we're through with pre-checks, now for the real thing.
|
|
||||||
auto* newRoom = static_cast<MatriqueRoom*>(room);
|
|
||||||
const auto it = std::find_if(m_rooms.begin(), m_rooms.end(),
|
|
||||||
[=](const MatriqueRoom* r) { return r == prev || r == newRoom; });
|
|
||||||
if (it != m_rooms.end())
|
|
||||||
{
|
|
||||||
const int row = it - m_rooms.begin();
|
|
||||||
// There's no guarantee that prev != newRoom
|
|
||||||
if (*it == prev && *it != newRoom)
|
|
||||||
{
|
|
||||||
prev->disconnect(this);
|
|
||||||
m_rooms.replace(row, newRoom);
|
|
||||||
connectRoomSignals(newRoom);
|
|
||||||
}
|
|
||||||
emit dataChanged(index(row), index(row));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
|
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
|
||||||
doAddRoom(newRoom);
|
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
|
||||||
endInsertRows();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::deleteRoom(QMatrixClient::Room* room)
|
|
||||||
{
|
|
||||||
auto i = m_rooms.indexOf(static_cast<MatriqueRoom*>(room));
|
|
||||||
if (i == -1)
|
|
||||||
return; // Already deleted, nothing to do
|
|
||||||
|
|
||||||
beginRemoveRows(QModelIndex(), i, i);
|
|
||||||
m_rooms.removeAt(i);
|
|
||||||
endRemoveRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::doAddRoom(QMatrixClient::Room* r)
|
|
||||||
{
|
|
||||||
if (auto* room = static_cast<MatriqueRoom*>(r))
|
|
||||||
{
|
|
||||||
m_rooms.append(room);
|
m_rooms.append(room);
|
||||||
connectRoomSignals(room);
|
endInsertRows();
|
||||||
} else
|
|
||||||
{
|
|
||||||
qCritical() << "Attempt to add nullptr to the room list";
|
|
||||||
Q_ASSERT(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::connectRoomSignals(MatriqueRoom* room)
|
|
||||||
{
|
|
||||||
connect(room, &MatriqueRoom::displaynameChanged,
|
|
||||||
this, [=]{ displaynameChanged(room); } );
|
|
||||||
connect( room, &MatriqueRoom::unreadMessagesChanged,
|
|
||||||
this, [=]{ unreadMessagesChanged(room); } );
|
|
||||||
connect( room, &MatriqueRoom::notificationCountChanged,
|
|
||||||
this, [=]{ unreadMessagesChanged(room); } );
|
|
||||||
connect( room, &MatriqueRoom::joinStateChanged,
|
|
||||||
this, [=]{ refresh(room); });
|
|
||||||
connect( room, &MatriqueRoom::avatarChanged,
|
|
||||||
this, [=]{ refresh(room, { Qt::DecorationRole }); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int RoomListModel::rowCount(const QModelIndex& parent) const
|
int RoomListModel::rowCount(const QModelIndex& parent) const
|
||||||
|
@ -145,83 +57,47 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const
|
||||||
qDebug() << "UserListModel: something wrong here...";
|
qDebug() << "UserListModel: something wrong here...";
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
auto room = m_rooms.at(index.row());
|
QMatrixClient::Room* room = m_rooms.at(index.row());
|
||||||
using QMatrixClient::JoinState;
|
if( role == Qt::DisplayRole )
|
||||||
switch (role)
|
|
||||||
{
|
{
|
||||||
case Qt::DisplayRole:
|
|
||||||
return room->displayName();
|
return room->displayName();
|
||||||
case Qt::DecorationRole:
|
}
|
||||||
|
if( role == Qt::ForegroundRole )
|
||||||
|
{
|
||||||
|
if( room->highlightCount() > 0 )
|
||||||
|
return QBrush(QColor("orange"));
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
if( role == Qt::DecorationRole )
|
||||||
{
|
{
|
||||||
if(room->avatarUrl().toString() != "") {
|
if(room->avatarUrl().toString() != "") {
|
||||||
qInfo() << "Room avatar:" << room->avatarUrl();
|
|
||||||
return room->avatarUrl();
|
return room->avatarUrl();
|
||||||
} else if(room->users().length() == 2) {
|
|
||||||
QMatrixClient::User* user = room->users().at(0);
|
|
||||||
qInfo() << "User avatar:" << user->avatarUrl();
|
|
||||||
return user->avatarUrl();
|
|
||||||
}
|
}
|
||||||
|
return QVariant();
|
||||||
}
|
}
|
||||||
case Qt::StatusTipRole:
|
if (role == Qt::StatusTipRole )
|
||||||
{
|
{
|
||||||
return room->topic();
|
return room->topic();
|
||||||
}
|
}
|
||||||
case Qt::ToolTipRole:
|
|
||||||
{
|
|
||||||
int hlCount = room->highlightCount();
|
|
||||||
auto result = QStringLiteral("<b>%1</b><br>").arg(room->displayName());
|
|
||||||
result += tr("Main alias: %1<br>").arg(room->canonicalAlias());
|
|
||||||
result += tr("Members: %1<br>").arg(room->memberCount());
|
|
||||||
if (hlCount > 0)
|
|
||||||
result += tr("Unread mentions: %1<br>").arg(hlCount);
|
|
||||||
result += tr("ID: %1<br>").arg(room->id());
|
|
||||||
switch (room->joinState())
|
|
||||||
{
|
|
||||||
case JoinState::Join:
|
|
||||||
result += tr("You joined this room");
|
|
||||||
break;
|
|
||||||
case JoinState::Leave:
|
|
||||||
result += tr("You left this room");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result += tr("You were invited into this room");
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
case HasUnreadRole:
|
|
||||||
return room->hasUnreadMessages();
|
|
||||||
case HighlightCountRole:
|
|
||||||
return room->highlightCount();
|
|
||||||
case JoinStateRole:
|
|
||||||
return toCString(room->joinState()); // FIXME: better make the enum QVariant-convertible
|
|
||||||
default:
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RoomListModel::namesChanged(QMatrixClient::Room* room)
|
||||||
|
{
|
||||||
|
int row = m_rooms.indexOf(room);
|
||||||
|
emit dataChanged(index(row), index(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room)
|
||||||
|
{
|
||||||
|
int row = m_rooms.indexOf(room);
|
||||||
|
emit dataChanged(index(row), index(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> RoomListModel::roleNames() const {
|
QHash<int, QByteArray> RoomListModel::roleNames() const {
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
roles[Qt::DisplayRole] = "name";
|
roles[Qt::DisplayRole] = "name";
|
||||||
roles[Qt::DecorationRole] = "avatar";
|
roles[Qt::DecorationRole] = "avatar";
|
||||||
roles[Qt::StatusTipRole] = "value";
|
roles[Qt::StatusTipRole] = "topic";
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomListModel::displaynameChanged(MatriqueRoom* room)
|
|
||||||
{
|
|
||||||
refresh(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::unreadMessagesChanged(MatriqueRoom* room)
|
|
||||||
{
|
|
||||||
refresh(room);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RoomListModel::refresh(MatriqueRoom* room, const QVector<int>& roles)
|
|
||||||
{
|
|
||||||
int row = m_rooms.indexOf(room);
|
|
||||||
if (row == -1)
|
|
||||||
qCritical() << "Room" << room->id() << "not found in the room list";
|
|
||||||
else
|
|
||||||
emit dataChanged(index(row), index(row), roles);
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,55 +2,39 @@
|
||||||
#define ROOMLISTMODEL_H
|
#define ROOMLISTMODEL_H
|
||||||
|
|
||||||
#include <QtCore/QAbstractListModel>
|
#include <QtCore/QAbstractListModel>
|
||||||
|
#include "room.h"
|
||||||
#include "matriqueroom.h"
|
#include "connection.h"
|
||||||
|
|
||||||
namespace QMatrixClient
|
|
||||||
{
|
|
||||||
class Connection;
|
|
||||||
class Room;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RoomListModel: public QAbstractListModel
|
class RoomListModel: public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection)
|
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Roles {
|
RoomListModel(QObject* parent=0);
|
||||||
HasUnreadRole = Qt::UserRole + 1,
|
virtual ~RoomListModel();
|
||||||
HighlightCountRole, JoinStateRole
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit RoomListModel(QObject* parent = nullptr);
|
QMatrixClient::Connection* getConnection() {return m_connection;}
|
||||||
|
|
||||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
|
||||||
void setConnection(QMatrixClient::Connection* connection);
|
void setConnection(QMatrixClient::Connection* connection);
|
||||||
void deleteConnection(QMatrixClient::Connection* connection);
|
|
||||||
|
|
||||||
MatriqueRoom* roomAt(QModelIndex index) const;
|
Q_INVOKABLE QMatrixClient::Room* roomAt(int row);
|
||||||
QModelIndex indexOf(MatriqueRoom* room) const;
|
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
|
Q_INVOKABLE int rowCount(const QModelIndex& parent=QModelIndex()) const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex& index, int role) const override;
|
|
||||||
QHash<int, QByteArray> roleNames() const;
|
QHash<int, QByteArray> roleNames() const;
|
||||||
int rowCount(const QModelIndex& parent) const override;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void displaynameChanged(MatriqueRoom* room);
|
void namesChanged(QMatrixClient::Room* room);
|
||||||
void unreadMessagesChanged(MatriqueRoom* room);
|
void unreadMessagesChanged(QMatrixClient::Room* room);
|
||||||
void refresh(MatriqueRoom* room, const QVector<int>& roles = {});
|
void addRoom(QMatrixClient::Room* room);
|
||||||
|
|
||||||
void updateRoom(QMatrixClient::Room* room,
|
|
||||||
QMatrixClient::Room* prev);
|
|
||||||
void deleteRoom(QMatrixClient::Room* room);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMatrixClient::Connection* m_connection;
|
QMatrixClient::Connection* m_connection;
|
||||||
QList<MatriqueRoom*> m_rooms;
|
QList<QMatrixClient::Room*> m_rooms;
|
||||||
|
|
||||||
void doAddRoom(QMatrixClient::Room* r);
|
signals:
|
||||||
void connectRoomSignals(MatriqueRoom* room);
|
void connectionChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ROOMLISTMODEL_H
|
#endif // ROOMLISTMODEL_H
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.3
|
|
||||||
import "qrc:/qml/form"
|
|
||||||
|
|
||||||
Page {
|
|
||||||
property var contactListModel
|
|
||||||
|
|
||||||
ListForm {
|
|
||||||
id: roomListForm
|
|
||||||
height: parent.height
|
|
||||||
width: 320
|
|
||||||
listModel: contactListModel
|
|
||||||
}
|
|
||||||
|
|
||||||
DetailForm {
|
|
||||||
id: detailForm
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: roomListForm.width
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,18 +9,6 @@ import "qrc:/qml/component"
|
||||||
Page {
|
Page {
|
||||||
property var controller
|
property var controller
|
||||||
|
|
||||||
property alias homeserver: settings.server
|
|
||||||
property alias username: settings.user
|
|
||||||
property alias password: settings.pass
|
|
||||||
|
|
||||||
Settings {
|
|
||||||
id: settings
|
|
||||||
|
|
||||||
property alias server: serverField.text
|
|
||||||
property alias user: usernameField.text
|
|
||||||
property alias pass: passwordField.text
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -68,29 +56,33 @@ Page {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
padding: 64
|
padding: 64
|
||||||
|
|
||||||
Column {
|
ColumnLayout {
|
||||||
id: main_col
|
id: mainCol
|
||||||
spacing: 8
|
width: parent.width
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
ImageStatus {
|
ImageStatus {
|
||||||
width: 96
|
Layout.preferredWidth: 96
|
||||||
height: width
|
Layout.preferredHeight: 96
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
source: "qrc:/asset/img/avatar.png"
|
source: "qrc:/asset/img/avatar.png"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: serverField
|
id: serverField
|
||||||
width: parent.width
|
|
||||||
height: 48
|
Layout.fillWidth: true
|
||||||
placeholderText: "Server"
|
|
||||||
leftPadding: 16
|
leftPadding: 16
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
|
||||||
|
placeholderText: "Server"
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
implicitHeight: 48
|
||||||
|
|
||||||
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
border.color: parent.activeFocus ? Material.accent : "transparent"
|
border.color: parent.activeFocus ? Material.accent : "transparent"
|
||||||
border.width: 2
|
border.width: 2
|
||||||
}
|
}
|
||||||
|
@ -98,15 +90,19 @@ Page {
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: usernameField
|
id: usernameField
|
||||||
width: parent.width
|
|
||||||
height: 48
|
Layout.fillWidth: true
|
||||||
placeholderText: "Username"
|
|
||||||
leftPadding: 16
|
leftPadding: 16
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
|
||||||
|
placeholderText: "Username"
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
implicitHeight: 48
|
||||||
|
|
||||||
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
border.color: parent.activeFocus ? Material.accent : "transparent"
|
border.color: parent.activeFocus ? Material.accent : "transparent"
|
||||||
border.width: 2
|
border.width: 2
|
||||||
}
|
}
|
||||||
|
@ -114,15 +110,20 @@ Page {
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
width: parent.width
|
|
||||||
height: 48
|
Layout.fillWidth: true
|
||||||
placeholderText: "Password"
|
|
||||||
leftPadding: 16
|
leftPadding: 16
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
|
||||||
|
placeholderText: "Password"
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
implicitHeight: 48
|
||||||
|
|
||||||
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
border.color: parent.activeFocus ? Material.accent : "transparent"
|
border.color: parent.activeFocus ? Material.accent : "transparent"
|
||||||
border.width: 2
|
border.width: 2
|
||||||
}
|
}
|
||||||
|
@ -130,20 +131,13 @@ Page {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: loginButton
|
id: loginButton
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
text: "LOGIN"
|
text: "LOGIN"
|
||||||
highlighted: true
|
highlighted: true
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
onClicked: controller.login(homeserver, username, password)
|
onClicked: controller.loginWithCredentials(serverField.text, usernameField.text, passwordField.text)
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: logoutButton
|
|
||||||
text: "LOGOUT"
|
|
||||||
flat: true
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
onClicked: controller.logout()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
qml/Room.qml
39
qml/Room.qml
|
@ -1,24 +1,47 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import Matrique 0.1
|
||||||
|
|
||||||
import "qrc:/qml/form"
|
import "qrc:/qml/form"
|
||||||
|
|
||||||
import Matrique 0.1
|
|
||||||
|
|
||||||
Page {
|
Page {
|
||||||
property RoomListModel roomListModel
|
property alias connection: roomListModel.connection
|
||||||
|
|
||||||
|
id: page
|
||||||
|
|
||||||
|
RoomListModel {
|
||||||
|
id: roomListModel
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
ListForm {
|
ListForm {
|
||||||
id: roomListForm
|
id: roomListForm
|
||||||
height: parent.height
|
|
||||||
width: 320
|
Layout.fillHeight: true
|
||||||
|
// Layout.preferredWidth: {
|
||||||
|
// if (page.width > 560) {
|
||||||
|
// return page.width * 0.4;
|
||||||
|
// } else {
|
||||||
|
// return 80;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Layout.preferredWidth: 320
|
||||||
|
Layout.maximumWidth: 360
|
||||||
|
|
||||||
listModel: roomListModel
|
listModel: roomListModel
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomForm {
|
RoomForm {
|
||||||
id: roomForm
|
id: roomForm
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: roomListForm.width
|
Layout.fillWidth: true
|
||||||
roomIndex: roomListForm.currentIndex
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
currentRoom: roomListForm.currentIndex != -1 ? roomListModel.roomAt(roomListForm.currentIndex) : null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.3
|
|
||||||
import QtQuick.Controls.Material 2.3
|
|
||||||
|
|
||||||
Page {
|
|
||||||
property alias theme: themeSwitch.checked
|
|
||||||
header: TabBar {
|
|
||||||
id: settingBar
|
|
||||||
width: parent.width
|
|
||||||
z: 10
|
|
||||||
currentIndex: settingBar.currentIndex
|
|
||||||
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("Overview")
|
|
||||||
}
|
|
||||||
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("Interface")
|
|
||||||
}
|
|
||||||
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("Network")
|
|
||||||
}
|
|
||||||
|
|
||||||
TabButton {
|
|
||||||
text: qsTr("Sync")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SwipeView {
|
|
||||||
id: settingSwipe
|
|
||||||
|
|
||||||
currentIndex: settingBar.currentIndex
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
Page {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Page {
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
Switch {
|
|
||||||
id: themeSwitch
|
|
||||||
text: qsTr("Dark Theme")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Page {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Page {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.3
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property Connection currentConnection: null
|
|
||||||
property var currentRoom: null
|
|
||||||
|
|
||||||
function setRoom(room) {
|
|
||||||
currentRoom = room
|
|
||||||
messageModel.changeRoom(room)
|
|
||||||
}
|
|
||||||
|
|
||||||
function setConnection(conn) {
|
|
||||||
currentConnection = conn
|
|
||||||
messageModel.setConnection(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendLine(text) {
|
|
||||||
if(!currentRoom || !currentConnection) return
|
|
||||||
currentConnection.postMessage(currentRoom, "m.text", text)
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
|
||||||
id: chatView
|
|
||||||
anchors.fill: parent
|
|
||||||
flickableDirection: Flickable.VerticalFlick
|
|
||||||
verticalLayoutDirection: ListView.BottomToTop
|
|
||||||
model: MessageEventModel { id: messageModel }
|
|
||||||
|
|
||||||
delegate: Row {
|
|
||||||
id: message
|
|
||||||
width: parent.width
|
|
||||||
spacing: 8
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: timelabel
|
|
||||||
text: time.toLocaleTimeString("hh:mm:ss")
|
|
||||||
color: "grey"
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
width: 64
|
|
||||||
elide: Text.ElideRight
|
|
||||||
text: eventType == "message" ? author : "***"
|
|
||||||
color: eventType == "message" ? "grey" : "lightgrey"
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
text: content
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
width: parent.width - (x - parent.x) - spacing
|
|
||||||
color: eventType == "message" ? "black" : "lightgrey"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
property: "date"
|
|
||||||
labelPositioning: ViewSection.CurrentLabelAtStart
|
|
||||||
delegate: Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: childrenRect.height
|
|
||||||
Label {
|
|
||||||
width: parent.width
|
|
||||||
text: section.toLocaleString(Qt.locale())
|
|
||||||
color: "grey"
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onAtYBeginningChanged: {
|
|
||||||
if(currentRoom && atYBeginning) currentRoom.getPreviousContent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +1,31 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.11
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.4
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property bool statusIndicator: false
|
|
||||||
property bool opaqueBackground: false
|
property bool opaqueBackground: false
|
||||||
property alias source: avatar.source
|
property alias source: avatar.source
|
||||||
|
|
||||||
|
id: item
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.width
|
width: item.width
|
||||||
height: parent.width
|
height: item.width
|
||||||
radius: parent.width / 2
|
radius: item.width / 2
|
||||||
color: "white"
|
color: "white"
|
||||||
visible: opaqueBackground
|
visible: opaqueBackground
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: avatar
|
id: avatar
|
||||||
width: parent.width
|
width: item.width
|
||||||
height: parent.width
|
height: item.width
|
||||||
|
|
||||||
mipmap: true
|
mipmap: true
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
sourceSize.width: parent.width
|
sourceSize.width: item.width
|
||||||
sourceSize.height: parent.width
|
sourceSize.height: item.width
|
||||||
|
|
||||||
layer.effect: OpacityMask {
|
layer.effect: OpacityMask {
|
||||||
maskSource: Item {
|
maskSource: Item {
|
||||||
|
@ -38,15 +39,5 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.width
|
|
||||||
radius: parent.width / 2
|
|
||||||
color: "transparent"
|
|
||||||
border.color: "#4caf50"
|
|
||||||
border.width: 4
|
|
||||||
visible: statusIndicator
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.10
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.3
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls.Material 2.3
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property alias icon: iconText.text
|
property alias icon: iconText.text
|
||||||
property var color: "white"
|
property var color: Material.theme == Material.Light ? "black" : "white"
|
||||||
|
|
||||||
id: item
|
id: item
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,9 @@ import QtQuick.Controls 2.3
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls.Material 2.3
|
import QtQuick.Controls.Material 2.3
|
||||||
|
|
||||||
Drawer {
|
Item {
|
||||||
property SwipeView swipeView
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
interactive: false
|
|
||||||
position: 1.0
|
|
||||||
visible: true
|
|
||||||
modal: false
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: Material.accent
|
color: Material.accent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls.Material 2.3
|
import QtQuick.Controls.Material 2.3
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property Item page
|
property var page
|
||||||
property alias contentItem: buttonDelegate.contentItem
|
property alias contentItem: buttonDelegate.contentItem
|
||||||
signal clicked
|
signal clicked
|
||||||
|
|
||||||
|
|
|
@ -50,28 +50,14 @@ Item {
|
||||||
width: parent.height
|
width: parent.height
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue0b7" }
|
||||||
text: "\ue0b7"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDelegate {
|
ItemDelegate {
|
||||||
width: parent.height
|
width: parent.height
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue62e" }
|
||||||
text: "\ue62e"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,97 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.11
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.4
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.11
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
import QtQuick.Controls.Material 2.3
|
import QtQuick.Controls.Material 2.3
|
||||||
|
import QtQml.Models 2.3
|
||||||
|
import Matrique 0.1
|
||||||
|
|
||||||
import "qrc:/qml/component"
|
import "qrc:/qml/component"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property var listModel
|
property alias listModel: delegateModel.model
|
||||||
property alias currentIndex: listView.currentIndex
|
property alias currentIndex: listView.currentIndex
|
||||||
|
readonly property bool mini: width <= 80 // Used as an indicator of whether the listform should be displayed as "Mini mode".
|
||||||
|
|
||||||
|
DelegateModel {
|
||||||
|
id: delegateModel
|
||||||
|
groups: [
|
||||||
|
DelegateModelGroup {
|
||||||
|
name: "filterGroup"; includeByDefault: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
filterOnGroup: "filterGroup"
|
||||||
|
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
width: parent.width
|
||||||
|
height: 80
|
||||||
|
onClicked: listView.currentIndex = index
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 16
|
||||||
|
spacing: 16
|
||||||
|
|
||||||
|
ImageStatus {
|
||||||
|
Layout.preferredWidth: height
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
source: avatar == null || avatar == "" ? "qrc:/asset/img/avatar.png" : "image://mxc/" + avatar
|
||||||
|
opaqueBackground: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
text: {
|
||||||
|
if (name != "") {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (alias != "") {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
font.pointSize: 16
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.NoWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
text: topic === "" ? "No topic yet." : topic
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.NoWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilter(filterName){
|
||||||
|
var roomCount = listModel.rowCount();
|
||||||
|
for (var i = 0; i < roomCount; i++){
|
||||||
|
var roomName = "";
|
||||||
|
if (listModel.roomAt(i).name != "") {
|
||||||
|
roomName = listModel.roomAt(i).name;
|
||||||
|
} else if (model.alias != "") {
|
||||||
|
roomName = listModel.roomAt(i).alias;
|
||||||
|
} else {
|
||||||
|
roomName = listModel.roomAt(i).id;
|
||||||
|
}
|
||||||
|
if (roomName.toLowerCase().indexOf(filterName.toLowerCase()) !== -1) {
|
||||||
|
items.addGroups(i, 1, "filterGroup");
|
||||||
|
} else {items.removeGroups(i, 1, "filterGroup");}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -22,10 +106,10 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: serverField
|
id: searchField
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 36
|
height: 36
|
||||||
leftPadding: 16
|
leftPadding: mini ? 4 : 16
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
@ -34,19 +118,17 @@ Item {
|
||||||
Row {
|
Row {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Text {
|
MaterialIcon {
|
||||||
width: parent.height
|
icon: "\ue8b6"
|
||||||
height: parent.height
|
|
||||||
text: "\ue8b6"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
color: "white"
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
width: mini ? parent.width : parent.height
|
||||||
|
height: parent.height
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
visible: !mini
|
||||||
text: "Search"
|
text: "Search"
|
||||||
color: "white"
|
color: "white"
|
||||||
font.pointSize: 12
|
font.pointSize: 12
|
||||||
|
@ -56,15 +138,19 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: serverField.activeFocus || serverField.text != "" ? parent.width : 0
|
width: searchField.activeFocus || searchField.text != "" ? parent.width : 0
|
||||||
height: parent.height
|
height: parent.height
|
||||||
color: "white"
|
color: "white"
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 }
|
PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
delegateModel.applyFilter(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,13 +163,12 @@ Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "#eaeaea"
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Label {
|
||||||
z: 10
|
z: 10
|
||||||
text: "Here? No, not here."
|
text: mini ? "Empty" : "Here? No, not here."
|
||||||
color: "#424242"
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: listView.count === 0
|
visible: listView.count === 0
|
||||||
}
|
}
|
||||||
|
@ -94,53 +179,15 @@ Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
model: listModel
|
|
||||||
|
|
||||||
highlight: Rectangle {
|
highlight: Rectangle {
|
||||||
color: Material.accent
|
color: Material.accent
|
||||||
opacity: 0.2
|
opacity: 0.2
|
||||||
}
|
}
|
||||||
|
highlightMoveDuration: 250
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
||||||
|
|
||||||
delegate: ItemDelegate {
|
model: delegateModel
|
||||||
width: parent.width
|
|
||||||
height: 80
|
|
||||||
onClicked: listView.currentIndex = index
|
|
||||||
|
|
||||||
contentItem: Row {
|
|
||||||
width: parent.width - 32
|
|
||||||
height: parent.height - 32
|
|
||||||
spacing: 16
|
|
||||||
|
|
||||||
ImageStatus {
|
|
||||||
width: parent.height
|
|
||||||
height: parent.height
|
|
||||||
source: avatar == "" ? "qrc:/asset/img/avatar.png" : "image://mxc/" + avatar
|
|
||||||
opaqueBackground: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width - parent.height - parent.spacing
|
|
||||||
height: parent.height
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: name
|
|
||||||
color: "#424242"
|
|
||||||
font.pointSize: 16
|
|
||||||
elide: Text.ElideRight
|
|
||||||
wrapMode: Text.NoWrap
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: value
|
|
||||||
color: "#424242"
|
|
||||||
elide: Text.ElideRight
|
|
||||||
wrapMode: Text.NoWrap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,37 @@ import QtQuick.Controls 2.3
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.3
|
||||||
import QtQuick.Controls.Material 2.3
|
import QtQuick.Controls.Material 2.3
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
|
import Matrique 0.1
|
||||||
import "qrc:/qml/component"
|
import "qrc:/qml/component"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property int roomIndex
|
id: item
|
||||||
|
property var currentRoom
|
||||||
|
|
||||||
|
Pane {
|
||||||
|
anchors.fill: parent
|
||||||
|
padding: 0
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: currentRoom == null
|
||||||
|
Pane {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
z: 10
|
||||||
|
text: "Please choose a room."
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
|
visible: currentRoom != null
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
z: 10
|
z: 10
|
||||||
padding: 16
|
padding: 16
|
||||||
|
@ -20,37 +42,89 @@ Item {
|
||||||
Layout.preferredHeight: 80
|
Layout.preferredHeight: 80
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 16
|
spacing: 16
|
||||||
|
|
||||||
ImageStatus {
|
ImageStatus {
|
||||||
width: parent.height
|
Layout.preferredWidth: parent.height
|
||||||
height: parent.height
|
Layout.fillHeight: true
|
||||||
source: "qrc:/asset/img/avatar.png"
|
source: "qrc:/asset/img/avatar.png"
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
ColumnLayout {
|
||||||
height: parent.height
|
Layout.fillWidth: true
|
||||||
Text {
|
Layout.fillHeight: true
|
||||||
text: "Astolfo"
|
|
||||||
font.pointSize: 18
|
Label {
|
||||||
color: "#424242"
|
Layout.fillWidth: true
|
||||||
|
text: currentRoom != null ? currentRoom.name : ""
|
||||||
|
font.pointSize: 16
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.NoWrap
|
||||||
}
|
}
|
||||||
Text {
|
|
||||||
text: "Rider of Black"
|
Label {
|
||||||
color: "#424242"
|
Layout.fillWidth: true
|
||||||
|
text: currentRoom != null ? currentRoom.topic : ""
|
||||||
|
elide: Text.ElideRight
|
||||||
|
wrapMode: Text.NoWrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Pane {
|
ListView {
|
||||||
|
id: messageListView
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
Layout.leftMargin: 16
|
||||||
|
Layout.rightMargin: 16
|
||||||
|
displayMarginBeginning: 40
|
||||||
|
displayMarginEnd: 40
|
||||||
|
verticalLayoutDirection: ListView.BottomToTop
|
||||||
|
spacing: 12
|
||||||
|
// model: MessageEventModel{ currentRoom: item.currentRoom }
|
||||||
|
model: 10
|
||||||
|
delegate: Row {
|
||||||
|
readonly property bool sentByMe: index % 2 == 0
|
||||||
|
|
||||||
|
id: messageRow
|
||||||
|
|
||||||
|
height: 40
|
||||||
|
anchors.right: sentByMe ? parent.right : undefined
|
||||||
|
spacing: 6
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: avatar
|
||||||
|
width: height
|
||||||
|
height: parent.height
|
||||||
|
color: "grey"
|
||||||
|
visible: !sentByMe
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: Math.min(messageText.implicitWidth + 24,
|
||||||
|
messageListView.width - (!sentByMe ? avatar.width + messageRow.spacing : 0))
|
||||||
|
height: parent.height
|
||||||
|
color: sentByMe ? "lightgrey" : Material.accent
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: messageText
|
||||||
|
text: index
|
||||||
|
color: sentByMe ? "black" : "white"
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 12
|
||||||
|
wrapMode: Label.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBar { /*anchors.left: messageListView.right*/ }
|
||||||
}
|
}
|
||||||
|
|
||||||
Pane {
|
Pane {
|
||||||
|
@ -68,14 +142,7 @@ Item {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue226" }
|
||||||
text: "\ue226"
|
|
||||||
// color: "#424242"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
|
@ -85,9 +152,10 @@ Item {
|
||||||
leftPadding: 16
|
leftPadding: 16
|
||||||
topPadding: 0
|
topPadding: 0
|
||||||
bottomPadding: 0
|
bottomPadding: 0
|
||||||
|
selectByMouse: true
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,32 +163,12 @@ Item {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue24e" }
|
||||||
text: "\ue24e"
|
|
||||||
// color: parent.pressed ? Material.accent : "#424242"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "#eaeaea"
|
color: Material.theme == Material.Light ? "#eaeaea" : "#242424"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemDelegate {
|
|
||||||
Layout.preferredWidth: height
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
contentItem: Text {
|
|
||||||
text: "\ue163"
|
|
||||||
// color: "#424242"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
209
qml/main.qml
209
qml/main.qml
|
@ -1,65 +1,128 @@
|
||||||
import QtQuick 2.10
|
import QtQuick 2.11
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.4
|
||||||
import QtQuick.Layouts 1.3
|
import QtQuick.Layouts 1.4
|
||||||
import QtQuick.Controls.Material 2.2
|
import QtQuick.Controls.Material 2.4
|
||||||
import QtGraphicalEffects 1.0
|
import QtGraphicalEffects 1.0
|
||||||
import Qt.labs.settings 1.0
|
import Qt.labs.settings 1.0
|
||||||
|
import Qt.labs.platform 1.0 as Platform
|
||||||
import "qrc:/qml/component"
|
|
||||||
import "qrc:/qml/form"
|
|
||||||
|
|
||||||
import Matrique 0.1
|
import Matrique 0.1
|
||||||
|
|
||||||
|
import "component"
|
||||||
|
import "form"
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: window
|
id: window
|
||||||
visible: true
|
visible: true
|
||||||
width: 960
|
width: 960
|
||||||
height: 640
|
height: 640
|
||||||
|
minimumWidth: 320
|
||||||
|
minimumHeight: 320
|
||||||
title: qsTr("Matrique")
|
title: qsTr("Matrique")
|
||||||
Material.theme: settingPage.theme ? Material.Dark : Material.Light
|
|
||||||
|
|
||||||
Controller {
|
|
||||||
id: matrixController
|
|
||||||
connection: m_connection
|
|
||||||
}
|
|
||||||
|
|
||||||
RoomListModel {
|
|
||||||
id: roomListModel
|
|
||||||
connection: m_connection
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings {
|
|
||||||
id: settings
|
|
||||||
|
|
||||||
property alias userID: matrixController.userID
|
|
||||||
property alias token: matrixController.token
|
|
||||||
}
|
|
||||||
|
|
||||||
FontLoader { id: materialFont; source: "qrc:/asset/font/material.ttf" }
|
FontLoader { id: materialFont; source: "qrc:/asset/font/material.ttf" }
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
id: setting
|
||||||
|
property alias homeserver: matriqueController.homeserver
|
||||||
|
property alias userID: matriqueController.userID
|
||||||
|
property alias token: matriqueController.token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform.SystemTrayIcon {
|
||||||
|
// visible: true
|
||||||
|
// iconSource: "qrc:/asset/img/icon.png"
|
||||||
|
|
||||||
|
// onActivated: {
|
||||||
|
// window.show()
|
||||||
|
// window.raise()
|
||||||
|
// window.requestActivate()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
Controller {
|
||||||
|
id: matriqueController
|
||||||
|
onErrorOccured: {
|
||||||
|
errorDialog.text = err;
|
||||||
|
errorDialog.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
property bool busy: matriqueController.busy
|
||||||
|
|
||||||
|
id: busyPopup
|
||||||
|
|
||||||
|
x: (window.width - width) / 2
|
||||||
|
y: (window.height - height) / 2
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||||
|
|
||||||
|
BusyIndicator { running: true }
|
||||||
|
|
||||||
|
onBusyChanged: {
|
||||||
|
if(busyPopup.busy) { busyPopup.open(); }
|
||||||
|
else { busyPopup.close(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
property alias text: errorLabel.text
|
||||||
|
|
||||||
|
id: errorDialog
|
||||||
|
width: 360
|
||||||
|
modal: true
|
||||||
|
title: "ERROR"
|
||||||
|
|
||||||
|
x: (window.width - width) / 2
|
||||||
|
y: (window.height - height) / 2
|
||||||
|
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: errorLabel
|
||||||
|
width: parent.width
|
||||||
|
text: "Label"
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: loginPage
|
||||||
|
|
||||||
|
Login { controller: matriqueController }
|
||||||
|
}
|
||||||
|
|
||||||
|
Room {
|
||||||
|
id: roomPage
|
||||||
|
connection: matriqueController.connection
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
SideNav {
|
SideNav {
|
||||||
id: sideNav
|
id: sideNav
|
||||||
width: 80
|
Layout.preferredWidth: 80
|
||||||
height: window.height
|
Layout.fillHeight: true
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
SideNavButton {
|
SideNavButton {
|
||||||
|
id: statusNavButton
|
||||||
contentItem: ImageStatus {
|
contentItem: ImageStatus {
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
height: parent.width
|
anchors.margins: 15
|
||||||
|
|
||||||
source: "qrc:/asset/img/avatar.png"
|
source: "qrc:/asset/img/avatar.png"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
statusIndicator: true
|
|
||||||
opaqueBackground: false
|
opaqueBackground: false
|
||||||
}
|
}
|
||||||
|
|
||||||
page: Room {
|
page: roomPage
|
||||||
id: roomPage
|
|
||||||
roomListModel: roomListModel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -68,62 +131,13 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
SideNavButton {
|
SideNavButton {
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue8b8"; color: "white" }
|
||||||
text: "\ue853"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
page: Login {
|
onClicked: matriqueController.logout()
|
||||||
id: loginPage
|
|
||||||
controller: matrixController
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SideNavButton {
|
SideNavButton {
|
||||||
contentItem: Text {
|
contentItem: MaterialIcon { icon: "\ue879"; color: "white" }
|
||||||
text: "\ue5d2"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
page: Contact {
|
|
||||||
id: contactPage
|
|
||||||
contactListModel: roomListModel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SideNavButton {
|
|
||||||
contentItem: Text {
|
|
||||||
text: "\ue8b8"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
page: Setting {
|
|
||||||
id: settingPage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SideNavButton {
|
|
||||||
contentItem: Text {
|
|
||||||
text: "\ue879"
|
|
||||||
font.pointSize: 16
|
|
||||||
font.family: materialFont.name
|
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: Qt.quit()
|
onClicked: Qt.quit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,8 +145,23 @@ ApplicationWindow {
|
||||||
|
|
||||||
StackView {
|
StackView {
|
||||||
id: stackView
|
id: stackView
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: sideNav.width
|
|
||||||
initialItem: roomPage
|
initialItem: roomPage
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
imageProvider.setConnection(matriqueController.connection)
|
||||||
|
imageProvider.connection = matriqueController.connection
|
||||||
|
|
||||||
|
console.log(matriqueController.homeserver, matriqueController.userID, matriqueController.token)
|
||||||
|
if (matriqueController.userID != "" && matriqueController.token != "") {
|
||||||
|
console.log("Perform auto-login.");
|
||||||
|
matriqueController.login();
|
||||||
|
} else {
|
||||||
|
stackView.replace(loginPage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
5
res.qrc
5
res.qrc
|
@ -6,7 +6,6 @@
|
||||||
<file>asset/font/material.ttf</file>
|
<file>asset/font/material.ttf</file>
|
||||||
<file>qml/Login.qml</file>
|
<file>qml/Login.qml</file>
|
||||||
<file>qml/main.qml</file>
|
<file>qml/main.qml</file>
|
||||||
<file>qml/Setting.qml</file>
|
|
||||||
<file>qml/component/ButtonDelegate.qml</file>
|
<file>qml/component/ButtonDelegate.qml</file>
|
||||||
<file>qml/component/ImageStatus.qml</file>
|
<file>qml/component/ImageStatus.qml</file>
|
||||||
<file>qml/component/SideNav.qml</file>
|
<file>qml/component/SideNav.qml</file>
|
||||||
|
@ -14,8 +13,8 @@
|
||||||
<file>qml/Room.qml</file>
|
<file>qml/Room.qml</file>
|
||||||
<file>qml/form/DetailForm.qml</file>
|
<file>qml/form/DetailForm.qml</file>
|
||||||
<file>qml/form/ListForm.qml</file>
|
<file>qml/form/ListForm.qml</file>
|
||||||
<file>qml/Contact.qml</file>
|
|
||||||
<file>qml/component/ChatRoom.qml</file>
|
|
||||||
<file>qml/component/SideNavButton.qml</file>
|
<file>qml/component/SideNavButton.qml</file>
|
||||||
|
<file>qml/component/MaterialIcon.qml</file>
|
||||||
|
<file>asset/img/icon.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Loading…
Reference in New Issue