diff --git a/retroshare-qml-app/src/libresapilocalclient.cpp b/retroshare-qml-app/src/libresapilocalclient.cpp index f30b3373c..29b7e7014 100644 --- a/retroshare-qml-app/src/libresapilocalclient.cpp +++ b/retroshare-qml-app/src/libresapilocalclient.cpp @@ -1,6 +1,6 @@ /* * RetroShare Android QML App - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * Copyright (C) 2016 Manu Pineda * * This program is free software: you can redistribute it and/or modify @@ -38,9 +38,7 @@ int LibresapiLocalClient::request( const QString& path, const QString& jsonData, data.append(path); data.append('\n'); data.append(jsonData); data.append('\n'); callbackQueue.enqueue(callback); - mLocalSocket.write(data); - - return 1; + return mLocalSocket.write(data); } void LibresapiLocalClient::socketError(QLocalSocket::LocalSocketError) diff --git a/retroshare-qml-app/src/main.cpp b/retroshare-qml-app/src/main.cpp index 0be8e7b15..9b7d9226b 100644 --- a/retroshare-qml-app/src/main.cpp +++ b/retroshare-qml-app/src/main.cpp @@ -1,6 +1,6 @@ /* * RetroShare Android QML App - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -39,7 +39,8 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; - /// @deprecated + /** When possible it is better to use +rsApi+ object directly instead of + * multiple instances of +LibresapiLocalClient+ in Qml */ qmlRegisterType( "org.retroshare.qml_components.LibresapiLocalClient", 1, 0, "LibresapiLocalClient"); @@ -55,7 +56,8 @@ int main(int argc, char *argv[]) engine.load(QUrl(QLatin1String("qrc:/qml/main.qml"))); QFileInfo fileInfo(sockPath); - qDebug() << "QML APP:" << sockPath << fileInfo.exists() << fileInfo.lastModified().toString(); + qDebug() << "QML APP:" << sockPath << fileInfo.exists() + << fileInfo.lastModified().toString(); return app.exec(); } diff --git a/retroshare-qml-app/src/qml.qrc b/retroshare-qml-app/src/qml.qrc index 594c556fd..ee37d10d5 100644 --- a/retroshare-qml-app/src/qml.qrc +++ b/retroshare-qml-app/src/qml.qrc @@ -1,10 +1,6 @@ qml/main.qml - qml/icons/star-2-128.png - qml/icons/settings-4-128.png - qml/icons/email-128.png - qml/icons/contacts-128.png qml/Locations.qml qml/jsonpath.js qml/JSONListModel.qml @@ -13,5 +9,9 @@ qml/RsLoginPassView.qml qml/TrustedNodesView.qml qml/ChatView.qml + qml/icons/retroshare06.png + qml/icons/remove-link.png + qml/icons/state-offline.png + qml/icons/state-ok.png diff --git a/retroshare-qml-app/src/qml/ChatView.qml b/retroshare-qml-app/src/qml/ChatView.qml index 4a06b6dd9..9a4c4314b 100644 --- a/retroshare-qml-app/src/qml/ChatView.qml +++ b/retroshare-qml-app/src/qml/ChatView.qml @@ -1,3 +1,21 @@ +/* + * RetroShare Android QML App + * Copyright (C) 2016-2017 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + import QtQuick 2.0 import QtQuick.Controls 1.4 import org.retroshare.qml_components.LibresapiLocalClient 1.0 @@ -43,16 +61,7 @@ Item delegate: chatMessageDelegate } - Rectangle - { - color: "green" - anchors.bottom: parent.bottom - anchors.left: parent.left - width: chatView.width - sendButton.width - height: Math.max(20, msgComposer.height) - } - - TextEdit + TextField { id: msgComposer anchors.bottom: parent.bottom diff --git a/retroshare-qml-app/src/qml/Contacts.qml b/retroshare-qml-app/src/qml/Contacts.qml index 4ecd267ef..6a00257f8 100644 --- a/retroshare-qml-app/src/qml/Contacts.qml +++ b/retroshare-qml-app/src/qml/Contacts.qml @@ -1,6 +1,6 @@ /* * RetroShare Android QML App - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -29,7 +29,15 @@ Item Component.onCompleted: refreshOwn() - function refreshData() { rsApi.request("/identity/*/", "", function(par) { locationsModel.json = par.response; if(contactsView.own_gxs_id == "") refreshOwn() }) } + function refreshData() + { + function refreshCallback(par) + { + locationsModel.json = par.response + if(contactsView.own_gxs_id == "") refreshOwn() + } + rsApi.request("/identity/*/", "", refreshCallback) + } function refreshOwn() { rsApi.request("/identity/own", "", function(par) @@ -43,6 +51,14 @@ Item else createIdentityDialog.visible = true }) } + function startChatCallback(par) + { + var chId = JSON.parse(par.response).data.chat_id + stackView.push({ + item:"qrc:/qml/ChatView.qml", + properties: {chatId: chId} + }) + } onFocusChanged: focus && refreshData() @@ -68,12 +84,16 @@ Item anchors.fill: parent onClicked: { - console.log("Contacts view onclicked:", model.name, model.gxs_id) + console.log("Contacts view onclicked:", model.name, + model.gxs_id) if(model.own) contactsView.own_gxs_id = model.gxs_id else { - var jsonData = { "own_gxs_hex": contactsView.own_gxs_id, "remote_gxs_hex": model.gxs_id } - rsApi.request("/chat/initiate_distant_chat", JSON.stringify(jsonData), function (par) { mainWindow.activeChatId = JSON.parse(par.response).data.chat_id }) + var jsonData = { "own_gxs_hex": contactsView.own_gxs_id, + "remote_gxs_hex": model.gxs_id } + rsApi.request("/chat/initiate_distant_chat", + JSON.stringify(jsonData), + contactsView.startChatCallback) } } Text diff --git a/retroshare-qml-app/src/qml/TrustedNodesView.qml b/retroshare-qml-app/src/qml/TrustedNodesView.qml index 2971bb27f..7f9a3b691 100644 --- a/retroshare-qml-app/src/qml/TrustedNodesView.qml +++ b/retroshare-qml-app/src/qml/TrustedNodesView.qml @@ -1,6 +1,6 @@ /* * RetroShare Android QML App - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -18,17 +18,31 @@ import QtQuick 2.0 import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 import "jsonpath.js" as JSONPath Item { - function refreshData() { rsApi.request("/peers/*", "", function(par) { jsonModel.json = par.response }) } + id: trustedNodesView + + function refreshData() + { + rsApi.request("/peers/*", "", + function(par) { jsonModel.json = par.response }) + } onFocusChanged: focus && refreshData() JSONListModel { id: jsonModel query: "$.data[*]" + + function isOnline(pgpId) + { + var qr = "$.data[?(@.pgp_id=='"+pgpId+"')].locations[*].is_online" + var locArr = JSONPath.jsonPath(JSON.parse(jsonModel.json), qr) + return locArr.reduce(function(cur,acc){return cur || acc}, false) + } } ListView @@ -39,38 +53,92 @@ Item model: jsonModel.model delegate: Item { - height: 50 - Row - { - height: 30 - Text - { - text: model.name - onTextChanged: color = JSONPath.jsonPath(JSON.parse(jsonModel.json), "$.data[?(@.pgp_id=='"+model.pgp_id+"')].locations[*].is_online").reduce(function(cur,acc){return cur || acc}, false) ? "lime" : "darkslategray" - } + height: 30 + width: parent.width - Rectangle + Image + { + id: statusImage + source: jsonModel.isOnline(model.pgp_id) ? + "icons/state-ok.png" : + "icons/state-offline.png" + + height: parent.height - 4 + fillMode: Image.PreserveAspectFit + anchors.leftMargin: 6 + anchors.verticalCenter: parent.verticalCenter + } + Text + { + text: model.name + anchors.verticalCenter: parent.verticalCenter + anchors.left: statusImage.right + anchors.leftMargin: 10 + } + Image + { + source: "icons/remove-link.png" + + height: parent.height - 6 + fillMode: Image.PreserveAspectFit + + anchors.right: parent.right + anchors.rightMargin: 2 + anchors.verticalCenter: parent.verticalCenter + + MouseArea { height: parent.height - width: parent.height - color: "red" - - MouseArea + width: parent.width + onClicked: { - height: parent.height - width: parent.height - onClicked: rsApi.request("/peers/"+model.pgp_id+"/delete") + deleteDialog.nodeName = model.name + deleteDialog.nodeId = model.pgp_id + deleteDialog.visible = true } } } } } + Dialog + { + id: deleteDialog + property string nodeName + property string nodeId + standardButtons: StandardButton.Yes | StandardButton.No + visible: false + onYes: + { + rsApi.request("/peers/"+nodeId+"/delete") + trustedNodesView.refreshData() + trustedNodesView.forceActiveFocus() + } + onNo: trustedNodesView.forceActiveFocus() + Text + { + text: "Are you sure to delete " + deleteDialog.nodeName + " ("+ + deleteDialog.nodeId +") ?" + + width: parent.width - 2 + wrapMode: Text.Wrap + } + } + Button { id: bottomButton text: "Add Trusted Node" anchors.bottom: parent.bottom - onClicked: swipeView.currentIndex = 3 + onClicked: stackView.push({item:"qrc:/qml/AddTrustedNode.qml"}) + width: parent.width + } + + Timer + { + interval: 800 + repeat: true + onTriggered: if(trustedNodesView.visible) trustedNodesView.refreshData() + Component.onCompleted: start() } } diff --git a/retroshare-qml-app/src/qml/icons/remove-link.png b/retroshare-qml-app/src/qml/icons/remove-link.png new file mode 100644 index 000000000..ae3650562 Binary files /dev/null and b/retroshare-qml-app/src/qml/icons/remove-link.png differ diff --git a/retroshare-qml-app/src/qml/icons/retroshare06.png b/retroshare-qml-app/src/qml/icons/retroshare06.png new file mode 120000 index 000000000..5a5721ef1 --- /dev/null +++ b/retroshare-qml-app/src/qml/icons/retroshare06.png @@ -0,0 +1 @@ +../../../../data/128x128/apps/retroshare06.png \ No newline at end of file diff --git a/retroshare-qml-app/src/qml/icons/state-offline.png b/retroshare-qml-app/src/qml/icons/state-offline.png new file mode 100644 index 000000000..b8236bd29 Binary files /dev/null and b/retroshare-qml-app/src/qml/icons/state-offline.png differ diff --git a/retroshare-qml-app/src/qml/icons/state-ok.png b/retroshare-qml-app/src/qml/icons/state-ok.png new file mode 100644 index 000000000..d4e84fdc3 Binary files /dev/null and b/retroshare-qml-app/src/qml/icons/state-ok.png differ diff --git a/retroshare-qml-app/src/qml/main.qml b/retroshare-qml-app/src/qml/main.qml index 37c14d521..079a40a60 100644 --- a/retroshare-qml-app/src/qml/main.qml +++ b/retroshare-qml-app/src/qml/main.qml @@ -1,6 +1,6 @@ /* * RetroShare Android QML App - * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016-2017 Gioacchino Mazzurco * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -24,94 +24,137 @@ ApplicationWindow { id: mainWindow visible: true - title: qsTr("RSChat") + title: "RetroShare" width: 400 height: 400 - property string activeChatId; - - Rectangle + toolBar: ToolBar { - id: mainView - anchors.fill: parent - states: - [ - State - { - name: "waiting_account_select" - PropertyChanges { target: swipeView; currentIndex: 0 } - PropertyChanges { target: locationsTab; enabled: true } - }, - State - { - name: "running_ok" - PropertyChanges { target: swipeView; currentIndex: 1 } - PropertyChanges { target: locationsTab; enabled: false } - }, - State - { - name: "running_ok_no_full_control" - PropertyChanges { target: swipeView; currentIndex: 1 } - PropertyChanges { target: locationsTab; enabled: false } - } - ] - - LibresapiLocalClient + Image { - onGoodResponseReceived: - { - var jsonReponse = JSON.parse(msg) - mainView.state = jsonReponse.data.runstate - } - Component.onCompleted: - { - openConnection(apiSocketPath) - request("/control/runstate/", "") - } + id: rsIcon + fillMode: Image.PreserveAspectFit + height: Math.max(30, parent.height - 4) + anchors.verticalCenter: parent.verticalCenter + source: "icons/retroshare06.png" } - - TabView + Label { - id: swipeView - anchors.fill: parent - visible: true - currentIndex: 0 + text: "RetroShare" + anchors.verticalCenter: parent.verticalCenter + anchors.left: rsIcon.right + anchors.leftMargin: 20 + } + } - Tab + menuBar: MenuBar + { + Menu + { + MenuItem { - title:"Locations" - id: locationsTab - Locations { onVisibleChanged: focus = visible } + text: "Trusted Nodes" + onTriggered: + stackView.push({item:"qrc:/qml/TrustedNodesView.qml"}) } - - Tab + MenuItem { - title: "Trusted Nodes" - TrustedNodesView { onVisibleChanged: focus = visible } - } - - Tab - { - title: "Contacts" - Contacts { onVisibleChanged: focus = visible } - } - - Tab - { - title: "Add Node" - AddTrustedNode { onVisibleChanged: focus = visible } - } - - Tab - { - title: "Chat" - ChatView - { - id: chatView - chatId: mainWindow.activeChatId - onVisibleChanged: focus = visible - } + text: "StackView State" + onTriggered: console.log(stackView.state, stackView.enabled) } } } + + StackView + { + id: stackView + anchors.fill: parent + Keys.onReleased: + if (event.key === Qt.Key_Back && stackView.depth > 1) + { + stackView.pop(); + event.accepted = true; + } + + function checkCoreStatus() + { + function runStateCallback(par) + { + var jsonReponse = JSON.parse(par.response) + var runState = jsonReponse.data.runstate + if(typeof(runState) === 'string') stackView.state = runState + else + { + stackView.state = "core_down" + console.log("runStateCallback(...) core is down") + } + } + var ret = rsApi.request("/control/runstate/", "", runStateCallback) + if ( ret < 1 ) + { + console.log("checkCoreStatus() core is down") + stackView.state = "core_down" + } + } + + Timer + { + id: refreshTimer + interval: 800 + repeat: true + onTriggered: if(stackView.visible) stackView.checkCoreStatus() + Component.onCompleted: start() + } + + state: "core_down" + states: [ + State + { + name: "core_down" + PropertyChanges { target: stackView; enabled: false } + }, + State + { + name: "waiting_account_select" + PropertyChanges { target: stackView; enabled: true } + StateChangeScript + { + script: + { + console.log("StateChangeScript waiting_account_select") + stackView.clear() + stackView.push({item:"qrc:/qml/Locations.qml"}) + } + } + }, + State + { + name: "running_ok" + PropertyChanges { target: stackView; enabled: true } + StateChangeScript + { + script: + { + console.log("StateChangeScript waiting_account_select") + stackView.clear() + stackView.push({item: "qrc:/qml/Contacts.qml"}) + } + } + }, + State + { + name: "running_ok_no_full_control" + PropertyChanges { target: stackView; state: "running_ok" } + } + ] + + initialItem: Rectangle + { + anchors.fill: parent + color: "green" + border.color: "black" + + Text { text: "Connecting to core..." } + } + } } diff --git a/retroshare-qml-app/src/retroshare-qml-app.pro b/retroshare-qml-app/src/retroshare-qml-app.pro index c878a8b09..ecdb19346 100644 --- a/retroshare-qml-app/src/retroshare-qml-app.pro +++ b/retroshare-qml-app/src/retroshare-qml-app.pro @@ -23,7 +23,8 @@ DISTFILES += \ android/res/values/libs.xml \ android/build.gradle \ android/gradle/wrapper/gradle-wrapper.properties \ - android/gradlew.bat + android/gradlew.bat \ + qml/icons/retroshare06.png ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android