commit c2f01ec1c4de8f4df0fd59415c008f4625102cbe Author: Black Hat Date: Fri Feb 23 22:39:14 2018 +0800 First commit. diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..1cf9b3180 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "matrix/libqmatrixclient"] + path = matrix/libqmatrixclient + url = https://github.com/QMatrixClient/libqmatrixclient diff --git a/asset/font/material.ttf b/asset/font/material.ttf new file mode 100644 index 000000000..7015564ad Binary files /dev/null and b/asset/font/material.ttf differ diff --git a/asset/img/avatar.png b/asset/img/avatar.png new file mode 100644 index 000000000..6d355bbb3 Binary files /dev/null and b/asset/img/avatar.png differ diff --git a/asset/img/background.jpg b/asset/img/background.jpg new file mode 100644 index 000000000..de559fd43 Binary files /dev/null and b/asset/img/background.jpg differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..cc2fd4a35 --- /dev/null +++ b/main.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include "connection.h" +#include "room.h" +#include "user.h" +#include "jobs/syncjob.h" +#include "settings.h" +using namespace QMatrixClient; + +// https://forum.qt.io/topic/57809 +Q_DECLARE_METATYPE(SyncJob*) +Q_DECLARE_METATYPE(Room*) + +int main(int argc, char *argv[]) +{ +#if defined(Q_OS_WIN) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif + + QGuiApplication app(argc, argv); + + qmlRegisterType(); qRegisterMetaType ("SyncJob*"); + qmlRegisterType(); qRegisterMetaType ("Room*"); + qmlRegisterType(); qRegisterMetaType ("User*"); + + qmlRegisterType ("Matrique", 0, 1, "Connection"); +// qmlRegisterType ("Matrique", 0, 1, "MessageEventModel"); +// qmlRegisterType ("Matrique", 0, 1, "RoomListModel"); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/matrique.pro b/matrique.pro new file mode 100644 index 000000000..7ab4e1c61 --- /dev/null +++ b/matrique.pro @@ -0,0 +1,45 @@ +QT += quick +CONFIG += c++14 + +include(matrix/libqmatrixclient/libqmatrixclient.pri) + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += main.cpp + +RESOURCES += \ + res.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + ChatForm.qml \ + LoginForm.qml \ + main.qml \ + Home.qml \ + Login.qml \ + ImageStatus.qml \ + ButtonDelegate.qml \ + SideNav.qml \ + ContactListForm.qml \ + ContactDetailForm.qml \ + Contact.qml \ + Setting.qml diff --git a/matrix/libqmatrixclient b/matrix/libqmatrixclient new file mode 160000 index 000000000..b7c1ff183 --- /dev/null +++ b/matrix/libqmatrixclient @@ -0,0 +1 @@ +Subproject commit b7c1ff183384738f170d53128c684681cb34f3b7 diff --git a/qml/Contact.qml b/qml/Contact.qml new file mode 100644 index 000000000..efcbe0104 --- /dev/null +++ b/qml/Contact.qml @@ -0,0 +1,17 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import "qrc:/qml/form" + +Page { + ContactListForm { + id: contactListForm + height: parent.height + width: 320 + } + + ContactDetailForm { + id: contactDetailForm + anchors.fill: parent + anchors.leftMargin: contactListForm.width + } +} diff --git a/qml/Home.qml b/qml/Home.qml new file mode 100644 index 000000000..d22562d88 --- /dev/null +++ b/qml/Home.qml @@ -0,0 +1,17 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import "qrc:/qml/form" + +Page { + ContactListForm { + id: contactListForm + height: parent.height + width: 320 + } + + ChatForm { + id: chatForm + anchors.fill: parent + anchors.leftMargin: contactListForm.width + } +} diff --git a/qml/Login.qml b/qml/Login.qml new file mode 100644 index 000000000..2810a67de --- /dev/null +++ b/qml/Login.qml @@ -0,0 +1,130 @@ +import QtQuick 2.10 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls 2.3 +import QtQuick.Controls.Material 2.3 +import "qrc:/qml/component" + +Page { + property var window + property alias username: usernameField.text + property alias password: passwordField.text + + Row { + anchors.fill: parent + + Pane { + width: parent.width / 2 + height: parent.height + + background: Item { + Image { + id: background + anchors.fill: parent + source: "qrc:/asset/img/background.jpg" + fillMode: Image.PreserveAspectCrop + } + + ColorOverlay { + anchors.fill: background + source: background + color: "#b000796b" + } + } + + Column { + x: 32 + anchors.verticalCenter: parent.verticalCenter + + Label { + text: "MATRIX LOGIN." + font.pointSize: 36 + font.bold: true + color: "white" + } + + Label { + text: "A NEW METHOD OF MESSAGING" + font.pointSize: 12 + color: "white" + } + } + } + + Pane { + width: parent.width / 2 + height: parent.height + padding: 64 + + Column { + id: main_col + spacing: 8 + anchors.fill: parent + + ImageStatus { + width: 96 + height: width + source: "qrc:/asset/img/avatar.png" + anchors.horizontalCenter: parent.horizontalCenter + } + + TextField { + id: serverField + width: parent.width + height: 48 + placeholderText: "Server" + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + + background: Rectangle { + color: "#eaeaea" + border.color: parent.activeFocus ? Material.accent : "transparent" + border.width: 2 + } + } + + TextField { + id: usernameField + width: parent.width + height: 48 + placeholderText: "Username" + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + + background: Rectangle { + color: "#eaeaea" + border.color: parent.activeFocus ? Material.accent : "transparent" + border.width: 2 + } + } + + TextField { + id: passwordField + width: parent.width + height: 48 + placeholderText: "Password" + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + + background: Rectangle { + color: "#eaeaea" + border.color: parent.activeFocus ? Material.accent : "transparent" + border.width: 2 + } + } + + Button { + id: loginButton + text: "LOGIN" + highlighted: true + width: parent.width + + onClicked: window.login() + } + } + } + } +} diff --git a/qml/Setting.qml b/qml/Setting.qml new file mode 100644 index 000000000..c3a6fda3d --- /dev/null +++ b/qml/Setting.qml @@ -0,0 +1,40 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 + +Page { + TabBar { + id: settingBar + width: parent.width + z: 10 + currentIndex: settingBar.currentIndex + + TabButton { + text: qsTr("Overview") + } + TabButton { + text: qsTr("Network") + } + TabButton { + text: qsTr("Sync") + } + } + + SwipeView { + id: settingSwipe + + currentIndex: settingBar.currentIndex + anchors.fill: parent + + Page { + + } + + Page { + + } + + Page { + + } + } +} diff --git a/qml/component/ButtonDelegate.qml b/qml/component/ButtonDelegate.qml new file mode 100644 index 000000000..ae766de50 --- /dev/null +++ b/qml/component/ButtonDelegate.qml @@ -0,0 +1,36 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.3 + +Item { + property int index + property alias contentItem: itemDelegate.contentItem + signal clicked + + id: buttonDelegate + + Layout.fillWidth: true + Layout.preferredHeight: width + + Rectangle { + width: swipeView.currentIndex === index ? parent.width : 0 + height: parent.height + anchors.bottom: itemDelegate.bottom + color: Qt.lighter(Material.accent) + + Behavior on width { + PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 } + } + } + + ItemDelegate { + id: itemDelegate + anchors.fill: parent + + onClicked: { + swipeView.currentIndex = index + buttonDelegate.clicked() + } + } +} diff --git a/qml/component/ImageStatus.qml b/qml/component/ImageStatus.qml new file mode 100644 index 000000000..d38cb5a96 --- /dev/null +++ b/qml/component/ImageStatus.qml @@ -0,0 +1,34 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtGraphicalEffects 1.0 + +Image { + id: avatar + + mipmap: true + layer.enabled: true + fillMode: Image.PreserveAspectCrop + + layer.effect: OpacityMask { + maskSource: Item { + width: avatar.width + height: avatar.width + Rectangle { + anchors.centerIn: parent + width: avatar.width + height: avatar.width + radius: avatar.width / 2 + } + } + } + + Rectangle { + id: circle + width: avatar.width + height: avatar.width + radius: avatar.width / 2 + color: "transparent" + border.color: "#4caf50" + border.width: 4 + } +} diff --git a/qml/component/SideNav.qml b/qml/component/SideNav.qml new file mode 100644 index 000000000..105446fab --- /dev/null +++ b/qml/component/SideNav.qml @@ -0,0 +1,17 @@ +import QtQuick 2.10 +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 { + color: Material.accent + } +} diff --git a/qml/form/ChatForm.qml b/qml/form/ChatForm.qml new file mode 100644 index 000000000..9b73a59c0 --- /dev/null +++ b/qml/form/ChatForm.qml @@ -0,0 +1,125 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.3 +import QtGraphicalEffects 1.0 +import "qrc:/qml/component" + +Item { + ColumnLayout { + anchors.fill: parent + + Pane { + z: 10 + padding: 16 + + Layout.fillWidth: true + Layout.preferredHeight: 80 + + background: Rectangle { + color: "#eaeaea" + } + + 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" + } + } + } + } + + Pane { + Layout.fillWidth: true + Layout.fillHeight: true + } + + Pane { + z: 10 + padding: 16 + + Layout.fillWidth: true + Layout.preferredHeight: 80 + + RowLayout { + anchors.fill: parent + spacing: 0 + + ItemDelegate { + Layout.preferredWidth: height + Layout.fillHeight: true + + contentItem: Text { + text: "\ue226" + color: "#424242" + font.pointSize: 16 + font.family: materialFont.name + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + TextField { + Layout.fillWidth: true + Layout.fillHeight: true + placeholderText: "Send a Message" + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + + background: Rectangle { + color: "#eaeaea" + } + } + + ItemDelegate { + Layout.preferredWidth: height + Layout.fillHeight: true + + contentItem: Text { + text: "\ue24e" + color: parent.pressed ? Material.accent : "#424242" + font.pointSize: 16 + font.family: materialFont.name + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + background: Rectangle { + color: "#eaeaea" + } + } + + 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 + } + } + } + } + } +} diff --git a/qml/form/ContactDetailForm.qml b/qml/form/ContactDetailForm.qml new file mode 100644 index 000000000..6e8b99721 --- /dev/null +++ b/qml/form/ContactDetailForm.qml @@ -0,0 +1,112 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.3 +import "qrc:/qml/component" + +Item { + ColumnLayout { + anchors.fill: parent + + Pane { + Layout.fillWidth: true + Layout.preferredHeight: 250 + padding: 32 + + background: Rectangle { + color: Material.accent + } + + Column { + anchors.fill: parent + + ImageStatus { + z: 10 + width: 96 + height: width + source: "qrc:/asset/img/avatar.png" + anchors.horizontalCenter: parent.horizontalCenter + } + + Text { + text: "Astolfo" + color: "white" + font.pointSize: 28 + anchors.horizontalCenter: parent.horizontalCenter + } + + Text { + text: "Rider of Black" + color: "#cdcdcd" + font.pointSize: 12 + anchors.horizontalCenter: parent.horizontalCenter + } + + Row { + height: 48 + anchors.horizontalCenter: parent.horizontalCenter + ItemDelegate { + 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 + } + } + + 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 + } + } + } + } + } + + Pane { + Layout.fillWidth: true + Layout.fillHeight: true + + leftPadding: 96 + rightPadding: 96 + + GridLayout { + width: parent.width + columns: 2 + flow: GridLayout.LeftToRight + anchors.horizontalCenter: parent.horizontalCenter + columnSpacing: 32 + + Text { + text: "Matrix ID" + } + + Text { + Layout.fillWidth: true + text: "Welcome" + } + + Text { + text: "Status" + } + + Text { + text: "Overline" + } + } + } + } +} diff --git a/qml/form/ContactListForm.qml b/qml/form/ContactListForm.qml new file mode 100644 index 000000000..887b6f865 --- /dev/null +++ b/qml/form/ContactListForm.qml @@ -0,0 +1,174 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 +import QtQuick.Controls.Material 2.3 +import "qrc:/qml/component" + +Item { + ColumnLayout { + anchors.fill: parent + spacing: 0 + + Pane { + z: 10 + Layout.fillWidth: true + Layout.preferredHeight: 80 + background: Rectangle { + color: Qt.tint(Material.accent, "#20FFFFFF") + } + + TextField { + id: serverField + width: parent.width + height: 36 + leftPadding: 16 + topPadding: 0 + bottomPadding: 0 + anchors.verticalCenter: parent.verticalCenter + + background: Item { + Row { + anchors.fill: parent + + Text { + width: parent.height + height: parent.height + text: "\ue8b6" + font.pointSize: 16 + font.family: materialFont.name + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + Text { + height: parent.height + text: "Search" + color: "white" + font.pointSize: 12 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + Rectangle { + width: serverField.activeFocus || serverField.text != "" ? parent.width : 0 + height: parent.height + color: "white" + + Behavior on width { + PropertyAnimation { easing.type: Easing.InOutQuad; duration: 200 } + } + } + } + } + } + + Pane { + Layout.fillWidth: true + Layout.fillHeight: true + padding: 0 + + background: Rectangle { + color: "#eaeaea" + } + + ListModel { + id: listModel + ListElement { + name: "Bill Smith" + number: "555 3264" + } + ListElement { + name: "John Brown" + number: "555 8426" + } + ListElement { + name: "Sam Wise" + number: "555 0473" + } + ListElement { + name: "Bill Smith" + number: "555 3264" + } + ListElement { + name: "John Brown" + number: "555 8426" + } + ListElement { + name: "Sam Wise" + number: "555 0473" + } + ListElement { + name: "Bill Smith" + number: "555 3264" + } + ListElement { + name: "John Brown" + number: "555 8426" + } + ListElement { + name: "Sam Wise" + number: "555 0473" + } + ListElement { + name: "Bill Smith" + number: "555 3264" + } + ListElement { + name: "John Brown" + number: "555 8426" + } + ListElement { + name: "Sam Wise" + number: "555 0473" + } + } + + ListView { + id: listView + width: parent.width + height: parent.height + + model: listModel + + highlight: Rectangle { + color: Material.accent + opacity: 0.2 + } + + ScrollBar.vertical: ScrollBar { id: scrollBar } + + delegate: ItemDelegate { + width: parent.width + height: 80 + onClicked: listView.currentIndex = index + + contentItem: Item { + Row { + spacing: 16 + + ImageStatus { + width: parent.height + height: parent.height + source: "qrc:/asset/img/avatar.png" + } + + Column { + Text { + text: name + color: "#424242" + } + Text { + text: number + color: "#424242" + } + } + } + } + } + } + } + } +} diff --git a/qml/main.qml b/qml/main.qml new file mode 100644 index 000000000..a72bf98dc --- /dev/null +++ b/qml/main.qml @@ -0,0 +1,168 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import QtGraphicalEffects 1.0 +import Qt.labs.settings 1.0 + +import "qrc:/qml/component" +import "qrc:/qml/form" + +import Matrique 0.1 + +ApplicationWindow { + id: window + visible: true + width: 960 + height: 640 + title: qsTr("Matrique") + + Connection { id: connection } + + Settings { + id: settings + + property alias user: loginPage.username + property alias pass: loginPage.password + property var token + } + + FontLoader { id: materialFont; source: "qrc:/asset/font/material.ttf" } + + function login() { + console.info("Login is invoked.") + + var connect = connection.connectToServer + + connection.connected.connect(function() { + settings.user = connection.userId() + settings.token = connection.accessToken + + connection.connectionError.connect(connection.reconnect) + connection.syncDone.connect(resync) + connection.reconnected.connect(resync) + + connection.sync() + }) + + var userParts = settings.user.split(':') + if(userParts.length === 1 || userParts[1] === "matrix.org") { // If this user uses default server. + console.info("Matrix server is used.") + connect(settings.user, settings.pass, "Device") + } else { + connection.resolved.connect(function() { + connect(settings.user, settings.pass, "Device") + }) + connection.resolveError.connect(function() { + console.info("Couldn't resolve server!") + }) + connection.resolveServer(userParts[1]) + } + } + + SideNav { + id: sideNav + width: 80 + height: window.height + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + ButtonDelegate { + index: 0 + + contentItem: ImageStatus { + width: parent.width + height: parent.width + source: "qrc:/asset/img/avatar.png" + anchors.horizontalCenter: parent.horizontalCenter + } + } + + Rectangle { + color: "transparent" + Layout.fillHeight: true + } + + ButtonDelegate { + index: 1 + + contentItem: Text { + text: "\ue853" + font.pointSize: 16 + font.family: materialFont.name + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ButtonDelegate { + index: 2 + + contentItem: Text { + text: "\ue5d2" + font.pointSize: 16 + font.family: materialFont.name + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ButtonDelegate { + index: 3 + + contentItem: Text { + text: "\ue8b8" + font.pointSize: 16 + font.family: materialFont.name + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ButtonDelegate { + index: 4 + + contentItem: Text { + text: "\ue879" + font.pointSize: 16 + font.family: materialFont.name + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + onClicked: Qt.quit() + } + } + } + + SwipeView { + id: swipeView + anchors.fill: parent + anchors.leftMargin: sideNav.width + interactive: false + orientation: Qt.Vertical + + Home { + + } + + Login { + id: loginPage + window: window + } + + Contact { + + } + + Setting { + + } + } +} diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf new file mode 100644 index 000000000..9d0d3debf --- /dev/null +++ b/qtquickcontrols2.conf @@ -0,0 +1,13 @@ +; This file can be edited to change the style of the application +; Read "Qt Quick Controls 2 Configuration File" for details: +; http://doc.qt.io/qt-5/qtquickcontrols2-configuration.html + +[Controls] +Style=Material + +[Material] +Theme=Light +Primary=#00695c +Accent=#00695c +;Foreground=Black +;Background=#161616 diff --git a/res.qrc b/res.qrc new file mode 100644 index 000000000..c3b15669b --- /dev/null +++ b/res.qrc @@ -0,0 +1,19 @@ + + + qtquickcontrols2.conf + asset/img/avatar.png + asset/img/background.jpg + asset/font/material.ttf + qml/Contact.qml + qml/Home.qml + qml/Login.qml + qml/main.qml + qml/Setting.qml + qml/component/ButtonDelegate.qml + qml/component/ImageStatus.qml + qml/component/SideNav.qml + qml/form/ChatForm.qml + qml/form/ContactDetailForm.qml + qml/form/ContactListForm.qml + +