diff --git a/main.cpp b/main.cpp index f923d86d8..60538ea77 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include +#include "room.h" #include "matrix/controller.h" #include "matrix/roomlistmodel.h" #include "matrix/imageprovider.h" @@ -19,11 +20,13 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); // Enable this if you need proxy. - QNetworkProxy proxy; - proxy.setType(QNetworkProxy::HttpProxy); - proxy.setHostName("localhost"); - proxy.setPort(1082); - QNetworkProxy::setApplicationProxy(proxy); +// QNetworkProxy proxy; +// proxy.setType(QNetworkProxy::HttpProxy); +// proxy.setHostName("localhost"); +// proxy.setPort(1082); +// QNetworkProxy::setApplicationProxy(proxy); + + qmlRegisterType(); qRegisterMetaType ("Room*"); qmlRegisterType("Matrique", 0, 1, "Controller"); qmlRegisterType("Matrique", 0, 1, "RoomListModel"); @@ -31,13 +34,12 @@ int main(int argc, char *argv[]) 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.rootContext()->setContextProperty("imageProvider", m_provider->getConnection()); 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 01f9a44b9..228330d84 100644 --- a/matrique.pro +++ b/matrique.pro @@ -18,8 +18,7 @@ SOURCES += main.cpp \ matrix/controller.cpp \ matrix/roomlistmodel.cpp \ matrix/imageprovider.cpp \ - matrix/messageeventmodel.cpp \ - matrix/matriqueroom.cpp + matrix/messageeventmodel.cpp RESOURCES += \ res.qrc @@ -53,5 +52,4 @@ HEADERS += \ matrix/controller.h \ matrix/roomlistmodel.h \ matrix/imageprovider.h \ - matrix/messageeventmodel.h \ - matrix/matriqueroom.h + matrix/messageeventmodel.h diff --git a/matrix/controller.cpp b/matrix/controller.cpp index 50bd3c70a..f48d4457c 100644 --- a/matrix/controller.cpp +++ b/matrix/controller.cpp @@ -3,51 +3,52 @@ #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() { } -void Controller::login(QString home, QString user, QString pass) { - if(!isLogin) { - if(home.isEmpty()) home = "matrix.org"; - +void Controller::login() { + if (!isLogin) { qDebug() << "UserID:" << userID; 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() << "Pass:" << pass; - if(!userID.isEmpty() && !token.isEmpty()) { - qDebug() << "Using token."; - m_connection->connectWithToken(userID, token, ""); - } else if(!user.isEmpty() && !pass.isEmpty()) { + if(!user.isEmpty() && !pass.isEmpty()) { qDebug() << "Using given credential."; - m_connection->connectToServer("@"+user+":"+home, pass, ""); + m_connection->setHomeserver(QUrl(serverAddr)); + m_connection->connectToServer(user, pass, ""); } } else { 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() { - userID = ""; - token = ""; + qDebug() << "Logging out."; + setUserID(""); + setToken(""); setIsLogin(false); } void Controller::connected() { + qDebug() << "Logged in."; + setHomeserver(m_connection->homeserver().toString()); setUserID(m_connection->userId()); setToken(m_connection->accessToken()); m_connection->loadState(); diff --git a/matrix/controller.h b/matrix/controller.h index a1da594f2..325894921 100644 --- a/matrix/controller.h +++ b/matrix/controller.h @@ -2,9 +2,7 @@ #define CONTROLLER_H #include - #include "libqmatrixclient/connection.h" - #include "roomlistmodel.h" namespace QMatrixClient { @@ -15,25 +13,27 @@ class Controller : public QObject { 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(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY homeserverChanged) Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged) Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged) + Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged) public: explicit Controller(QObject *parent = nullptr); ~Controller(); // 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(); // All the non-Q_INVOKABLE functions. // All the Q_PROPERTYs. - QMatrixClient::Connection* m_connection; + QMatrixClient::Connection* m_connection = new QMatrixClient::Connection(); QMatrixClient::Connection* getConnection() { return m_connection; } - void setConnection(QMatrixClient::Connection* conn); bool isLogin = false; 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: void connected(); void resync(); @@ -72,7 +90,9 @@ class Controller : public QObject void isLoginChanged(); void userIDChanged(); void tokenChanged(); - void homeServerChanged(); + void homeserverChanged(); + void busyChanged(); + void errorOccured(); public slots: }; diff --git a/matrix/imageprovider.cpp b/matrix/imageprovider.cpp index 350a014cb..9459fea45 100644 --- a/matrix/imageprovider.cpp +++ b/matrix/imageprovider.cpp @@ -10,13 +10,22 @@ using QMatrixClient::MediaThumbnailJob; -ImageProvider::ImageProvider(QObject *parent) +ImageProviderConnection::ImageProviderConnection(QObject* parent) : QObject(parent) { + +} + +ImageProviderConnection::~ImageProviderConnection() { + +} + +ImageProvider::ImageProvider(QObject* parent) : QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading) { #if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) qRegisterMetaType(); #endif + m_connection = new ImageProviderConnection(); } QImage ImageProvider::requestImage(const QString& id, @@ -34,9 +43,10 @@ QImage ImageProvider::requestImage(const QString& id, 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); }, + [=] { return m_connection->getConnection()->getThumbnail(mxcUri, requestedSize); }, Qt::BlockingQueuedConnection, &job); #else QMetaObject::invokeMethod(m_connection, "getThumbnail", @@ -64,9 +74,3 @@ QImage ImageProvider::requestImage(const QString& id, 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 index 78cb179fa..ef5babe7d 100644 --- a/matrix/imageprovider.h +++ b/matrix/imageprovider.h @@ -3,26 +3,47 @@ #include #include +#include -namespace QMatrixClient { - class Connection; -} +#include "libqmatrixclient/connection.h" + +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 { public: - explicit ImageProvider(QObject *parent = nullptr); + 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); + ImageProviderConnection* getConnection() { return m_connection; } + private: - QMatrixClient::Connection* m_connection; QReadWriteLock m_lock; + ImageProviderConnection* m_connection; }; #endif // IMAGEPROVIDER_H diff --git a/matrix/messageeventmodel.cpp b/matrix/messageeventmodel.cpp index 522b77d39..a2f740cff 100644 --- a/matrix/messageeventmodel.cpp +++ b/matrix/messageeventmodel.cpp @@ -23,7 +23,6 @@ QHash MessageEventModel::roleNames() const roles[AuthorRole] = "author"; roles[ContentRole] = "content"; roles[ContentTypeRole] = "contentType"; - roles[HighlightRole] = "highlight"; roles[ReadMarkerRole] = "readMarker"; roles[SpecialMarksRole] = "marks"; roles[LongOperationRole] = "progressInfo"; @@ -38,7 +37,7 @@ MessageEventModel::MessageEventModel(QObject* parent) qRegisterMetaType(); } -void MessageEventModel::changeRoom(MatriqueRoom* room) +void MessageEventModel::changeRoom(QMatrixClient::Room* room) { if (room == m_currentRoom) return; @@ -114,7 +113,7 @@ inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti) 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(); auto ts = baseIt->event()->timestamp(); @@ -137,7 +136,7 @@ QDateTime MessageEventModel::makeMessageTimestamp(MatriqueRoom::rev_iter_t baseI 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(); 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) return event->id() == lastReadEventId; diff --git a/matrix/messageeventmodel.h b/matrix/messageeventmodel.h index c30acf526..81f2584d8 100644 --- a/matrix/messageeventmodel.h +++ b/matrix/messageeventmodel.h @@ -2,8 +2,7 @@ #define MESSAGEEVENTMODEL_H #include - -#include "matriqueroom.h" +#include "room.h" class MessageEventModel: public QAbstractListModel { @@ -13,7 +12,7 @@ class MessageEventModel: public QAbstractListModel // has to be re-calculated anyway). // XXX: A better way would be to make [Room::]Timeline a list model // 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: enum EventRoles { @@ -25,7 +24,6 @@ class MessageEventModel: public QAbstractListModel AuthorRole, ContentRole, ContentTypeRole, - HighlightRole, ReadMarkerRole, SpecialMarksRole, LongOperationRole, @@ -33,7 +31,7 @@ class MessageEventModel: public QAbstractListModel explicit MessageEventModel(QObject* parent = nullptr); - void changeRoom(MatriqueRoom* room); + void changeRoom(QMatrixClient::Room* room); int rowCount(const QModelIndex& parent = QModelIndex()) 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); private: - MatriqueRoom* m_currentRoom; + QMatrixClient::Room* m_currentRoom; QString lastReadEventId; - QDateTime makeMessageTimestamp(MatriqueRoom::rev_iter_t baseIt) const; - QString makeDateString(MatriqueRoom::rev_iter_t baseIt) const; + QDateTime makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const; + QString makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const; void refreshEventRoles(const QString& eventId, const QVector roles); }; diff --git a/matrix/roomlistmodel.cpp b/matrix/roomlistmodel.cpp index a40ca2787..4622199f8 100644 --- a/matrix/roomlistmodel.cpp +++ b/matrix/roomlistmodel.cpp @@ -1,131 +1,43 @@ #include "roomlistmodel.h" -#include - -#include "matriqueroom.h" -#include "connection.h" -#include "user.h" +#include +#include +#include RoomListModel::RoomListModel(QObject* parent) : QAbstractListModel(parent) -{ } +{ + m_connection = 0; +} + +RoomListModel::~RoomListModel() +{ +} void RoomListModel::setConnection(QMatrixClient::Connection* connection) { - Q_ASSERT(connection); - - using QMatrixClient::Room; beginResetModel(); m_connection = connection; - connect( connection, &QMatrixClient::Connection::loggedOut, - this, [=]{ deleteConnection(connection); } ); - connect( connection, &QMatrixClient::Connection::invitedRoom, - this, &RoomListModel::updateRoom); - connect( connection, &QMatrixClient::Connection::joinedRoom, - 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); + m_rooms.clear(); + connect( connection, &QMatrixClient::Connection::newRoom, this, &RoomListModel::addRoom ); + for( QMatrixClient::Room* room: connection->roomMap().values() ) { + connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged ); + m_rooms.append(room); + } 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(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(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()); - doAddRoom(newRoom); - endInsertRows(); - } -} - -void RoomListModel::deleteRoom(QMatrixClient::Room* room) -{ - auto i = m_rooms.indexOf(static_cast(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(r)) - { - m_rooms.append(room); - connectRoomSignals(room); - } 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 }); }); + beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count()); + connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged ); + m_rooms.append(room); + endInsertRows(); } 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..."; return QVariant(); } - auto room = m_rooms.at(index.row()); - using QMatrixClient::JoinState; - switch (role) + QMatrixClient::Room* room = m_rooms.at(index.row()); + if( role == Qt::DisplayRole ) { - case Qt::DisplayRole: - return room->displayName(); - case Qt::DecorationRole: - { - if(room->avatarUrl().toString() != "") { - qInfo() << "Room avatar:" << 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(); - } - } - case Qt::StatusTipRole: - { - return room->topic(); - } - case Qt::ToolTipRole: - { - int hlCount = room->highlightCount(); - auto result = QStringLiteral("%1
").arg(room->displayName()); - result += tr("Main alias: %1
").arg(room->canonicalAlias()); - result += tr("Members: %1
").arg(room->memberCount()); - if (hlCount > 0) - result += tr("Unread mentions: %1
").arg(hlCount); - result += tr("ID: %1
").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 room->displayName(); } + if( role == Qt::ForegroundRole ) + { + if( room->highlightCount() > 0 ) + return QBrush(QColor("orange")); + return QVariant(); + } + if( role == Qt::DecorationRole ) + { + if(room->avatarUrl().toString() != "") { + return room->avatarUrl(); + } + return QVariant(); + } + if (role == Qt::StatusTipRole ) + { + return room->topic(); + } + 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 RoomListModel::roleNames() const { QHash roles; roles[Qt::DisplayRole] = "name"; roles[Qt::DecorationRole] = "avatar"; - roles[Qt::StatusTipRole] = "value"; + roles[Qt::StatusTipRole] = "topic"; return roles; } - -void RoomListModel::displaynameChanged(MatriqueRoom* room) -{ - refresh(room); -} - -void RoomListModel::unreadMessagesChanged(MatriqueRoom* room) -{ - refresh(room); -} - -void RoomListModel::refresh(MatriqueRoom* room, const QVector& 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); -} diff --git a/matrix/roomlistmodel.h b/matrix/roomlistmodel.h index f2bb6308b..2bcd4172f 100644 --- a/matrix/roomlistmodel.h +++ b/matrix/roomlistmodel.h @@ -2,55 +2,39 @@ #define ROOMLISTMODEL_H #include - -#include "matriqueroom.h" - -namespace QMatrixClient -{ - class Connection; - class Room; -} +#include "room.h" +#include "connection.h" class RoomListModel: public QAbstractListModel { Q_OBJECT - Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection) public: - enum Roles { - HasUnreadRole = Qt::UserRole + 1, - HighlightCountRole, JoinStateRole - }; + RoomListModel(QObject* parent=0); + virtual ~RoomListModel(); - explicit RoomListModel(QObject* parent = nullptr); - - QMatrixClient::Connection* getConnection() { return m_connection; } + QMatrixClient::Connection* getConnection() {return m_connection;} void setConnection(QMatrixClient::Connection* connection); - void deleteConnection(QMatrixClient::Connection* connection); - MatriqueRoom* roomAt(QModelIndex index) const; - QModelIndex indexOf(MatriqueRoom* room) const; + Q_INVOKABLE QMatrixClient::Room* roomAt(int row); + + 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 roleNames() const; - int rowCount(const QModelIndex& parent) const override; private slots: - void displaynameChanged(MatriqueRoom* room); - void unreadMessagesChanged(MatriqueRoom* room); - void refresh(MatriqueRoom* room, const QVector& roles = {}); - - void updateRoom(QMatrixClient::Room* room, - QMatrixClient::Room* prev); - void deleteRoom(QMatrixClient::Room* room); + void namesChanged(QMatrixClient::Room* room); + void unreadMessagesChanged(QMatrixClient::Room* room); + void addRoom(QMatrixClient::Room* room); private: QMatrixClient::Connection* m_connection; - QList m_rooms; + QList m_rooms; - void doAddRoom(QMatrixClient::Room* r); - void connectRoomSignals(MatriqueRoom* room); + signals: + void connectionChanged(); }; #endif // ROOMLISTMODEL_H diff --git a/qml/Contact.qml b/qml/Contact.qml deleted file mode 100644 index 6901d75c7..000000000 --- a/qml/Contact.qml +++ /dev/null @@ -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 - } -} diff --git a/qml/Login.qml b/qml/Login.qml index bae1953d0..d6070671b 100644 --- a/qml/Login.qml +++ b/qml/Login.qml @@ -9,18 +9,6 @@ import "qrc:/qml/component" Page { 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 { anchors.fill: parent @@ -68,29 +56,33 @@ Page { height: parent.height padding: 64 - Column { - id: main_col - spacing: 8 - anchors.fill: parent + ColumnLayout { + id: mainCol + width: parent.width ImageStatus { - width: 96 - height: width + Layout.preferredWidth: 96 + Layout.preferredHeight: 96 + Layout.alignment: Qt.AlignHCenter + source: "qrc:/asset/img/avatar.png" - anchors.horizontalCenter: parent.horizontalCenter } TextField { id: serverField - width: parent.width - height: 48 - placeholderText: "Server" + + Layout.fillWidth: true + leftPadding: 16 topPadding: 0 bottomPadding: 0 + placeholderText: "Server" + background: Rectangle { - color: "#eaeaea" + implicitHeight: 48 + + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" border.color: parent.activeFocus ? Material.accent : "transparent" border.width: 2 } @@ -98,15 +90,19 @@ Page { TextField { id: usernameField - width: parent.width - height: 48 - placeholderText: "Username" + + Layout.fillWidth: true + leftPadding: 16 topPadding: 0 bottomPadding: 0 + placeholderText: "Username" + background: Rectangle { - color: "#eaeaea" + implicitHeight: 48 + + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" border.color: parent.activeFocus ? Material.accent : "transparent" border.width: 2 } @@ -114,15 +110,20 @@ Page { TextField { id: passwordField - width: parent.width - height: 48 - placeholderText: "Password" + + Layout.fillWidth: true + leftPadding: 16 topPadding: 0 bottomPadding: 0 + placeholderText: "Password" + echoMode: TextInput.Password + background: Rectangle { - color: "#eaeaea" + implicitHeight: 48 + + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" border.color: parent.activeFocus ? Material.accent : "transparent" border.width: 2 } @@ -130,20 +131,13 @@ Page { Button { id: loginButton + + Layout.fillWidth: true + text: "LOGIN" highlighted: true - width: parent.width - onClicked: controller.login(homeserver, username, password) - } - - Button { - id: logoutButton - text: "LOGOUT" - flat: true - width: parent.width - - onClicked: controller.logout() + onClicked: controller.loginWithCredentials(serverField.text, usernameField.text, passwordField.text) } } } diff --git a/qml/Room.qml b/qml/Room.qml index 5bf724c25..41d307bec 100644 --- a/qml/Room.qml +++ b/qml/Room.qml @@ -1,24 +1,47 @@ import QtQuick 2.10 import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import Matrique 0.1 import "qrc:/qml/form" -import Matrique 0.1 - Page { - property RoomListModel roomListModel + property alias connection: roomListModel.connection - ListForm { - id: roomListForm - height: parent.height - width: 320 - listModel: roomListModel + id: page + + RoomListModel { + id: roomListModel } - RoomForm { - id: roomForm + RowLayout { anchors.fill: parent - anchors.leftMargin: roomListForm.width - roomIndex: roomListForm.currentIndex + spacing: 0 + + ListForm { + id: roomListForm + + 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 + } + + RoomForm { + id: roomForm + + Layout.fillWidth: true + Layout.fillHeight: true + + currentRoom: roomListForm.currentIndex != -1 ? roomListModel.roomAt(roomListForm.currentIndex) : null + } } } diff --git a/qml/Setting.qml b/qml/Setting.qml deleted file mode 100644 index 308ac8d6b..000000000 --- a/qml/Setting.qml +++ /dev/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 { - - } - } -} diff --git a/qml/component/ChatRoom.qml b/qml/component/ChatRoom.qml deleted file mode 100644 index 8bb038f2e..000000000 --- a/qml/component/ChatRoom.qml +++ /dev/null @@ -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() - } - } -} diff --git a/qml/component/ImageStatus.qml b/qml/component/ImageStatus.qml index 77f216b06..ce9d30f2f 100644 --- a/qml/component/ImageStatus.qml +++ b/qml/component/ImageStatus.qml @@ -1,30 +1,31 @@ -import QtQuick 2.10 -import QtQuick.Controls 2.3 +import QtQuick 2.11 +import QtQuick.Controls 2.4 import QtGraphicalEffects 1.0 Item { - property bool statusIndicator: false property bool opaqueBackground: false property alias source: avatar.source + id: item + Rectangle { - width: parent.width - height: parent.width - radius: parent.width / 2 + width: item.width + height: item.width + radius: item.width / 2 color: "white" visible: opaqueBackground } Image { id: avatar - width: parent.width - height: parent.width + width: item.width + height: item.width mipmap: true layer.enabled: true fillMode: Image.PreserveAspectCrop - sourceSize.width: parent.width - sourceSize.height: parent.width + sourceSize.width: item.width + sourceSize.height: item.width layer.effect: OpacityMask { 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 - } } } diff --git a/qml/component/MaterialIcon.qml b/qml/component/MaterialIcon.qml index bd8745052..d2fcd5867 100644 --- a/qml/component/MaterialIcon.qml +++ b/qml/component/MaterialIcon.qml @@ -1,10 +1,11 @@ import QtQuick 2.10 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.3 Item { property alias icon: iconText.text - property var color: "white" + property var color: Material.theme == Material.Light ? "black" : "white" id: item diff --git a/qml/component/SideNav.qml b/qml/component/SideNav.qml index 105446fab..330f483ba 100644 --- a/qml/component/SideNav.qml +++ b/qml/component/SideNav.qml @@ -3,15 +3,9 @@ import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.3 -Drawer { - property SwipeView swipeView - - interactive: false - position: 1.0 - visible: true - modal: false - - background: Rectangle { +Item { + Rectangle { + anchors.fill: parent color: Material.accent } } diff --git a/qml/component/SideNavButton.qml b/qml/component/SideNavButton.qml index 2e653916d..7a217d2d1 100644 --- a/qml/component/SideNavButton.qml +++ b/qml/component/SideNavButton.qml @@ -4,7 +4,7 @@ import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.3 Item { - property Item page + property var page property alias contentItem: buttonDelegate.contentItem signal clicked diff --git a/qml/form/DetailForm.qml b/qml/form/DetailForm.qml index 75b80b7f9..837f55106 100644 --- a/qml/form/DetailForm.qml +++ b/qml/form/DetailForm.qml @@ -50,28 +50,14 @@ Item { width: parent.height height: parent.height - contentItem: Text { - text: "\ue0b7" - font.pointSize: 16 - font.family: materialFont.name - color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } + contentItem: MaterialIcon { icon: "\ue0b7" } } ItemDelegate { width: parent.height height: parent.height - contentItem: Text { - text: "\ue62e" - font.pointSize: 16 - font.family: materialFont.name - color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } + contentItem: MaterialIcon { icon: "\ue62e" } } } } diff --git a/qml/form/ListForm.qml b/qml/form/ListForm.qml index c6eda8f50..cf84691a9 100644 --- a/qml/form/ListForm.qml +++ b/qml/form/ListForm.qml @@ -1,13 +1,97 @@ -import QtQuick 2.10 -import QtQuick.Controls 2.3 -import QtQuick.Layouts 1.3 +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.11 import QtGraphicalEffects 1.0 import QtQuick.Controls.Material 2.3 +import QtQml.Models 2.3 +import Matrique 0.1 + import "qrc:/qml/component" Item { - property var listModel + property alias listModel: delegateModel.model 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 { anchors.fill: parent @@ -22,10 +106,10 @@ Item { } TextField { - id: serverField + id: searchField width: parent.width height: 36 - leftPadding: 16 + leftPadding: mini ? 4 : 16 topPadding: 0 bottomPadding: 0 anchors.verticalCenter: parent.verticalCenter @@ -34,19 +118,17 @@ Item { Row { anchors.fill: parent - Text { - width: parent.height - height: parent.height - text: "\ue8b6" - font.pointSize: 16 - font.family: materialFont.name + MaterialIcon { + icon: "\ue8b6" color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + + width: mini ? parent.width : parent.height + height: parent.height } Text { height: parent.height + visible: !mini text: "Search" color: "white" font.pointSize: 12 @@ -56,15 +138,19 @@ Item { } Rectangle { - width: serverField.activeFocus || serverField.text != "" ? parent.width : 0 + width: searchField.activeFocus || searchField.text != "" ? parent.width : 0 height: parent.height color: "white" 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 Rectangle { anchors.fill: parent - color: "#eaeaea" + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" } - Text { + Label { z: 10 - text: "Here? No, not here." - color: "#424242" + text: mini ? "Empty" : "Here? No, not here." anchors.centerIn: parent visible: listView.count === 0 } @@ -94,53 +179,15 @@ Item { width: parent.width height: parent.height - model: listModel - highlight: Rectangle { color: Material.accent opacity: 0.2 } + highlightMoveDuration: 250 ScrollBar.vertical: ScrollBar { id: scrollBar } - delegate: ItemDelegate { - 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 - } - } - } - } + model: delegateModel } } } diff --git a/qml/form/RoomForm.qml b/qml/form/RoomForm.qml index 024af630a..4aad0526e 100644 --- a/qml/form/RoomForm.qml +++ b/qml/form/RoomForm.qml @@ -3,123 +3,171 @@ import QtQuick.Controls 2.3 import QtQuick.Layouts 1.3 import QtQuick.Controls.Material 2.3 import QtGraphicalEffects 1.0 +import Matrique 0.1 import "qrc:/qml/component" Item { - property int roomIndex + id: item + property var currentRoom - ColumnLayout { + Pane { anchors.fill: parent - spacing: 0 + padding: 0 - Pane { - z: 10 - padding: 16 - - Layout.fillWidth: true - Layout.preferredHeight: 80 - - background: Rectangle { - color: "#eaeaea" + background: Item { + anchors.fill: parent + visible: currentRoom == null + Pane { + anchors.fill: parent } - Row { - anchors.fill: parent - spacing: 16 - - ImageStatus { - width: parent.height - height: parent.height - source: "qrc:/asset/img/avatar.png" - } - - Column { - height: parent.height - Text { - text: "Astolfo" - font.pointSize: 18 - color: "#424242" - } - Text { - text: "Rider of Black" - color: "#424242" - } - } + Label { + z: 10 + text: "Please choose a room." + anchors.centerIn: parent } } - Pane { - Layout.fillWidth: true - Layout.fillHeight: true - } + ColumnLayout { + anchors.fill: parent + spacing: 0 - Pane { - z: 10 - padding: 16 + visible: currentRoom != null - Layout.fillWidth: true - Layout.preferredHeight: 80 + Pane { + z: 10 + padding: 16 - RowLayout { - anchors.fill: parent - spacing: 0 + Layout.fillWidth: true + Layout.preferredHeight: 80 - ItemDelegate { - Layout.preferredWidth: height - Layout.fillHeight: true + background: Rectangle { + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" + } - contentItem: Text { - text: "\ue226" -// color: "#424242" - font.pointSize: 16 - font.family: materialFont.name - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + RowLayout { + anchors.fill: parent + spacing: 16 + + ImageStatus { + Layout.preferredWidth: parent.height + Layout.fillHeight: true + source: "qrc:/asset/img/avatar.png" + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + + Label { + Layout.fillWidth: true + text: currentRoom != null ? currentRoom.name : "" + font.pointSize: 16 + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + + Label { + Layout.fillWidth: true + text: currentRoom != null ? currentRoom.topic : "" + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + } + } + + ListView { + id: messageListView + + Layout.fillWidth: 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 + } } } - TextField { - Layout.fillWidth: true - Layout.fillHeight: true - placeholderText: "Send a Message" - leftPadding: 16 - topPadding: 0 - bottomPadding: 0 + ScrollBar.vertical: ScrollBar { /*anchors.left: messageListView.right*/ } + } - background: Rectangle { - color: "#eaeaea" - } - } + Pane { + z: 10 + padding: 16 - ItemDelegate { - Layout.preferredWidth: height - Layout.fillHeight: true + Layout.fillWidth: true + Layout.preferredHeight: 80 - contentItem: Text { - text: "\ue24e" -// color: parent.pressed ? Material.accent : "#424242" - font.pointSize: 16 - font.family: materialFont.name - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + RowLayout { + anchors.fill: parent + spacing: 0 + + ItemDelegate { + Layout.preferredWidth: height + Layout.fillHeight: true + + contentItem: MaterialIcon { icon: "\ue226" } } - background: Rectangle { - color: "#eaeaea" + TextField { + Layout.fillWidth: true + Layout.fillHeight: true + placeholderText: "Send a Message" + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + selectByMouse: true + + background: Rectangle { + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" + } } - } - ItemDelegate { - Layout.preferredWidth: height - Layout.fillHeight: true + 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 + contentItem: MaterialIcon { icon: "\ue24e" } + + background: Rectangle { + color: Material.theme == Material.Light ? "#eaeaea" : "#242424" + } } } } diff --git a/qml/main.qml b/qml/main.qml index c71012112..2b7443b5f 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -1,138 +1,167 @@ -import QtQuick 2.10 -import QtQuick.Controls 2.3 -import QtQuick.Layouts 1.3 -import QtQuick.Controls.Material 2.2 +import QtQuick 2.11 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.4 +import QtQuick.Controls.Material 2.4 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 - -import "qrc:/qml/component" -import "qrc:/qml/form" - +import Qt.labs.platform 1.0 as Platform import Matrique 0.1 +import "component" +import "form" + ApplicationWindow { id: window visible: true width: 960 height: 640 + minimumWidth: 320 + minimumHeight: 320 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" } - SideNav { - id: sideNav - width: 80 - height: window.height + Settings { + id: setting + property alias homeserver: matriqueController.homeserver + property alias userID: matriqueController.userID + property alias token: matriqueController.token + } - ColumnLayout { - anchors.fill: parent - spacing: 0 +// Platform.SystemTrayIcon { +// visible: true +// iconSource: "qrc:/asset/img/icon.png" - SideNavButton { - contentItem: ImageStatus { - width: parent.width - height: parent.width - source: "qrc:/asset/img/avatar.png" - anchors.horizontalCenter: parent.horizontalCenter - statusIndicator: true - opaqueBackground: false - } +// onActivated: { +// window.show() +// window.raise() +// window.requestActivate() +// } +// } - page: Room { - id: roomPage - roomListModel: roomListModel - } - } - - Rectangle { - color: "transparent" - Layout.fillHeight: true - } - - SideNavButton { - contentItem: Text { - text: "\ue853" - font.pointSize: 16 - font.family: materialFont.name - color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - - page: Login { - id: loginPage - controller: matrixController - } - } - - SideNavButton { - contentItem: Text { - 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() - } + Controller { + id: matriqueController + onErrorOccured: { + errorDialog.text = err; + errorDialog.open(); } } - StackView { - id: stackView + 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 - anchors.leftMargin: sideNav.width - initialItem: roomPage + spacing: 0 + + SideNav { + id: sideNav + Layout.preferredWidth: 80 + Layout.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + SideNavButton { + id: statusNavButton + contentItem: ImageStatus { + anchors.fill: parent + anchors.margins: 15 + + source: "qrc:/asset/img/avatar.png" + opaqueBackground: false + } + + page: roomPage + } + + Rectangle { + color: "transparent" + Layout.fillHeight: true + } + + SideNavButton { + contentItem: MaterialIcon { icon: "\ue8b8"; color: "white" } + + onClicked: matriqueController.logout() + } + + SideNavButton { + contentItem: MaterialIcon { icon: "\ue879"; color: "white" } + onClicked: Qt.quit() + } + } + } + + StackView { + id: stackView + 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); + } } } diff --git a/res.qrc b/res.qrc index 7b6d63968..1cd0ac50d 100644 --- a/res.qrc +++ b/res.qrc @@ -6,7 +6,6 @@ asset/font/material.ttf qml/Login.qml qml/main.qml - qml/Setting.qml qml/component/ButtonDelegate.qml qml/component/ImageStatus.qml qml/component/SideNav.qml @@ -14,8 +13,8 @@ qml/Room.qml qml/form/DetailForm.qml qml/form/ListForm.qml - qml/Contact.qml - qml/component/ChatRoom.qml qml/component/SideNavButton.qml + qml/component/MaterialIcon.qml + asset/img/icon.png