diff --git a/Desktop.qml b/Desktop.qml index 678700ad..81cd4248 100644 --- a/Desktop.qml +++ b/Desktop.qml @@ -1,326 +1,326 @@ // 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.UserData 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: (UserData.loginStatus == DDPClient.LoginFailed || UserData.loginStatus == DDPClient.LoggedOut) -// visible: (UserData.loginStatus != DDPClient.LoggedIn) + visible: (Ruqola.loginStatus == DDPClient.LoginFailed || Ruqola.loginStatus == DDPClient.LoggedOut) +// visible: (Ruqola.loginStatus != DDPClient.LoggedIn) anchors.fill:parent z: 10 - serverURL: UserData.serverURL - username: UserData.userName + serverURL: Ruqola.serverURL + username: Ruqola.userName onAccepted: { - UserData.password = loginTab.password; - UserData.userName = loginTab.username; - UserData.serverURL = loginTab.serverURL; - UserData.tryLogin(); + Ruqola.password = loginTab.password; + Ruqola.userName = loginTab.username; + Ruqola.serverURL = loginTab.serverURL; + Ruqola.tryLogin(); } } BusyIndicator { id: busy anchors.centerIn: parent - visible: UserData.loginStatus == DDPClient.LoggingIn + 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, " + UserData.userName + 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: UserData.roomModel() + model: Ruqola.roomModel() visible: parent.visible selectedRoomID: appid.selectedRoomID; onRoomSelected: { if (roomID == selectedRoomID) { return; } console.log("Choosing room", roomID); appid.selectedRoomID = roomID; - activeChat.model = UserData.getModelForRoom(roomID) - topicWidget.selectedRoom = UserData.getRoom(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; } } Item { anchors.right: parent.right anchors.left: roomsList.right anchors.top: parent.top anchors.bottom: messageLine.top // Item { // anchors.fill: parent // id: greeter // visible: false // // visible: selectedRoomID.empty // Text { // text: "Welcome to Ruqola!"; // } // } 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 && (UserData.loginStatus != DDPClient.LoggingIn) +// visible: parent.visible && (Ruqola.loginStatus != DDPClient.LoggingIn) // visible: !greeter.visible ListView { id: activeChat -// model: UserData.getModelForRoom(selectedRoomID) +// 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 TextField { id: messageLine anchors.right: parent.right anchors.left: roomsList.right anchors.bottom: parent.bottom - placeholderText: if (UserData.loginStatus != DDPClient.LoggedIn || (selectedRoomID=="")){ + placeholderText: if (Ruqola.loginStatus != DDPClient.LoggedIn || (selectedRoomID=="")){ qsTr("Please Select a room") } else{ qsTr("Enter message") } height: 2.7*font.pixelSize onAccepted: { - if (text != "" && UserData.loginStatus == DDPClient.LoggedIn && !(selectedRoomID=="")) { - UserData.sendMessage(selectedRoomID, text); + if (text != "" && Ruqola.loginStatus == DDPClient.LoggedIn && !(selectedRoomID=="")) { + Ruqola.sendMessage(selectedRoomID, text); text = ""; } } } }// mainWidget Item Rectangle { z: -10 anchors.fill: parent color: "white" } onClosing: { console.log("Minimizing to systray..."); hide(); systrayIcon.windowVisible = visible; } function toggleShow() { if (visible) { hide(); systrayIcon.windowVisible = visible; } else { show(); raise(); requestActivate(); systrayIcon.windowVisible = visible; } } // function notificationMessageClicked() { // if (!visible) { // show(); // raise(); // requestActivate(); // systrayIcon.windowVisible = visible; // } // } Component.onCompleted: { systrayIcon.activated.connect(toggleShow); systrayIcon.messageClicked.connect(toggleShow); -// roomsList.model = UserData.roomModel(); +// roomsList.model = Ruqola.roomModel(); // timer.start(); // timer.fire(); } /* Timer { id: timer interval: 1000 onTriggered: { // console.log("FIRE"); - switch (UserData.loginStatus) { - case UserData.NotConnected: + switch (Ruqola.loginStatus) { + case Ruqola.NotConnected: statusText = qsTr("Not connected."); break; - case UserData.LoggedIn: - statusText = qsTr("Connected to " + UserData.serverURL); + case Ruqola.LoggedIn: + statusText = qsTr("Connected to " + Ruqola.serverURL); break; } } repeat: true }*/ // onStatusTextChanged: timer.restart(); } diff --git a/RoomDelegate.qml b/RoomDelegate.qml index 6c2e2af0..2ba54d9a 100644 --- a/RoomDelegate.qml +++ b/RoomDelegate.qml @@ -1,164 +1,164 @@ /* * * 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 . * */ import QtQuick 2.0 Item { property int d_unread: 0; property string d_name: "roomName"; property bool d_selected: false; property string d_roomID : ""; id: root signal roomSelected(string roomID) implicitWidth: nameLabel.implicitWidth+nameLabel.height+30 implicitHeight: nameLabel.implicitHeight + 10 visible: !d_name.empty Text { anchors.fill: parent id: nameLabel font.bold: d_unread > 0 font.pointSize: 11 text: d_name verticalAlignment: Text.AlignVCenter anchors.leftMargin: 15 color: d_selected ? "white" : "white" Rectangle { property bool hovered: false; states: [ State { name: "inactive" PropertyChanges { target: highlight; opacity: 0 } }, State { name: "selected" PropertyChanges { target: highlight; opacity: .7 } }, State { name: "hovered" PropertyChanges { target: highlight; opacity: .25 } } ] id: highlight // opacity: .5 // visible: d_selected anchors.fill: parent anchors.leftMargin: -10 anchors.rightMargin: 5 color: "#6ab141" z: -1 radius: 4 state: { if (d_selected) { return "selected"; } else { if (highlight.hovered) { return "hovered"; } else { return "inactive"; } } } MouseArea { hoverEnabled: true anchors.fill: parent onEntered: { // if (highlight.state != "selected") { highlight.hovered = true // highlight.state = "hovered" // } } onExited: { // if (highlight.state != "selected") { highlight.hovered = false // highlight.state = "inactive" // } } onClicked: { if (highlight.state == "hovered") { root.roomSelected(d_roomID); // highlight.state = "selected" d_selected: true; } else { root.roomSelected(""); // highlight.state = "hovered" d_selected: false; } } } //MouseArea closed } //Rectangle closed } //Text closed Rectangle { anchors.rightMargin: 15 visible: d_unread > 0 anchors.right: root.right anchors.verticalCenter: nameLabel.verticalCenter // width: nameLabel.font.pixelSize width: 0.7*nameLabel.height height: width color: "#6ab141" radius: width*0.5 Text { anchors.fill: parent color: "white" text: d_unread verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } } // id: room_chooser // // MouseArea { // anchors.fill: parent // onClicked: { // console.log("Choosing room", room_chooser.internal_id); // selectedRoomID = room_chooser.internal_id; // // // myModel.currentRoom = selectedRoomID; // // // This line crashes the program when we refine RoomsModel: -// // if (UserData.loginStatus != DDPClient.LoggingIn) -// // activeChat.model = UserData.getModelForRoom(selectedRoomID); +// // if (Ruqola.loginStatus != DDPClient.LoggingIn) +// // activeChat.model = Ruqola.getModelForRoom(selectedRoomID); // // // console.log(activeChat.count); // } // } } // Item closed diff --git a/Ruqola.pro b/Ruqola.pro index 6bd6d988..2c077736 100644 --- a/Ruqola.pro +++ b/Ruqola.pro @@ -1,18 +1,18 @@ TEMPLATE = app QT += widgets gui core qml quick websockets -HEADERS += src/messagemodel.h src/roommodel.h src/ddpclient.h src/userdata.h src/rocketchatbackend.h \ +HEADERS += src/messagemodel.h src/roommodel.h src/ddpclient.h src/ruqola.h src/rocketchatbackend.h \ src/notification.h -SOURCES += main.cpp src/messagemodel.cpp src/roommodel.cpp src/ddpclient.cpp src/userdata.cpp src/rocketchatbackend.cpp \ +SOURCES += main.cpp src/messagemodel.cpp src/roommodel.cpp src/ddpclient.cpp src/ruqola.cpp src/rocketchatbackend.cpp \ src/notification.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 += diff --git a/main.cpp b/main.cpp index afab3259..1bc56fa0 100644 --- a/main.cpp +++ b/main.cpp @@ -1,42 +1,42 @@ #include #include // only if desktop #include "src/roommodel.h" #include "src/rocketchatbackend.h" -#include "src/userdata.h" +#include "src/ruqola.h" #include "src/notification.h" #include #include #include int main(int argc, char *argv[]) { QApplication app(argc, argv); app.setWindowIcon(QIcon(":/systray.png")); QCoreApplication::setOrganizationName("KDE"); QCoreApplication::setOrganizationDomain("kde.org"); QCoreApplication::setApplicationName("Ruqola"); - qmlRegisterSingletonType("KDE.Ruqola.UserData", 1, 0, "UserData", userdata_singletontype_provider); + qmlRegisterSingletonType("KDE.Ruqola.Ruqola", 1, 0, "Ruqola", ruqola_singletontype_provider); qmlRegisterType("KDE.Ruqola.MessageModel", 1, 0, "MessageModel"); qmlRegisterType("KDE.Ruqola.DDPClient", 1, 0, "DDPClient"); qmlRegisterType("KDE.Ruqola.RoomModel", 1, 0, "RoomModel"); qmlRegisterType("KDE.Ruqola.RoomWrapper", 1, 0, "RoomWrapper"); qmlRegisterType("KDE.Ruqola.Notification", 1, 0, "Notification"); RocketChatBackend c; QQmlApplicationEngine engine; QQmlContext *ctxt = engine.rootContext(); - ctxt->setContextProperty("systrayIcon", UserData::self()->notification()); + ctxt->setContextProperty("systrayIcon", Ruqola::self()->notification()); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } diff --git a/src/ddpclient.cpp b/src/ddpclient.cpp index 2c57810d..29da5611 100644 --- a/src/ddpclient.cpp +++ b/src/ddpclient.cpp @@ -1,294 +1,294 @@ /* * * 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 "ddpclient.h" #include #include #include -#include "userdata.h" +#include "ruqola.h" void process_test(QJsonDocument doc) { qDebug() << "Callback test:" << doc; qDebug() << "End callback"; } void login_callback(QJsonDocument doc) { qDebug() << "LOGIN:" << doc; - UserData::self()->setAuthToken(doc.object().value("token").toString()); + Ruqola::self()->setAuthToken(doc.object().value("token").toString()); qDebug() << "End callback"; } void DDPClient::resume_login_callback(QJsonDocument doc) { qDebug() << "LOGIN:" << doc; - UserData::self()->setAuthToken(doc.object().value("token").toString()); + Ruqola::self()->setAuthToken(doc.object().value("token").toString()); qDebug() << "End callback"; } void empty_callback(QJsonDocument doc) { Q_UNUSED(doc); } DDPClient::DDPClient(const QString& url, QObject* parent) : QObject(parent), m_url(url), m_uid(1), m_loginJob(0), m_loginStatus(NotConnected), m_connected(false), m_attemptedPasswordLogin(false), m_attemptedTokenLogin(false) { m_webSocket.ignoreSslErrors(); connect(&m_webSocket, &QWebSocket::connected, this, &DDPClient::onWSConnected); connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &DDPClient::onTextMessageReceived); connect(&m_webSocket, &QWebSocket::disconnected, this, &DDPClient::WSclosed); - connect(UserData::self(), &UserData::serverURLChanged, this, &DDPClient::onServerURLChange); + connect(Ruqola::self(), &Ruqola::serverURLChanged, this, &DDPClient::onServerURLChange); if (!url.isEmpty()) { m_webSocket.open(QUrl("wss://"+url+"/websocket")); } qDebug() << "Trying to connect to URL" << url; } DDPClient::~DDPClient() { m_webSocket.close(); } void DDPClient::onServerURLChange() { - if (UserData::self()->serverURL() != m_url || !m_webSocket.isValid()) { + if (Ruqola::self()->serverURL() != m_url || !m_webSocket.isValid()) { if (m_webSocket.isValid()) { m_webSocket.flush(); m_webSocket.close(); } - m_url = UserData::self()->serverURL(); + m_url = Ruqola::self()->serverURL(); m_webSocket.open(QUrl("wss://"+m_url+"/websocket")); connect(&m_webSocket, &QWebSocket::connected, this, &DDPClient::onWSConnected); qDebug() << "Reconnecting" << m_url; //<< m_webSocket.st; } } DDPClient::LoginStatus DDPClient::loginStatus() const { return m_loginStatus; } bool DDPClient::isConnected() const { return m_connected; } bool DDPClient::isLoggedIn() const { return m_loginStatus == LoggedIn; } unsigned int DDPClient::method(const QString& m, const QJsonDocument& params) { return method(m, params, empty_callback); } unsigned int DDPClient::method(const QString& method, const QJsonDocument& params, std::function callback) { QString json; if (params.isArray()){ json = "{\"msg\":\"method\", \"method\": \"%1\", \"id\": \"%2\", \"params\": %3}"; } else { json = "{\"msg\":\"method\", \"method\": \"%1\", \"id\": \"%2\", \"params\": [%3]}"; } json = json.arg(method).arg(m_uid).arg(QString(params.toJson(QJsonDocument::Compact))); qDebug() << json.arg(method).arg(m_uid); //.arg(QString(params.toJson(QJsonDocument::Indented))); qint64 bytes = m_webSocket.sendTextMessage(json.toUtf8()); if (bytes < json.length()) { qDebug() << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; qDebug() << m_webSocket.isValid() << m_webSocket.error() << m_webSocket.requestUrl(); } else { qDebug() << "Successfully sent " << json; } //callback(QJsonDocument::fromJson(json.toUtf8())); m_callbackHash[m_uid] = callback; m_uid++; return m_uid - 1 ; } void DDPClient::subscribe(const QString& collection, const QJsonDocument& params) { QString json("{\"msg\":\"sub\",\"id\": \"%1\",\"name\":\"%2\", \"params\": %3}"); json = json.arg(m_uid).arg(collection).arg(QString(params.toJson(QJsonDocument::Compact))); qint64 bytes = m_webSocket.sendBinaryMessage(json.toUtf8()); if (bytes < json.length()) { qDebug() << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; } m_uid++; } void DDPClient::onTextMessageReceived(QString message) { QJsonDocument response = QJsonDocument::fromJson(message.toUtf8()); if (!response.isNull() && response.isObject()) { QJsonObject root = response.object(); QString messageType = root.value("msg").toString(); if (messageType == "updated") { } else if (messageType == "result") { // qDebug() << "got a result" << root; unsigned id = root.value("id").toString().toInt(); if (m_callbackHash.contains(id)) { std::function callback = m_callbackHash.take(id); callback( QJsonDocument(root.value("result").toObject()) ); } emit result(id, QJsonDocument(root.value("result").toObject())); if (id == m_loginJob) { if (root.value("error").toObject().value("error").toInt() == 403) { qDebug() << "Wrong password or token expired"; // // Kill wrong credentials, so we don't try to use them again -// if (!UserData::instance()->authToken().isEmpty()) { -// UserData::instance()->setAuthToken(QString()); -// } else if (!UserData::instance()->password().isEmpty()) { -// UserData::instance()->setPassword(QString()); +// if (!Ruqola::instance()->authToken().isEmpty()) { +// Ruqola::instance()->setAuthToken(QString()); +// } else if (!Ruqola::instance()->password().isEmpty()) { +// Ruqola::instance()->setPassword(QString()); // } // setLoginStatus(DDPClient::LoginFailed); login(); // Let's keep trying to log in } else { - UserData::self()->setAuthToken(root.value("result").toObject().value("token").toString()); + Ruqola::self()->setAuthToken(root.value("result").toObject().value("token").toString()); setLoginStatus(DDPClient::LoggedIn); } // emit loggedInChanged(); } } else if (messageType == "connected") { qDebug() << "Connected"; m_connected = true; emit connectedChanged(); setLoginStatus(DDPClient::LoggingIn); login(); // Try to resume auth token login } else if (messageType == "error") { qDebug() << "ERROR!!" << message; } else if (messageType == "ping") { qDebug() << "Ping - Pong"; m_webSocket.sendBinaryMessage("{\"msg\":\"pong\"}"); } else if (messageType == "added"){ qDebug() << "ADDING" <password().isEmpty()) { + if (!Ruqola::self()->password().isEmpty()) { // If we have a password and we couldn't log in, let's stop here if (m_attemptedPasswordLogin) { setLoginStatus(LoginFailed); return; } m_attemptedPasswordLogin = true; QString json = "{\"password\":\"%1\", \"user\": {\"username\":\"%2\"}}"; - json = json.arg(UserData::self()->password()).arg(UserData::self()->userName()); + json = json.arg(Ruqola::self()->password()).arg(Ruqola::self()->userName()); m_loginJob = method("login", QJsonDocument::fromJson(json.toUtf8())); - } else if (!UserData::self()->authToken().isEmpty() && !m_attemptedTokenLogin) { + } else if (!Ruqola::self()->authToken().isEmpty() && !m_attemptedTokenLogin) { m_attemptedPasswordLogin = true; QString json = "{\"resume\":\"%1\"}"; - json = json.arg(UserData::self()->authToken()); + json = json.arg(Ruqola::self()->authToken()); m_loginJob = method("login", QJsonDocument::fromJson(json.toUtf8())); } else { setLoginStatus(LoginFailed); } } void DDPClient::logOut() { // setLoginStatus(NotConnected); m_webSocket.close(); } void DDPClient::onWSConnected() { qDebug() << "Websocket connected at URL" << m_url; QString json("{\"msg\":\"connect\", \"version\": \"1\", \"support\": [\"1\"]}"); qint64 bytes = m_webSocket.sendTextMessage(json.toUtf8()); if (bytes < json.length()) { qDebug() << "ERROR! I couldn't send all of my message. This is a bug! (try again)"; } else { qDebug() << "Successfully sent " << json; } } void DDPClient::WSclosed() { qDebug() << "WebSocket CLOSED" << m_webSocket.closeReason() << m_webSocket.error() << m_webSocket.closeCode(); setLoginStatus(NotConnected); // m_connected = false; } diff --git a/src/ddpclient.h b/src/ddpclient.h index ac91c266..f075241a 100644 --- a/src/ddpclient.h +++ b/src/ddpclient.h @@ -1,129 +1,129 @@ /* * * 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 DDPCLIENT_H #define DDPCLIENT_H // #include // #include // #include #include #include #include class QJsonObject; class QJsonDocument; class QUrl; class QWebSocket; class DDPClient : public QObject { Q_OBJECT public: enum LoginStatus { NotConnected, LoggingIn, LoggedIn, LoginFailed, LoggedOut }; Q_ENUM(LoginStatus) DDPClient(const QString &url = QString(), QObject *parent = 0); ~DDPClient(); /** * @brief Call a method with name @param method and parameters @param params * * @param method The name of the method * @param params The parameters * @return unsigned int, the ID of the called method. Watch for it */ unsigned method(const QString &method, const QJsonDocument ¶ms); unsigned method(const QString &method, const QJsonDocument ¶ms, std::function callback); // unsigned method(const QString &method, const QJsonObject ¶ms); void subscribe(const QString &collection, const QJsonDocument ¶ms); Q_INVOKABLE void login(); void logOut(); // Q_INVOKABLE void loginWithPassword(); bool isConnected() const; bool isLoggedIn() const; void onServerURLChange(); signals: // void connected(); void connectedChanged(); void loginStatusChanged(); // void loggedInChanged(); void disconnected(); /** * @brief Emitted whenever a result is received. The parameter is the expected ID. * * @param id the ID received in the method() call */ void result(unsigned id, QJsonDocument result); void added(QJsonObject item); void changed(QJsonObject item); private slots: void onWSConnected(); void onTextMessageReceived(QString message); void WSclosed(); private: LoginStatus loginStatus() const; void setLoginStatus(LoginStatus l); void resume_login_callback(QJsonDocument doc); QString m_url; QWebSocket m_webSocket; unsigned m_uid; QHash > m_callbackHash; unsigned m_loginJob; LoginStatus m_loginStatus; bool m_connected; bool m_attemptedPasswordLogin; bool m_attemptedTokenLogin; - friend class UserData; + friend class Ruqola; }; // #include "ddpclient.moc" #endif // DDPCLIENT_H diff --git a/src/messagemodel.cpp b/src/messagemodel.cpp index b9e7d74f..f3820512 100644 --- a/src/messagemodel.cpp +++ b/src/messagemodel.cpp @@ -1,211 +1,211 @@ /* * * 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 #include #include #include #include // #include #include #include #include "messagemodel.h" -#include "userdata.h" +#include "ruqola.h" Message MessageModel::fromJSon(const QJsonObject& o) { Message message; message.username = o["username"].toString(); message.message = o["message"].toString(); message.userID = o["userID"].toString(); message.timestamp = (qint64) o["timestamp"].toDouble(); message.systemMessage = o["systemMessage"].toBool(); message.systemMessageType = o["type"].toString(); message.roomID = o["roomID"].toString(); message.messageID = o["messageID"].toString(); return message; } QByteArray MessageModel::serialize(const Message& message) { QJsonDocument d; QJsonObject o; o["username"] = message.username; o["message"] = message.message; o["userID"] = message.userID; o["timestamp"] = message.timestamp; o["systemMessage"] = message.systemMessage; o["type"] = message.systemMessageType; o["roomID"] = message.roomID; o["messageID"] = message.messageID; d.setObject(o); return d.toBinaryData(); } MessageModel::MessageModel(const QString &roomID, QObject* parent) : QAbstractListModel(parent), m_roomID(roomID) { qDebug() << "Creating message Model"; - QDir cacheDir(UserData::self()->cacheBasePath()+"/rooms_cache"); + QDir cacheDir(Ruqola::self()->cacheBasePath()+"/rooms_cache"); // load cache if (QFile::exists(cacheDir.absoluteFilePath(roomID)) && !roomID.isEmpty()) { QFile f(cacheDir.absoluteFilePath(roomID)); if (f.open(QIODevice::ReadOnly)) { QDataStream in(&f); while (!f.atEnd()) { char * byteArray; quint32 length; in.readBytes(byteArray, length); QByteArray arr = QByteArray::fromRawData(byteArray, length); Message m = MessageModel::fromJSon(QJsonDocument::fromBinaryData(arr).object()); addMessage(m); // m_allMessages[m.timestamp] = m; // qDebug() << m.message; } } } } MessageModel::~MessageModel() { - QDir cacheDir(UserData::self()->cacheBasePath()+"/rooms_cache"); + QDir cacheDir(Ruqola::self()->cacheBasePath()+"/rooms_cache"); qDebug() << "Caching to..." << cacheDir.path(); if (!cacheDir.exists(cacheDir.path())) { cacheDir.mkpath(cacheDir.path()); } QFile f(cacheDir.absoluteFilePath(m_roomID)); if (f.open(QIODevice::WriteOnly)) { QDataStream out(&f); foreach (const Message m, m_allMessages) { QByteArray ms = MessageModel::serialize(m); out.writeBytes(ms, ms.size()); } } } QHash MessageModel::roleNames() const { QHash roles; roles[MessageText] = "messageText"; roles[Username] = "username"; roles[Timestamp] = "timestamp"; roles[UserID] = "userID"; roles[SystemMessage] = "systemMessage"; roles[SystemMessageType] = "type"; return roles; } qint64 MessageModel::lastTimestamp() const { if (m_allMessages.size()) { qDebug() << "returning timestamp" << m_allMessages.last().timestamp; return m_allMessages.last().timestamp; } else { return 0; } } int MessageModel::rowCount(const QModelIndex& parent) const { // qDebug() << "C++ asked for rowcount " << m_allMessages.size(); // if (m_allMessages.contains(m_currentRoom)) { return m_allMessages.size(); (void)parent; } void MessageModel::addMessage(const Message& message) { // Don't add empty messages? if (message.message.isEmpty()) { return; } // qDebug() << "MessageModel::addMessage called"; auto existingMessage = qFind(m_allMessages.begin(), m_allMessages.end(), message); bool present = (existingMessage != m_allMessages.end()); auto i = qUpperBound(m_allMessages.begin(), m_allMessages.end(), message); int pos = i-m_allMessages.begin(); bool messageChanged = false; // if (qFind(m_allMessages.begin(), m_allMessages.end(), message) != m_allMessages.end()) { if (present){ // if (pos != m_allMessages.size()) { // we're at the end // qDebug() << "detecting a message change"; messageChanged = true; //Figure out a better way to update just the really changed message } else { beginInsertRows(QModelIndex(), pos, pos); } if (messageChanged) { m_allMessages.replace(pos-1, message); } else { m_allMessages.insert(i, message); } if (messageChanged) { emit dataChanged(createIndex(1, 1), createIndex(pos, 1)); } else { endInsertRows(); } } QVariant MessageModel::data(const QModelIndex& index, int role) const { int idx = index.row();//-1; if (role == MessageModel::Username) { // qDebug() << "C++ returning username" << // m_allMessages[m_currentRoom].values().at(idx).username(); return m_allMessages.at(idx).username; } else if (role == MessageModel::MessageText) { return m_allMessages.at(idx).message; } else if (role == MessageModel::Timestamp) { return QVariant(m_allMessages.at(idx).timestamp); } else if (role == MessageModel::UserID) { return QVariant(m_allMessages.at(idx).userID); } else if (role == MessageModel::SystemMessage) { // qDebug() << "System message?" << m_allMessages.at(idx).systemMessage; return QVariant(m_allMessages.at(idx).systemMessage); } else if (role == MessageModel::SystemMessageType) { return QVariant(m_allMessages.at(idx).systemMessageType); } else { return QVariant(""); } } // #include "messagelist.moc" diff --git a/src/notification.cpp b/src/notification.cpp index 2f945af1..f094aab5 100644 --- a/src/notification.cpp +++ b/src/notification.cpp @@ -1,94 +1,94 @@ /* * * 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 "notification.h" -#include "userdata.h" +#include "ruqola.h" #include #include #include bool Notification::windowVisible() const { return m_windowVisible; } void Notification::setWindowVisible(bool value){ if (m_windowVisible != value){ m_windowVisible = value; emit windowVisibleChanged(); } } QString Notification::message() const { return m_message; } void Notification::setMessage(const QString &message) { if (m_message != message){ m_message = message; emit messageChanged(); } } //create actions in Menu void Notification::createActions(){ m_quitAction = new QAction(tr("&Quit"), this); connect(m_quitAction, &QAction::triggered, qApp, &QCoreApplication::quit); } //create systrayIcon void Notification::createTrayIcon(){ if (!QSystemTrayIcon::isSystemTrayAvailable()) { QMessageBox::critical(0, QObject::tr("Systray"), QObject::tr("Cannot detect SystemTray on this system.")); return; } m_trayIconMenu = new QMenu(); m_trayIconMenu->addAction(m_quitAction); m_trayIconMenu->addSeparator(); this->setContextMenu(m_trayIconMenu); this->setToolTip("Ruqola"); this->setIcon(QIcon(":/systray.png")); this->setVisible(true); } void Notification::updateDesktopNotification() { if (!windowVisible()){ QString title("New Ruqola Message!"); //This can be enhanced later this->showMessage(title, m_message, QSystemTrayIcon::Information, 5000 ); } } Notification::Notification(): m_windowVisible(true){ createActions(); createTrayIcon(); //connect messageChanged signal to updateDesktopNotification Slot connect(this, SIGNAL(messageChanged()), this, SLOT(updateDesktopNotification())); } diff --git a/src/rocketchatbackend.cpp b/src/rocketchatbackend.cpp index 0a3b7e5d..b9e40764 100644 --- a/src/rocketchatbackend.cpp +++ b/src/rocketchatbackend.cpp @@ -1,249 +1,249 @@ /* * * 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 "rocketchatbackend.h" #include #include #include -#include "userdata.h" +#include "ruqola.h" #include "ddpclient.h" void debug_callback(QJsonDocument doc) { qDebug() << "DEBUG:" << doc; } void process_backlog(QJsonDocument messages) { qDebug() << messages.object().value("messages").toArray().size(); RocketChatBackend::processIncomingMessages(messages.object().value("messages").toArray()); } void rooms_callback(QJsonDocument doc) { - RoomModel *model = UserData::self()->roomModel(); + RoomModel *model = Ruqola::self()->roomModel(); QJsonArray removed = doc.object().value("remove").toArray(); QJsonArray updated = doc.object().value("update").toArray(); for (int i = 0; i < updated.size(); i++) { QJsonObject room = updated.at(i).toObject(); if (room.value("t").toString() != "d") { QString roomID = room.value("_id").toString(); - MessageModel *roomModel = UserData::self()->getModelForRoom(roomID); + MessageModel *roomModel = Ruqola::self()->getModelForRoom(roomID); // let's be extra safe around crashes - if (UserData::self()->loginStatus() == DDPClient::LoggedIn) { + if (Ruqola::self()->loginStatus() == DDPClient::LoggedIn) { Room r; r.id = roomID; r.name = room["name"].toString(); r.topic = room["topic"].toString(); qDebug() << "Adding room" << r.name << r.id << r.topic; model->addRoom(r); } QString params = QString("[\"%1\"]").arg(roomID); - UserData::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); + Ruqola::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); // Load history QByteArray json = "[\""+roomID.toLatin1() + "\", null, 50, {\"$date\": " + QString::number(roomModel->lastTimestamp()).toLatin1()+ "}]"; - UserData::self()->ddp()->method("loadHistory", QJsonDocument::fromJson(json), process_backlog); + Ruqola::self()->ddp()->method("loadHistory", QJsonDocument::fromJson(json), process_backlog); } } } void subs_callback(QJsonDocument doc) { - RoomModel *model = UserData::self()->roomModel(); + RoomModel *model = Ruqola::self()->roomModel(); QJsonArray removed = doc.object().value("remove").toArray(); QJsonArray updated = doc.object().value("update").toArray(); for (int i = 0; i < updated.size(); i++) { QJsonObject room = updated.at(i).toObject(); if (room.value("t").toString() != "d") { QString roomID = room.value("rid").toString(); - MessageModel *roomModel = UserData::self()->getModelForRoom(roomID); + MessageModel *roomModel = Ruqola::self()->getModelForRoom(roomID); // let's be extra safe around crashes - if (UserData::self()->loginStatus() == DDPClient::LoggedIn) { + if (Ruqola::self()->loginStatus() == DDPClient::LoggedIn) { Room r; r.id = roomID; r.name = room["name"].toString(); r.topic = room["topic"].toString(); qDebug() << "Adding room" << r.name << r.id << r.topic; model->addRoom(r); } QString params = QString("[\"%1\"]").arg(roomID); - UserData::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); + Ruqola::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); // Load history QByteArray json = "[\""+roomID.toLatin1() + "\", null, 50, {\"$date\": " + QString::number(roomModel->lastTimestamp()).toLatin1()+ "}]"; - UserData::self()->ddp()->method("loadHistory", QJsonDocument::fromJson(json), process_backlog); + Ruqola::self()->ddp()->method("loadHistory", QJsonDocument::fromJson(json), process_backlog); } } } void RocketChatBackend::processIncomingMessages(QJsonArray messages) { foreach (const QJsonValue v, messages) { QJsonObject o = v.toObject(); Message m; QString roomId = o.value("rid").toString(); QString type = o.value("t").toString(); m.username = o.value("u").toObject().value("username").toString(); m.userID = o.value("u").toObject().value("_id").toString(); m.message = o.value("msg").toString(); m.messageID = o.value("_id").toString(); m.roomID = roomId; m.timestamp = (qint64)o.value("ts").toObject().value("$date").toDouble(); if (!type.isEmpty()) { m.systemMessage = true; m.systemMessageType = type; } else { m.systemMessage = false; } - UserData::self()->getModelForRoom(roomId)->addMessage(m); + Ruqola::self()->getModelForRoom(roomId)->addMessage(m); // qDebug() << "RocketChatBackend::processIncomingMessages sending notification"; //Send notifications only when user is logged in - if ( UserData::self()->loginStatus() == DDPClient::LoggedIn) { + if ( Ruqola::self()->loginStatus() == DDPClient::LoggedIn) { QString userName = m.username; QString message = m.message; QString param = QString("%1 \n %2").arg(userName).arg(message); - UserData::self()->notification()->setMessage(param); + Ruqola::self()->notification()->setMessage(param); } else { qDebug() << m.username << " recieved message: " << m.message; } } } RocketChatBackend::RocketChatBackend(QObject* parent) : QObject(parent) { - connect(UserData::self(), &UserData::loginStatusChanged, this, &RocketChatBackend::onLoginStatusChanged); - connect(UserData::self(), &UserData::userIDChanged, this, &RocketChatBackend::onUserIDChanged); - connect(UserData::self()->ddp(), &DDPClient::changed, this, &RocketChatBackend::onChanged); - connect(UserData::self()->ddp(), &DDPClient::added, this, &RocketChatBackend::onAdded); + connect(Ruqola::self(), &Ruqola::loginStatusChanged, this, &RocketChatBackend::onLoginStatusChanged); + connect(Ruqola::self(), &Ruqola::userIDChanged, this, &RocketChatBackend::onUserIDChanged); + connect(Ruqola::self()->ddp(), &DDPClient::changed, this, &RocketChatBackend::onChanged); + connect(Ruqola::self()->ddp(), &DDPClient::added, this, &RocketChatBackend::onAdded); } RocketChatBackend::~RocketChatBackend() { } void RocketChatBackend::onLoginStatusChanged() { - if (UserData::self()->loginStatus() == DDPClient::LoggedIn) { + if (Ruqola::self()->loginStatus() == DDPClient::LoggedIn) { qDebug() << "GETTING LIST OF ROOMS"; -// UserData::self()->ddp()->method("subscriptions/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); - UserData::self()->ddp()->method("rooms/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); +// Ruqola::self()->ddp()->method("subscriptions/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); + Ruqola::self()->ddp()->method("rooms/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); -// UserData::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); +// Ruqola::self()->ddp()->subscribe("stream-room-messages", QJsonDocument::fromJson(params.toLatin1())); } } void RocketChatBackend::onLoggedIn() { -// if (UserData::self()->loginStatus() != DDPClient::LoggedIn) { -// qDebug() << "not yet logged in:" << UserData::self()->loginStatus(); +// if (Ruqola::self()->loginStatus() != DDPClient::LoggedIn) { +// qDebug() << "not yet logged in:" << Ruqola::self()->loginStatus(); // return; // } // // get list of rooms -// UserData::self()->ddp()->method("rooms/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); +// Ruqola::self()->ddp()->method("rooms/get", QJsonDocument::fromJson("{\"$date\": 0}"), rooms_callback); } void RocketChatBackend::onAdded(QJsonObject object) { QString collection = object.value("collection").toString(); // qDebug() << "ROCKET BACK" << object << collection; if (collection == "stream-room-messages") { } else if (collection == "users") { if (object["username"].isNull()) { // it's us! get ID - UserData::self()->setUserID(object["id"].toString()); + Ruqola::self()->setUserID(object["id"].toString()); } qDebug() << "NEW USER ADDED: " << object.value("userName").toString(); } else if (collection == "rooms") { } else if (collection == "stream-notify-user"){ } } void RocketChatBackend::onChanged(QJsonObject object) { QString collection = object["collection"].toString(); // qDebug() << "ROCKET CHAT BACK onChanged" << object << collection; if (collection == "stream-room-messages") { QJsonObject fields = object.value("fields").toObject(); QString roomId = fields.value("eventName").toString(); QJsonArray contents = fields.value("args").toArray(); RocketChatBackend::processIncomingMessages(contents); } else if (collection == "users") { qDebug() << "USER CHANGED"; } else if (collection == "rooms") { } else if (collection == "stream-notify-user"){ } } void RocketChatBackend::onUserIDChanged() { qDebug() << "subscribing to notification feed"; - QString params = QString("[\"%1/%2\"]").arg(UserData::self()->userID()).arg(QString("notification")); - UserData::self()->ddp()->subscribe("stream-notify-user", QJsonDocument::fromJson(params.toLatin1())); + QString params = QString("[\"%1/%2\"]").arg(Ruqola::self()->userID()).arg(QString("notification")); + Ruqola::self()->ddp()->subscribe("stream-notify-user", QJsonDocument::fromJson(params.toLatin1())); } diff --git a/src/roommodel.cpp b/src/roommodel.cpp index aa2397bf..688673e2 100644 --- a/src/roommodel.cpp +++ b/src/roommodel.cpp @@ -1,233 +1,233 @@ /* * * 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 "roommodel.h" -#include "userdata.h" +#include "ruqola.h" #include #include Room RoomModel::fromJSon(const QJsonObject& o) { Room r; r.name = o["name"].toString(); r.id = o["id"].toString(); r.unread = o["unread"].toInt(0); return r; } QByteArray RoomModel::serialize(const Room& r) { QJsonDocument d; QJsonObject o; o["name"] = r.name; o["id"] = r.id; o["unread"] = r.unread; d.setObject(o); return d.toBinaryData(); } RoomWrapper::RoomWrapper(QObject *parent) : QObject(parent) {} RoomWrapper::RoomWrapper(const Room &r, QObject *parent) : QObject(parent) { m_name = r.name; m_topic = r.topic; m_unread = r.unread; m_id = r.id; m_selected = r.selected; } RoomModel::RoomModel(QObject* parent) : QAbstractListModel(parent) { -// connect(UserData::self(), &UserData::loginStatusChanged, this, &RoomModel::onLoginStatusChanged); +// connect(Ruqola::self(), &Ruqola::loginStatusChanged, this, &RoomModel::onLoginStatusChanged); } RoomModel::~RoomModel() { - QDir cacheDir(UserData::self()->cacheBasePath()); + QDir cacheDir(Ruqola::self()->cacheBasePath()); if (!cacheDir.exists(cacheDir.path())) { cacheDir.mkpath(cacheDir.path()); } QFile f(cacheDir.absoluteFilePath("rooms")); if (f.open(QIODevice::WriteOnly)) { QDataStream out(&f); foreach (const Room m, m_roomsList) { QByteArray ms = RoomModel::serialize(m); out.writeBytes(ms, ms.size()); } } } void RoomModel::clear() { if (m_roomsList.size()) { beginRemoveRows(QModelIndex(), 0, rowCount()-1); m_roomsList.clear(); QAbstractItemModel::endRemoveRows(); } } RoomWrapper* RoomModel::findRoom(const QString& roomID) const { foreach (const Room r, m_roomsList) { if (r.id == roomID) { return new RoomWrapper(r); } } Room r; return new RoomWrapper(r); } // Clear data and refill it with data in the cache, if there is void RoomModel::reset() { - if (UserData::self()->cacheBasePath().isEmpty()) { + if (Ruqola::self()->cacheBasePath().isEmpty()) { return; } clear(); - QDir cacheDir(UserData::self()->cacheBasePath()); + QDir cacheDir(Ruqola::self()->cacheBasePath()); // load cache if (cacheDir.exists(cacheDir.path())) { QFile f(cacheDir.absoluteFilePath("rooms")); if (f.open(QIODevice::ReadOnly)) { QDataStream in(&f); while (!f.atEnd()) { char * byteArray; quint32 length; in.readBytes(byteArray, length); QByteArray arr = QByteArray::fromRawData(byteArray, length); Room m = RoomModel::fromJSon(QJsonDocument::fromBinaryData(arr).object()); addRoom(m.id, m.name, m.selected); } } qDebug() << "Cache Loaded"; } } QHash RoomModel::roleNames() const { QHash roles; roles[RoomName] = "name"; roles[RoomID] = "room_id"; roles[RoomSelected] = "selected"; roles[RoomUnread] = "unread"; return roles; } int RoomModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent); // if (m_roomsHash.size() > 4) {return 4;} // qDebug() << m_roomsList.size() << "ROOMS"; return m_roomsList.size(); } QVariant RoomModel::data(const QModelIndex & index, int role) const { Room r = m_roomsList.at(index.row()); if (role == RoomModel::RoomName) { return r.name; } else if (role == RoomModel::RoomID) { return r.id; } else if (role == RoomModel::RoomSelected) { return r.selected; } else { return QVariant("0"); } } // void RoomModel::setActiveRoom(const QString& activeRoom) // { // foreach (const QString &id, m_roomsHash.keys()) { // qDebug() << id; // m_roomsHash[id].selected = (id == activeRoom); // } // // emit dataChanged(createIndex(1, 1), createIndex(rowCount(), 1)); // } void RoomModel::addRoom(const QString& roomID, const QString& roomName, bool selected) { if (roomID.isEmpty() || roomName.isEmpty()) { return; } qDebug() << "Adding room" << roomID << roomName; Room r; r.id = roomID; r.name = roomName; r.selected = selected; addRoom(r); } void RoomModel::addRoom(const Room &room) { auto existingRoom = qFind(m_roomsList.begin(), m_roomsList.end(), room); bool present = (existingRoom != m_roomsList.end()); auto i = qUpperBound(m_roomsList.begin(), m_roomsList.end(), room); int pos = i-m_roomsList.begin(); bool roomChanged = false; qDebug() << pos; // if (qFind(m_roomsList.begin(), m_roomsList.end(), room) != m_roomsList.end() && pos > 0) { if (present) { // qDebug() << (qFind(m_roomsList.begin(), m_roomsList.end(), room) - m_roomsList.begin()); // if (pos != m_roomsList.size()) { // we're at the end qDebug() << "Room changed!"; roomChanged = true; //Figure out a better way to update just the really changed message } else { beginInsertRows(QModelIndex(), pos, pos); } if (roomChanged) { m_roomsList.replace(pos-1, room); } else { qDebug() << "Inserting room at position" <getModelForRoom(room.id); + Ruqola::self()->getModelForRoom(room.id); } // #include "roommodel.moc" diff --git a/src/userdata.cpp b/src/ruqola.cpp similarity index 78% rename from src/userdata.cpp rename to src/ruqola.cpp index eb939a4c..2b7c5944 100644 --- a/src/userdata.cpp +++ b/src/ruqola.cpp @@ -1,243 +1,243 @@ /* * * 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 "userdata.h" +#include "ruqola.h" #include "roommodel.h" #include "ddpclient.h" #include "notification.h" -UserData *UserData::m_self = 0; +Ruqola *Ruqola::m_self = 0; -QString UserData::authToken() const +QString Ruqola::authToken() const { return m_authToken; } -QString UserData::userName() const +QString Ruqola::userName() const { return m_userName; } -QString UserData::userID() const +QString Ruqola::userID() const { return m_userID; } -QString UserData::password() const +QString Ruqola::password() const { return m_password; } -void UserData::setAuthToken(const QString& token) +void Ruqola::setAuthToken(const QString& token) { qDebug() << "Setting token to" << token; QSettings s; m_authToken = token; s.setValue("authToken", token); } -void UserData::setPassword(const QString& password) +void Ruqola::setPassword(const QString& password) { m_password = password; } -void UserData::setUserName(const QString& username) +void Ruqola::setUserName(const QString& username) { m_userName = username; QSettings s; s.setValue("username", username); emit userNameChanged(); } -void UserData::setUserID(const QString& userID) +void Ruqola::setUserID(const QString& userID) { m_userName = userID; QSettings s; s.setValue("userID", userID); emit userIDChanged(); } -RoomModel * UserData::roomModel() +RoomModel * Ruqola::roomModel() { if (!m_roomModel) { qDebug() << "creating new RoomModel"; m_roomModel = new RoomModel(this); qDebug() << m_roomModel; } return m_roomModel; } -DDPClient * UserData::ddp() +DDPClient * Ruqola::ddp() { if (!m_ddp) { m_ddp = new DDPClient(serverURL()); - connect(m_ddp, &DDPClient::loginStatusChanged, this, &UserData::loginStatusChanged); + connect(m_ddp, &DDPClient::loginStatusChanged, this, &Ruqola::loginStatusChanged); // connect(m_ddp, &DDPClient::loginStatusChanged, this, [=](){qDebug() << "Signal received";}); } return m_ddp; } -Notification * UserData::notification() +Notification * Ruqola::notification() { if (m_notification == NULL) { m_notification = new Notification(); m_notification->show(); } return m_notification; } -void UserData::sendMessage(const QString &roomID, const QString &message) +void Ruqola::sendMessage(const QString &roomID, const QString &message) { QString json = "{\"rid\": \"%1\", \"msg\": \"%2\"}"; json = json.arg(roomID, message); ddp()->method("sendMessage", QJsonDocument::fromJson(json.toUtf8())); } -MessageModel * UserData::getModelForRoom(const QString& roomID) +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 UserData::serverURL() const +QString Ruqola::serverURL() const { return m_serverURL; } -void UserData::setServerURL(const QString& 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 UserData::loginStatus() +DDPClient::LoginStatus Ruqola::loginStatus() { if (m_ddp) { return ddp()->loginStatus(); } else { return DDPClient::LoggedOut; } } -void UserData::tryLogin() +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 UserData::logOut() +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 UserData::cacheBasePath() const +QString Ruqola::cacheBasePath() const { if (m_serverURL.isEmpty()) { return QString(); } return QStandardPaths::writableLocation(QStandardPaths::CacheLocation)+'/'+m_serverURL; } -// QString UserData::activeRoom() const +// QString Ruqola::activeRoom() const // { // return m_activeRoom; // } -// void UserData::setActiveRoom(const QString& activeRoom) +// void Ruqola::setActiveRoom(const QString& activeRoom) // { // m_activeRoom = activeRoom; // // roomModel()->setActiveRoom(activeRoom); // emit activeRoomChanged(); // } -RoomWrapper * UserData::getRoom(const QString& roomID) +RoomWrapper * Ruqola::getRoom(const QString& roomID) { return roomModel()->findRoom(roomID); } -UserData::UserData(QObject* parent): QObject(parent), m_ddp(0), m_roomModel(0), m_notification(0) +Ruqola::Ruqola(QObject* parent): QObject(parent), m_ddp(0), m_roomModel(0), m_notification(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(); } -UserData * UserData::self() +Ruqola * Ruqola::self() { if (!m_self) { - m_self = new UserData; + 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(); } return m_self; } diff --git a/src/userdata.h b/src/ruqola.h similarity index 92% rename from src/userdata.h rename to src/ruqola.h index 7156ca05..29127870 100644 --- a/src/userdata.h +++ b/src/ruqola.h @@ -1,118 +1,118 @@ /* * * 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" class QString; -class UserData: public QObject +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 UserData* self(); + 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(); Q_INVOKABLE RoomModel *roomModel(); Q_INVOKABLE void sendMessage(const QString &roomID, const QString &message); Q_INVOKABLE MessageModel* getModelForRoom(const QString &roomID); Q_INVOKABLE void tryLogin(); Q_INVOKABLE void logOut(); Q_INVOKABLE RoomWrapper* getRoom(const QString &roomID); // void setRoomModel(); QString cacheBasePath() const; signals: void userNameChanged(); void userIDChanged(); void serverURLChanged(); void loginStatusChanged(); private: - UserData(QObject *parent = 0); - static UserData *m_self; + 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; RoomModel *m_roomModel; Notification *m_notification; QHash< QString, MessageModel * > m_messageModels; }; -inline static QObject *userdata_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +inline static QObject *ruqola_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) - UserData *userData = UserData::self(); + Ruqola *userData = Ruqola::self(); return userData; } #endif // USERDATA_H