diff --git a/Desktop.qml b/Desktop.qml index ac0b23ac..15d17e02 100644 --- a/Desktop.qml +++ b/Desktop.qml @@ -1,349 +1,352 @@ // Skeleton from https://github.com/achipa/outqross_blog.git // Almost everything has been re-adapted import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.2 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 import QtQuick.Layouts 1.1 import Qt.labs.settings 1.0 import QtGraphicalEffects 1.0 import KDE.Ruqola.Ruqola 1.0 import KDE.Ruqola.DDPClient 1.0 import KDE.Ruqola.Notification 1.0 // import "Log.js" as Log // import "Data.js" as Data ApplicationWindow { property int margin: 11 property string statusText property string lightGreen: "#6ab141"; property string darkGreen: "#00613a"; property string selectedRoomID: ""; id: appid title: qsTr("Ruqola") width: 800 height: 600 visible: true Shortcut { sequence: StandardKey.Quit context: Qt.ApplicationShortcut onActivated: Qt.quit() } Login { id: loginTab visible: (Ruqola.loginStatus == DDPClient.LoginFailed || Ruqola.loginStatus == DDPClient.LoggedOut) // visible: (Ruqola.loginStatus != DDPClient.LoggedIn) anchors.fill:parent z: 10 serverURL: Ruqola.serverURL username: Ruqola.userName onAccepted: { Ruqola.password = loginTab.password; Ruqola.userName = loginTab.username; Ruqola.serverURL = loginTab.serverURL; Ruqola.tryLogin(); - } + } + onOauthAccepted: { + Ruqola.tryOAuthLogin(); + } } BusyIndicator { id: busy anchors.centerIn: parent visible: Ruqola.loginStatus == DDPClient.LoggingIn } Item { id: mainWidget anchors.fill: parent visible: !loginTab.visible Rectangle { id: userBox anchors.top: parent.top width: parent.width anchors.left: parent.left anchors.right: roomsList.right height: 40 color: darkGreen Text { verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignRight anchors.rightMargin: 10 anchors.fill: parent font.pointSize: 12 color: "white" text: "Hello, " + Ruqola.userName } } RoomsView { anchors.top: userBox.bottom anchors.left: parent.left anchors.bottom: parent.bottom anchors.margins: 0 width: 200 height: appid.height id: roomsList model: Ruqola.roomModel() visible: parent.visible selectedRoomID: appid.selectedRoomID; onRoomSelected: { if (roomID == selectedRoomID) { return; } console.log("Choosing room", roomID); appid.selectedRoomID = roomID; activeChat.model = Ruqola.getModelForRoom(roomID) topicWidget.selectedRoom = Ruqola.getRoom(roomID) } onCountChanged: { // console.log("We have", roomsList.count, "rooms") } LinearGradient { id: greenGradient anchors.fill: parent start: Qt.point(0, 0) end: Qt.point(roomsList.width, 0) gradient: Gradient { GradientStop { position: 0.0; color: "#6ab141" } GradientStop { position: 1.0; color: "#00613a" } } z: -1; } } //RoomsView Item { anchors.right: parent.right anchors.left: roomsList.right anchors.top: parent.top anchors.bottom: input.top id: chatView Rectangle { id: topicWidget color: "#fff" anchors.top: parent.top anchors.right: parent.right anchors.left: parent.left height: nameLabel.height + topicLabel.height property var selectedRoom; Text { id: nameLabel text: "#" + parent.selectedRoom.name font.pointSize: 18 verticalAlignment: Text.AlignVCenter anchors.leftMargin: 20 height: 40 // height: font.pixelSize + 10 anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right } Text { id: topicLabel text: topicWidget.selectedRoom.topic anchors.top: nameLabel.bottom anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right horizontalAlignment: Text.AlignHCenter height: font.pixelSize + 10 } } ScrollView { anchors.right: parent.right anchors.left: parent.left anchors.top: topicWidget.bottom anchors.bottom: parent.bottom verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn // visible: parent.visible && (Ruqola.loginStatus != DDPClient.LoggingIn) // visible: !greeter.visible ListView { id: activeChat // model: Ruqola.getModelForRoom(selectedRoomID) onCountChanged: { // console.log("changed") // var newIndex = count - 1 // last index // positionViewAtEnd() positionViewAtIndex(count - 1, ListView.Beginning) // currentIndex = newIndex } // Component.onCompleted: positionViewAtEnd() Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning) // onSelectedRoomIDChanged: { console.log("CHANGED"); activeChat.positionViewAtEnd(); } // model: myModel anchors.fill:parent visible : count > 0 z: -1 // ScrollBar.vertical: ScrollBar { } delegate: Message { i_messageText: messageText i_username: username i_systemMessage: systemMessage i_systemMessageType: type //width: parent.width } } } } //Item chatView Item { anchors.bottom: parent.bottom anchors.left: roomsList.right anchors.right: parent.right id: input height: 40 TextField { id: messageLine anchors.left: parent.left anchors.bottom: parent.bottom anchors.top: parent.top anchors.right: emoticonsButton.left placeholderText: if (Ruqola.loginStatus != DDPClient.LoggedIn || (selectedRoomID=="")){ qsTr("Please Select a room") } else{ qsTr("Enter message") } // height: 2.7*font.pixelSize property string type: "text"; onAccepted: { if (text != "" && Ruqola.loginStatus == DDPClient.LoggedIn && !(selectedRoomID=="")) { Ruqola.sendMessage(selectedRoomID, text, type); text = ""; } } } Button { anchors.bottom: parent.bottom anchors.top: parent.top anchors.right: attachmentsButton.left width: 50 id : emoticonsButton iconName: "emoticonsButton" iconSource: "qrc:/Emoticon.png" visible: true } Button { anchors.bottom: parent.bottom anchors.top: parent.top anchors.right: parent.right width: 50 id : attachmentsButton iconName: "attachmentsButton" iconSource: "qrc:/attach-button.jpg" visible: true onClicked: Ruqola.attachmentButtonClicked(); } }//Item input }// mainWidget Item Image { id: receivedImage source:" " width: 60 height: 80 fillMode: Image.PreserveAspectFit // visible: //only when an image is recieved from server sourceSize.width: 1024 sourceSize.height: 1024 } Rectangle { z: -10 anchors.fill: parent color: "white" } onClosing: { console.log("Minimizing to systray..."); hide(); } function toggleShow() { if (visible) { hide(); } else { show(); raise(); requestActivate(); } } Component.onCompleted: { systrayIcon.activated.connect(toggleShow); systrayIcon.messageClicked.connect(toggleShow); // roomsList.model = Ruqola.roomModel(); // timer.start(); // timer.fire(); } /* Timer { id: timer interval: 1000 onTriggered: { // console.log("FIRE"); switch (Ruqola.loginStatus) { case Ruqola.NotConnected: statusText = qsTr("Not connected."); break; case Ruqola.LoggedIn: statusText = qsTr("Connected to " + Ruqola.serverURL); break; } } repeat: true }*/ // onStatusTextChanged: timer.restart(); } diff --git a/Login.qml b/Login.qml index 5add9217..85024467 100644 --- a/Login.qml +++ b/Login.qml @@ -1,107 +1,116 @@ import QtQuick 2.7 import QtQuick.Controls 1.3 Item { property alias username: usernameField.text; property alias password: passField.text; property alias serverURL: urlField.text; signal accepted() - + signal oauthAccepted() + Keys.onPressed: { if (event.key === Qt.Key_Enter) { acceptingButton.clicked(); } else if (event.key === StandardKey.Escape) { } } id: loginForm // color: "#eeeeee" implicitHeight: 400 implicitWidth: 300 Column { id: form anchors.centerIn: parent width: 0.8*parent.width spacing: 3 Text { text: "Ruqola Log in" color: "#555" id: loginLabel - font.pixelSize: 20 + font.pixelSize: 40 horizontalAlignment: Text.AlignHCenter width: parent.width } Item { id: spacer width: 30 height: 30 } Text { width: parent.width text:"Rocket Chat Server" } TextField { id: urlField // text: loginForm.serverURL width: parent.width placeholderText: qsTr("Enter address of the server") } Text { id:username width: parent.width text:"Enter your username" } TextField { width: parent.width id: usernameField placeholderText: qsTr("Enter username") } Text { id: passLabel width: parent.width text:"Enter your password" } TextField { width: parent.width id:passField echoMode: TextInput.Password inputMethodHints: Qt.ImhHiddenText placeholderText: qsTr("Enter password") } Item { id: spacer2 width: 30 height: 30 } Button { id: acceptingButton width: parent.width text: qsTr("Log in") enabled: (passField.text && urlField.text && usernameField.text) onClicked: loginForm.accepted() isDefault: true } + + Button { + id: authButton + width: parent.width + text: qsTr("Log in with Google Account") + enabled: (passField.text && urlField.text && usernameField.text) + onClicked: loginForm.oauthAccepted() + } } // Component.onCompleted: { // acceptingButton.clicked.connect(loginForm.accepted) // } } diff --git a/Ruqola.pro b/Ruqola.pro index 867b1d81..8675924f 100644 --- a/Ruqola.pro +++ b/Ruqola.pro @@ -1,20 +1,23 @@ TEMPLATE = app -QT += widgets gui core qml quick websockets +QT += widgets gui core qml quick websockets network networkauth HEADERS += src/messagemodel.h src/roommodel.h src/ddpclient.h src/ruqola.h src/rocketchatbackend.h \ src/notification.h \ - src/messagequeue.h + src/messagequeue.h \ + src/authentication.h SOURCES += main.cpp src/messagemodel.cpp src/roommodel.cpp src/ddpclient.cpp src/ruqola.cpp src/rocketchatbackend.cpp \ src/notification.cpp \ - src/messagequeue.cpp + src/messagequeue.cpp \ + src/authentication.cpp RESOURCES += qml.qrc # Additional import path used to resolve QML modules in Qt Creator's code model # QML_IMPORT_PATH = # Default rules for deployment. include(deployment.pri) -DISTFILES += +DISTFILES += \ + src/client_secret.json diff --git a/src/authentication.cpp b/src/authentication.cpp index afa507dd..1b2d80b8 100644 --- a/src/authentication.cpp +++ b/src/authentication.cpp @@ -1,86 +1,109 @@ +/* + * + * Copyright 2016 Riccardo Iaconelli + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + #include "ruqola.h" #include "authentication.h" #include #include Authentication::Authentication() { getDataFromJson(); } void Authentication::OAuthLogin() { QJsonObject authKeys; authKeys["credentialToken"] = m_client_id; authKeys["credentialSecret"] = m_client_secret; QJsonArray requestPermissions; requestPermissions.append("email"); bool requestOfflineToken = true; - QString scope = QString("%1 %2 %3").arg("openID").arg("profile").arg("email"); + QString scope = QString("openID profile email"); QSettings s; s.setValue("stateHexNumber", QString("{67C8770B-44F1-410A-AB9A-F9B5446F13EE}")); QUuid state(s.value("stateHexNumber").toString()); QJsonObject loginUrlParameters; loginUrlParameters["client_id"] = m_client_id; loginUrlParameters["response_type"] = QString("code"); loginUrlParameters["scope"] = scope; loginUrlParameters["state"] = state.toString(); QString username = s.value("username").toString(); QString loginHint = username; QString loginStyle = QString("redirect"); QString redirectUrl = s.value("redirectUrl").toString(); QJsonObject json; json["requestPermissions"] = requestPermissions; json["requestOfflineToken"] = requestOfflineToken; json["loginUrlParameters"] = loginUrlParameters; json["loginHint"] = loginHint; json["loginStyle"] = loginStyle; json["redirectUrl"] = redirectUrl; Ruqola::self()->ddp()->method("login", QJsonDocument(json)); } void Authentication::getDataFromJson(){ QDir cacheDir(":/src/client_secret.json"); if (!cacheDir.exists(cacheDir.path())) { cacheDir.mkpath(cacheDir.path()); } QFile f(cacheDir.absoluteFilePath("client_secret.json")); QString val; if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { val = f.readAll(); } QJsonDocument document = QJsonDocument::fromJson(val.toUtf8()); QJsonObject object = document.object(); const auto settingsObject = object["web"].toObject(); const QUrl authUri(settingsObject["auth_uri"].toString()); const auto clientId = settingsObject["client_id"].toString(); const QUrl tokenUri(settingsObject["token_uri"].toString()); const auto clientSecret(settingsObject["client_secret"].toString()); const auto redirectUrls = settingsObject["redirect_uris"].toArray(); const QUrl redirectUrl(redirectUrls[0].toString()); QSettings s; s.setValue("clientID", clientId); m_client_id = clientId; s.setValue("clientSecret", clientSecret); m_client_secret = clientSecret; s.setValue("redirectUrl", redirectUrl); } //#include "authentication.moc" diff --git a/src/authentication.h b/src/authentication.h index 4f927e28..dc466620 100644 --- a/src/authentication.h +++ b/src/authentication.h @@ -1,27 +1,50 @@ +/* + * + * Copyright 2016 Riccardo Iaconelli + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + #ifndef AUTHENTICATION_H #define AUTHENTICATION_H #include #include class Authentication { public: Authentication(); void getDataFromJson(); void OAuthLogin(); void sendApiRequest(); private slots: void onGranted(); private: bool m_authGranted; QString m_client_id; QString m_client_secret; QOAuth2AuthorizationCodeFlow * m_google; }; #endif // AUTHENTICATION_H diff --git a/src/ruqola.cpp b/src/ruqola.cpp index 876116e3..292eff88 100644 --- a/src/ruqola.cpp +++ b/src/ruqola.cpp @@ -1,284 +1,321 @@ /* * * Copyright 2016 Riccardo Iaconelli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ruqola.h" #include "roommodel.h" #include "ddpclient.h" #include "notification.h" #include "messagequeue.h" #include #include #include #include Ruqola *Ruqola::m_self = 0; QString Ruqola::authToken() const { return m_authToken; } QString Ruqola::userName() const { return m_userName; } QString Ruqola::userID() const { return m_userID; } QString Ruqola::password() const { return m_password; } void Ruqola::setAuthToken(const QString& token) { qDebug() << "Setting token to" << token; QSettings s; m_authToken = token; s.setValue("authToken", token); } void Ruqola::setPassword(const QString& password) { m_password = password; } void Ruqola::setUserName(const QString& username) { m_userName = username; QSettings s; s.setValue("username", username); emit userNameChanged(); } void Ruqola::setUserID(const QString& userID) { m_userName = userID; QSettings s; s.setValue("userID", userID); emit userIDChanged(); } RoomModel * Ruqola::roomModel() { if (!m_roomModel) { qDebug() << "creating new RoomModel"; m_roomModel = new RoomModel(this); qDebug() << m_roomModel; } return m_roomModel; } DDPClient * Ruqola::ddp() { if (!m_ddp) { m_ddp = new DDPClient(serverURL()); connect(m_ddp, &DDPClient::loginStatusChanged, this, &Ruqola::loginStatusChanged); // connect(m_ddp, &DDPClient::loginStatusChanged, this, [=](){qDebug() << "Signal received";}); } return m_ddp; } MessageQueue * Ruqola::messageQueue() { if (!m_messageQueue) { m_messageQueue = new MessageQueue(); // retry to send any unsent messages Ruqola::self()->messageQueue()->processQueue(); } return m_messageQueue; } Notification * Ruqola::notification() { - if (m_notification == NULL) { + if (!m_notification) { m_notification = new Notification(); m_notification->show(); } return m_notification; } +Authentication * Ruqola::authentication() +{ + if (!m_authentication) { + m_authentication = new Authentication(); + } + + qDebug() << "------------------------------------------"; + qDebug() << "return auth object"; + return m_authentication; +} + void Ruqola::attachmentButtonClicked() { QString fileName = QFileDialog::getOpenFileName(Q_NULLPTR, "Select one or more files to open", QDir::homePath(), "Images (*.png *.jpeg *.jpg)"); qDebug() << "Selected Image " << fileName; QFile file(fileName); if (!file.open(QFile::ReadOnly)) { qDebug() << "Cannot open the selected file"; return; } const QString message = QString::fromLatin1(file.readAll().toBase64()); const QString roomID("3cGRyFLWgnPL7B79n"); //hard code roomID for now const QString type("image"); sendMessage(roomID, message, type); } void Ruqola::sendMessage(const QString &roomID, const QString &message, const QString &type) { QJsonObject json; json["rid"] = roomID; json["msg"] = message; json["type"] = type; ddp()->method("sendMessage", QJsonDocument(json), DDPClient::Persistent); } MessageModel * Ruqola::getModelForRoom(const QString& roomID) { if (m_messageModels.contains(roomID)) { // qDebug() << "Returning old model for " << roomID; return m_messageModels.value(roomID); } else { // qDebug() << "Creating a new model"; m_messageModels[roomID] = new MessageModel(roomID, this); return m_messageModels[roomID]; } } QString Ruqola::serverURL() const { return m_serverURL; } void Ruqola::setServerURL(const QString& serverURL) { if (m_serverURL == serverURL) { return; } QSettings s; s.setValue("serverURL", serverURL); m_serverURL = serverURL; // m_roomModel->reset(); emit serverURLChanged(); } DDPClient::LoginStatus Ruqola::loginStatus() { if (m_ddp) { return ddp()->loginStatus(); } else { return DDPClient::LoggedOut; } } void Ruqola::tryLogin() { qDebug() << "Attempting login" << userName() << "on" << serverURL(); // Reset model views foreach (const QString key, m_messageModels.keys()) { MessageModel *m = m_messageModels.take(key); delete m; } delete m_ddp; m_ddp = 0; // In the meantime, load cache... m_roomModel->reset(); // This creates a new ddp() object. // DDP will automatically try to connect and login. ddp(); } +void Ruqola::tryOAuthLogin() +{ + m_authentication->OAuthLogin(); + + // Reset model views + foreach (const QString key, m_messageModels.keys()) { + MessageModel *m = m_messageModels.take(key); + delete m; + } + delete m_ddp; + m_ddp = 0; + + // In the meantime, load cache... + m_roomModel->reset(); + +} + void Ruqola::logOut() { setAuthToken(QString()); setPassword(QString()); foreach (const QString key, m_messageModels.keys()) { MessageModel *m = m_messageModels.take(key); delete m; } delete m_ddp; m_ddp = 0; emit loginStatusChanged(); m_roomModel->clear(); } QString Ruqola::cacheBasePath() const { if (m_serverURL.isEmpty()) { return QString(); } return QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+'/'+m_serverURL; } // QString Ruqola::activeRoom() const // { // return m_activeRoom; // } // void Ruqola::setActiveRoom(const QString& activeRoom) // { // m_activeRoom = activeRoom; // // roomModel()->setActiveRoom(activeRoom); // emit activeRoomChanged(); // } RoomWrapper * Ruqola::getRoom(const QString& roomID) { return roomModel()->findRoom(roomID); } -Ruqola::Ruqola(QObject* parent): QObject(parent), m_ddp(0), m_messageQueue(0), m_roomModel(0), m_notification(0) +Ruqola::Ruqola(QObject* parent): + QObject(parent), + m_ddp(0), + m_messageQueue(0), + m_roomModel(0), + m_notification(0), + m_authentication(0) { QSettings s; m_serverURL = s.value("serverURL", "demo.rocket.chat").toString(); m_userName = s.value("username").toString(); m_userID = s.value("userID").toString(); m_authToken = s.value("authToken").toString(); } Ruqola * Ruqola::self() { if (!m_self) { m_self = new Ruqola; // Create DDP object so we try to connect at startup m_self->ddp(); // Clear rooms data and refill it with data in the cache, if there is m_self->roomModel()->reset(); // Create systray to show notifications m_self->notification(); //Initialize the messageQueue object m_self->messageQueue(); + + m_self->authentication(); + } return m_self; } diff --git a/src/ruqola.h b/src/ruqola.h index 8e888956..0fa7fe7f 100644 --- a/src/ruqola.h +++ b/src/ruqola.h @@ -1,124 +1,126 @@ /* * * Copyright 2016 Riccardo Iaconelli * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef USERDATA_H #define USERDATA_H #include #include #include #include "ddpclient.h" #include "roommodel.h" #include "messagemodel.h" #include "notification.h" #include "messagequeue.h" - +#include "authentication.h" class QString; class Ruqola: public QObject { Q_OBJECT Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) Q_PROPERTY(QString userID READ userID WRITE setUserID NOTIFY userIDChanged) Q_PROPERTY(QString serverURL READ serverURL WRITE setServerURL NOTIFY serverURLChanged) Q_PROPERTY(QString password WRITE setPassword) // Q_PROPERTY (bool connected READ connected NOTIFY connectedChanged) Q_PROPERTY(DDPClient::LoginStatus loginStatus READ loginStatus NOTIFY loginStatusChanged) // Q_PROPERTY(QString activeRoom READ activeRoom WRITE setActiveRoom NOTIFY activeRoomChanged) public: static Ruqola* self(); void setUserName(const QString &username); QString userName() const; void setUserID(const QString &userID); QString userID() const; void setPassword(const QString &password); QString password() const; void setAuthToken(const QString &token); QString authToken() const; bool connected(); DDPClient::LoginStatus loginStatus(); QString serverURL() const; void setServerURL(const QString &serverURL); // QString activeRoom() const; // void setActiveRoom(const QString &activeRoom); DDPClient *ddp(); Notification *notification(); MessageQueue *messageQueue(); - + Authentication *authentication(); Q_INVOKABLE RoomModel *roomModel(); Q_INVOKABLE void sendMessage(const QString &roomID, const QString &message, const QString &type); Q_INVOKABLE MessageModel* getModelForRoom(const QString &roomID); Q_INVOKABLE void tryLogin(); Q_INVOKABLE void logOut(); + Q_INVOKABLE void tryOAuthLogin(); Q_INVOKABLE RoomWrapper* getRoom(const QString &roomID); Q_INVOKABLE void attachmentButtonClicked(); QString cacheBasePath() const; signals: void userNameChanged(); void userIDChanged(); void serverURLChanged(); void loginStatusChanged(); private: Ruqola(QObject *parent = 0); static Ruqola *m_self; QString m_password; QString m_userName; QString m_userID; QString m_authToken; QString m_serverURL; DDPClient *m_ddp; MessageQueue *m_messageQueue; RoomModel *m_roomModel; Notification *m_notification; + Authentication *m_authentication; QHash< QString, MessageModel * > m_messageModels; }; inline static QObject *ruqola_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) Ruqola *userData = Ruqola::self(); return userData; } #endif // USERDATA_H