From 00be891d3b0cb401e642a5331aedcc399641b8ef Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Mon, 31 May 2021 01:49:43 +0200 Subject: [refactor] unclutter main qml --- gui/qml/BackgroundImage.qml | 15 +++++ gui/qml/BridgesItem.qml | 58 ++++++++++++++++ gui/qml/LocationText.qml | 8 +++ gui/qml/MainBar.qml | 16 +++++ gui/qml/VPNSwitch.qml | 64 ++++++++++++++++++ gui/qml/VpnState.qml | 42 +++++++----- gui/qml/logic.js | 39 +++++++++++ gui/qml/main.qml | 156 ++++++-------------------------------------- 8 files changed, 247 insertions(+), 151 deletions(-) create mode 100644 gui/qml/BackgroundImage.qml create mode 100644 gui/qml/BridgesItem.qml create mode 100644 gui/qml/LocationText.qml create mode 100644 gui/qml/MainBar.qml create mode 100644 gui/qml/VPNSwitch.qml create mode 100644 gui/qml/logic.js (limited to 'gui/qml') diff --git a/gui/qml/BackgroundImage.qml b/gui/qml/BackgroundImage.qml new file mode 100644 index 0000000..86b8cba --- /dev/null +++ b/gui/qml/BackgroundImage.qml @@ -0,0 +1,15 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.4 + +Rectangle { + + anchors.fill: parent; + anchors.topMargin: 40; + + Image { + source: "qrc:/assets/img/bird.jpg"; + fillMode: Image.PreserveAspectCrop; + anchors.fill: parent; + opacity: 0.8; + } +} diff --git a/gui/qml/BridgesItem.qml b/gui/qml/BridgesItem.qml new file mode 100644 index 0000000..1cf152c --- /dev/null +++ b/gui/qml/BridgesItem.qml @@ -0,0 +1,58 @@ +import QtQuick 2.9 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.4 + +import "logic.js" as Logic + +Item { + + anchors.centerIn: parent + width: parent.width + property alias displayReconnect: bridgeReconnect.visible + + Column { + + anchors.centerIn: parent + spacing: 10 + width: parent.width + + CheckBox { + id: bridgeCheck + checked: false + text: qsTr("Use obfs4 bridges") + font.pixelSize: 14 + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + if (checked) { + Logic.setNeedsReconnect(true); + bridgeReconnect.visible = true; + } else { + // This would also need a "needs reconnect" for de-selecting bridges the next time. + // better to wait and see the new connection widgets though + Logic.setNeedsReconnect(false); + bridgeReconnect.visible = false; + } + } + } + + Text { + id: bridgesInfo + width: 250 + color: "grey" + text: qsTr("Select a bridge only if you know that you need it to evade censorship in your country or local network.") + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WordWrap + } + + Text { + id: bridgeReconnect + width: 250 + font.pixelSize: 12 + color: "red" + text: qsTr("We will attempt to connect to a bridge the next time you connect to the VPN.") + anchors.horizontalCenter: parent.horizontalCenter + wrapMode: Text.WordWrap + visible: false; + } + } +} diff --git a/gui/qml/LocationText.qml b/gui/qml/LocationText.qml new file mode 100644 index 0000000..883a8a4 --- /dev/null +++ b/gui/qml/LocationText.qml @@ -0,0 +1,8 @@ +import QtQuick 2.9 + +Text { + font.pixelSize: 10 + color: "black" + text: qsTr("Location has been manually set.") + anchors.horizontalCenter: parent.horizontalCenter +} diff --git a/gui/qml/MainBar.qml b/gui/qml/MainBar.qml new file mode 100644 index 0000000..1f28bac --- /dev/null +++ b/gui/qml/MainBar.qml @@ -0,0 +1,16 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.4 + +TabBar { + //id: bar + width: parent.width + TabButton { + text: qsTr("Status") + } + TabButton { + text: qsTr("Location") + } + TabButton { + text: qsTr("Bridges") + } +} diff --git a/gui/qml/VPNSwitch.qml b/gui/qml/VPNSwitch.qml new file mode 100644 index 0000000..14b3734 --- /dev/null +++ b/gui/qml/VPNSwitch.qml @@ -0,0 +1,64 @@ +import QtQuick 2.9 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.4 + + +SwitchDelegate { + + //id: vpntoggle + + text: qsTr("") + checked: false + anchors.horizontalCenter: parent.horizontalCenter + + /* + Connections { + function onCheckedChanged() { + if (vpntoggle.checked == true + && ctx.status == "off") { + backend.switchOn() + } + if (vpntoggle.checked === false + && ctx.status == "on") { + backend.switchOff() + } + } + } + */ + + contentItem: Text { + rightPadding: vpntoggle.indicator.width + vpntoggle.spacing + text: vpntoggle.text + font: vpntoggle.font + opacity: enabled ? 1.0 : 0.5 + color: vpntoggle.down ? "#17a81a" : "#21be2b" + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + + indicator: Rectangle { + implicitWidth: 48 + implicitHeight: 26 + x: vpntoggle.width - width - vpntoggle.rightPadding + y: parent.height / 2 - height / 2 + radius: 13 + color: vpntoggle.checked ? "#17a81a" : "transparent" + border.color: vpntoggle.checked ? "#17a81a" : "#cccccc" + + Rectangle { + x: vpntoggle.checked ? parent.width - width : 0 + width: 26 + height: 26 + radius: 13 + color: vpntoggle.down ? "#cccccc" : "#ffffff" + border.color: vpntoggle.checked ? (vpntoggle.down ? "#17a81a" : "#21be2b") : "#999999" + } + } + + background: Rectangle { + implicitWidth: 100 + implicitHeight: 40 + visible: vpntoggle.down || vpntoggle.highlighted + color: vpntoggle.down ? "#17a81a" : "#eeeeee" + } +} // end switchdelegate diff --git a/gui/qml/VpnState.qml b/gui/qml/VpnState.qml index e1a183c..332dcaa 100644 --- a/gui/qml/VpnState.qml +++ b/gui/qml/VpnState.qml @@ -1,6 +1,8 @@ import QtQuick 2.0 import QtQuick.Controls 2.12 +import "logic.js" as Logic + StateGroup { state: ctx ? ctx.status : "" @@ -11,9 +13,12 @@ StateGroup { }, State { name: "off" + StateChangeScript { + script: Logic.setStatus("off"); + } PropertyChanges { target: systray - tooltip: toHuman("off") + tooltip: Logic.toHuman("off") icon.source: icons["off"] } PropertyChanges { @@ -22,15 +27,15 @@ StateGroup { } PropertyChanges { target: statusItem - text: toHuman("off") + text: Logic.toHuman("off") } PropertyChanges { target: autoSelectionItem - text: qsTr("Best") + text: qsTr("Recommended") } PropertyChanges { target: mainStatus - text: toHuman("off") + text: Logic.toHuman("off") } PropertyChanges { target: mainCurrentGateway @@ -39,9 +44,16 @@ StateGroup { }, State { name: "on" + StateChangeScript { + script: { + Logic.setNeedsReconnect(false); + brReconnect = false; + } + + } PropertyChanges { target: systray - tooltip: toHuman("on") + tooltip: Logic.toHuman("on") icon.source: icons["on"] } PropertyChanges { @@ -50,7 +62,7 @@ StateGroup { } PropertyChanges { target: statusItem - text: toHuman("on") + text: Logic.toHuman("on") } PropertyChanges { target: autoSelectionItem @@ -65,7 +77,7 @@ StateGroup { } PropertyChanges { target: mainStatus - text: toHuman("on") + text: Logic.toHuman("on") } PropertyChanges { target: mainCurrentGateway @@ -77,12 +89,12 @@ StateGroup { name: "starting" PropertyChanges { target: systray - tooltip: toHuman("connecting") + tooltip: Logic.toHuman("connecting") icon.source: icons["wait"] } PropertyChanges { target: statusItem - text: toHuman("connecting") + text: Logic.toHuman("connecting") } PropertyChanges { target: autoSelectionItem @@ -108,12 +120,12 @@ StateGroup { name: "stopping" PropertyChanges { target: systray - tooltip: toHuman("stopping") + tooltip: Logic.toHuman("stopping") icon.source: icons["wait"] } PropertyChanges { target: statusItem - text: toHuman("stopping") + text: Logic.toHuman("stopping") } PropertyChanges { target: autoSelectionItem @@ -121,7 +133,7 @@ StateGroup { } PropertyChanges { target: mainStatus - text: toHuman("stopping") + text: Logic.toHuman("stopping") } PropertyChanges { target: mainCurrentGateway @@ -132,12 +144,12 @@ StateGroup { name: "failed" PropertyChanges { target: systray - tooltip: toHuman("failed") + tooltip: Logic.toHuman("failed") icon.source: icons["wait"] } PropertyChanges { target: statusItem - text: toHuman("failed") + text: Logic.toHuman("failed") } PropertyChanges { target: autoSelectionItem @@ -145,7 +157,7 @@ StateGroup { } PropertyChanges { target: mainStatus - text: toHuman("failed") + text: Logic.toHuman("failed") } PropertyChanges { target: mainCurrentGateway diff --git a/gui/qml/logic.js b/gui/qml/logic.js new file mode 100644 index 0000000..4fdbb99 --- /dev/null +++ b/gui/qml/logic.js @@ -0,0 +1,39 @@ +let status = 'off'; +let needsReconnect = false; + +function setStatus(st) { + status = st; +} + +function getStatus() { + return status; +} + +function setNeedsReconnect(val) { + needsReconnect = val; +} + +function getNeedsReconnect() { + return needsReconnect; +} + +function toHuman(st) { + switch (st) { + case "off": + //: %1 -> application name + return qsTr("%1 off").arg(ctx.appName) + case "on": + //: %1 -> application name + return qsTr("%1 on").arg(ctx.appName) + case "connecting": + //: %1 -> application name + return qsTr("Connecting to %1").arg(ctx.appName) + case "stopping": + //: %1 -> application name + return qsTr("Stopping %1").arg(ctx.appName) + case "failed": + //: %1 -> application name + return qsTr("%1 blocking internet").arg( + ctx.appName) // TODO failed is not handed yet + } +} diff --git a/gui/qml/main.qml b/gui/qml/main.qml index 7048a81..f75a121 100644 --- a/gui/qml/main.qml +++ b/gui/qml/main.qml @@ -5,6 +5,8 @@ import QtQuick.Controls 2.4 import Qt.labs.platform 1.0 +import "logic.js" as Logic + ApplicationWindow { id: app visible: true @@ -18,26 +20,16 @@ ApplicationWindow { property var ctx property var loginDone property var allowEmptyPass + property var needsRestart + onSceneGraphError: function(error, msg) { console.debug("ERROR while initializing scene") console.debug(msg) } - // TODO refactor into discrete components. - - TabBar { + MainBar { id: bar - width: parent.width - TabButton { - text: qsTr("Status") - } - TabButton { - text: qsTr("Location") - } - TabButton { - text: qsTr("Bridges") - } } StackLayout { @@ -50,17 +42,8 @@ ApplicationWindow { id: infoTab anchors.centerIn: parent - Rectangle { + BackgroundImage { id: background - anchors.fill: parent; - anchors.topMargin: 40; - - Image { - source: "qrc:/assets/img/bird.jpg"; - fillMode: Image.PreserveAspectCrop; - anchors.fill: parent; - opacity: 0.8; - } } Item { @@ -96,14 +79,9 @@ ApplicationWindow { anchors.horizontalCenter: parent.horizontalCenter } - SwitchDelegate { - + VPNSwitch { id: vpntoggle - text: qsTr("") - checked: false - anchors.horizontalCenter: parent.horizontalCenter - Connections { function onCheckedChanged() { if (vpntoggle.checked == true @@ -116,50 +94,10 @@ ApplicationWindow { } } } + } - contentItem: Text { - rightPadding: vpntoggle.indicator.width + vpntoggle.spacing - text: vpntoggle.text - font: vpntoggle.font - opacity: enabled ? 1.0 : 0.5 - color: vpntoggle.down ? "#17a81a" : "#21be2b" - elide: Text.ElideRight - verticalAlignment: Text.AlignVCenter - } - - indicator: Rectangle { - implicitWidth: 48 - implicitHeight: 26 - x: vpntoggle.width - width - vpntoggle.rightPadding - y: parent.height / 2 - height / 2 - radius: 13 - color: vpntoggle.checked ? "#17a81a" : "transparent" - border.color: vpntoggle.checked ? "#17a81a" : "#cccccc" - - Rectangle { - x: vpntoggle.checked ? parent.width - width : 0 - width: 26 - height: 26 - radius: 13 - color: vpntoggle.down ? "#cccccc" : "#ffffff" - border.color: vpntoggle.checked ? (vpntoggle.down ? "#17a81a" : "#21be2b") : "#999999" - } - } - - background: Rectangle { - implicitWidth: 100 - implicitHeight: 40 - visible: vpntoggle.down || vpntoggle.highlighted - color: vpntoggle.down ? "#17a81a" : "#eeeeee" - } - } // end switchdelegate - - Text { + LocationText { id: manualOverrideWarning - font.pixelSize: 10 - color: "grey" - text: qsTr("Location has been manually set.") - anchors.horizontalCenter: parent.horizontalCenter visible: isManualLocation() } } // end column @@ -200,7 +138,6 @@ ApplicationWindow { backend.useLocation(currentText.toString()) } - delegate: ItemDelegate { // TODO: we could use icons // https://doc.qt.io/qt-5/qml-qtquick-controls2-abstractbutton.html#icon-prop @@ -232,44 +169,10 @@ ApplicationWindow { } // end column } // end item - Item { - + BridgesItem { id: bridgesTab - anchors.centerIn: parent - width: parent.width - - Column { - - anchors.centerIn: parent - spacing: 10 - width: parent.width + } - CheckBox { - checked: false - text: qsTr("Use obfs4 bridges") - font.pixelSize: 14 - anchors.horizontalCenter: parent.horizontalCenter - } - Text { - id: bridgesInfo - width: 250 - color: "grey" - text: qsTr("Select a bridge only if you know that you need it to evade censorship in your country or local network.") - anchors.horizontalCenter: parent.horizontalCenter - wrapMode: Text.WordWrap - } - Text { - id: bridgeReconnect - width: 250 - font.pixelSize: 12 - color: "red" - text: qsTr("The change will take effect next time you connect to the VPN.") - anchors.horizontalCenter: parent.horizontalCenter - wrapMode: Text.WordWrap - visible: true - } - } // end column - } // end item } // end stacklayout Connections { @@ -374,36 +277,13 @@ ApplicationWindow { console.debug("DEBUG: Pre-seeded providers:") console.debug(providers.getJson()) allowEmptyPass = shouldAllowEmptyPass() + needsRestart = false; /* TODO get appVisible flag from backend */ app.visible = true app.raise() } - function toHuman(st) { - switch (st) { - case "off": - //: %1 -> application name - return qsTr("%1 off").arg(ctx.appName) - case "on": - //: %1 -> application name - return qsTr("%1 on").arg(ctx.appName) - case "connecting": - //: %1 -> application name - return qsTr("Connecting to %1").arg(ctx.appName) - case "stopping": - //: %1 -> application name - return qsTr("Stopping %1").arg(ctx.appName) - case "failed": - //: %1 -> application name - return qsTr("%1 blocking internet").arg( - ctx.appName) // TODO failed is not handed yet - } - } - - function locationStr() { - return ctx.currentLocation + ", " + ctx.currentCountry - } property var icons: { "off": "qrc:/assets/icon/png/white/vpn_off.png", @@ -557,10 +437,8 @@ ApplicationWindow { systray.icon.source = icons["off"] tooltip = qsTr("Checking status…") console.debug("systray init completed") - //hide() if (systrayVisible) { console.log("show systray") - //show() if (Qt.platform.os === "windows") { let appname = ctx ? ctx.appName : "VPN" showNotification( @@ -570,6 +448,7 @@ ApplicationWindow { } } + // TODO move to logic, pass ctx // Helper to show notification messages function showNotification(msg) { console.log("Going to show notification message: ", msg) @@ -604,7 +483,6 @@ ApplicationWindow { MessageDialog { id: errorStartingVPN - //buttons: MessageDialog.Ok modality: Qt.NonModal title: qsTr("Error starting VPN") text: "" @@ -614,7 +492,6 @@ ApplicationWindow { MessageDialog { id: authAgent - //buttons: MessageDialog.Ok modality: Qt.NonModal title: qsTr("Missing authentication agent") text: qsTr("Could not find a polkit authentication agent. Please run one and try again.") @@ -625,4 +502,11 @@ ApplicationWindow { id: initFailure visible: false } + + function locationStr() { + return ctx.currentLocation + ", " + ctx.currentCountry + } + + property alias brReconnect:bridgesTab.displayReconnect + } -- cgit v1.2.3